mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-30 20:52:28 +00:00
Resolve conflicts
This commit is contained in:
commit
4308ee1a71
85 changed files with 3200 additions and 936 deletions
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
|
@ -1,4 +1,4 @@
|
|||
on: [push]
|
||||
on: [ push ]
|
||||
name: Continuous Integration
|
||||
|
||||
# Inspired by osu! lazer's CI
|
||||
|
@ -22,11 +22,6 @@ jobs:
|
|||
DB_USER: root
|
||||
DB_PASSWORD: lighthouse
|
||||
steps:
|
||||
- name: Cancel previous runs of this workflow
|
||||
uses: styfle/cancel-workflow-action@0.6.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
|
@ -36,11 +31,11 @@ jobs:
|
|||
with:
|
||||
mysql-version: '8.0'
|
||||
root-password: ${{ env.DB_PASSWORD }}
|
||||
|
||||
|
||||
- name: Create Lighthouse Database
|
||||
if: ${{ matrix.os.database }}
|
||||
run: mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} -h 127.0.0.1 -e "CREATE DATABASE ${{ env.DB_DATABASE }};";
|
||||
|
||||
|
||||
- name: Install .NET 5.0
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
|
@ -52,10 +47,10 @@ jobs:
|
|||
with:
|
||||
dotnet-version: "6.0.x"
|
||||
include-prerelease: true
|
||||
|
||||
|
||||
- name: Compile
|
||||
run: dotnet build -c Debug
|
||||
|
||||
|
||||
- name: Test
|
||||
continue-on-error: true
|
||||
run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx"
|
||||
|
@ -84,7 +79,7 @@ jobs:
|
|||
create-status-check: false
|
||||
create-pr-comment: false
|
||||
update-comment-if-one-exists: false
|
||||
|
||||
|
||||
- name: Check Test Results
|
||||
if: steps.process-trx.outputs.test-outcome == 'Failed'
|
||||
run: |
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Development Database" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
||||
<deployment type="docker-compose.yml">
|
||||
<settings>
|
||||
<option name="envFilePath" value="" />
|
||||
<option name="sourceFilePath" value="docker-compose.yml" />
|
||||
</settings>
|
||||
</deployment>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration default="false" name="Development Database" type="docker-deploy" factoryName="docker-compose.yml"
|
||||
server-name="Docker">
|
||||
<deployment type="docker-compose.yml">
|
||||
<settings>
|
||||
<option name="envFilePath" value=""/>
|
||||
<option name="sourceFilePath" value="docker-compose.yml"/>
|
||||
</settings>
|
||||
</deployment>
|
||||
<method v="2"/>
|
||||
</configuration>
|
||||
</component>
|
|
@ -2,12 +2,19 @@ using LBPUnion.ProjectLighthouse.Types.Settings;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public sealed class DatabaseFact : FactAttribute {
|
||||
public DatabaseFact() {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public sealed class DatabaseFact : FactAttribute
|
||||
{
|
||||
public DatabaseFact()
|
||||
{
|
||||
ServerSettings.DbConnectionString = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||
if(!ServerSettings.DbConnected) this.Skip = "Database not available";
|
||||
else {
|
||||
if (!ServerSettings.DbConnected)
|
||||
{
|
||||
this.Skip = "Database not available";
|
||||
}
|
||||
else
|
||||
{
|
||||
using Database database = new();
|
||||
database.Database.Migrate();
|
||||
}
|
||||
|
|
|
@ -8,31 +8,33 @@ using LBPUnion.ProjectLighthouse.Types;
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
public class LighthouseTest {
|
||||
public readonly TestServer Server;
|
||||
public class LighthouseTest
|
||||
{
|
||||
public readonly HttpClient Client;
|
||||
public readonly TestServer Server;
|
||||
|
||||
public LighthouseTest()
|
||||
{
|
||||
this.Server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
|
||||
|
||||
public LighthouseTest() {
|
||||
this.Server = new TestServer(new WebHostBuilder()
|
||||
.UseStartup<Startup>());
|
||||
|
||||
this.Client = this.Server.CreateClient();
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> AuthenticateResponse(int number = 0) {
|
||||
const char nullChar = (char)0x00;
|
||||
const char sepChar = (char)0x20;
|
||||
public async Task<HttpResponseMessage> AuthenticateResponse(int number = 0)
|
||||
{
|
||||
const string username = "unitTestUser";
|
||||
|
||||
string stringContent = $"{nullChar}{sepChar}{username}{number}{nullChar}";
|
||||
|
||||
string stringContent = $"{LoginData.UsernamePrefix}{username}{number}{(char)0x00}";
|
||||
|
||||
HttpResponseMessage response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", new StringContent(stringContent));
|
||||
return response;
|
||||
}
|
||||
|
||||
public async Task<LoginResult> Authenticate(int number = 0) {
|
||||
|
||||
public async Task<LoginResult> Authenticate(int number = 0)
|
||||
{
|
||||
HttpResponseMessage response = await this.AuthenticateResponse(number);
|
||||
|
||||
string responseContent = LbpSerializer.StringElement("loginResult", await response.Content.ReadAsStringAsync());
|
||||
|
@ -43,30 +45,31 @@ namespace LBPUnion.ProjectLighthouse.Tests {
|
|||
|
||||
public Task<HttpResponseMessage> AuthenticatedRequest(string endpoint, string mmAuth) => this.AuthenticatedRequest(endpoint, mmAuth, HttpMethod.Get);
|
||||
|
||||
public Task<HttpResponseMessage> AuthenticatedRequest(string endpoint, string mmAuth, HttpMethod method) {
|
||||
using var requestMessage = new HttpRequestMessage(method, endpoint);
|
||||
public Task<HttpResponseMessage> AuthenticatedRequest(string endpoint, string mmAuth, HttpMethod method)
|
||||
{
|
||||
using HttpRequestMessage? requestMessage = new(method, endpoint);
|
||||
requestMessage.Headers.Add("Cookie", mmAuth);
|
||||
|
||||
return this.Client.SendAsync(requestMessage);
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> UploadFileRequest(string endpoint, string filePath) {
|
||||
return await this.Client.PostAsync(endpoint, new StringContent(await File.ReadAllTextAsync(filePath)));
|
||||
}
|
||||
public async Task<HttpResponseMessage> UploadFileRequest(string endpoint, string filePath)
|
||||
=> await this.Client.PostAsync(endpoint, new StringContent(await File.ReadAllTextAsync(filePath)));
|
||||
|
||||
public async Task<HttpResponseMessage> UploadDataRequest(string endpoint, byte[] data) {
|
||||
return await this.Client.PostAsync(endpoint, new ByteArrayContent(data));
|
||||
}
|
||||
public async Task<HttpResponseMessage> UploadDataRequest(string endpoint, byte[] data)
|
||||
=> await this.Client.PostAsync(endpoint, new ByteArrayContent(data));
|
||||
|
||||
public async Task<HttpResponseMessage> AuthenticatedUploadFileRequest(string endpoint, string filePath, string mmAuth) {
|
||||
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, endpoint);
|
||||
public async Task<HttpResponseMessage> AuthenticatedUploadFileRequest(string endpoint, string filePath, string mmAuth)
|
||||
{
|
||||
using HttpRequestMessage? requestMessage = new(HttpMethod.Post, endpoint);
|
||||
requestMessage.Headers.Add("Cookie", mmAuth);
|
||||
requestMessage.Content = new StringContent(await File.ReadAllTextAsync(filePath));
|
||||
return await this.Client.SendAsync(requestMessage);
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> AuthenticatedUploadDataRequest(string endpoint, byte[] data, string mmAuth) {
|
||||
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, endpoint);
|
||||
public async Task<HttpResponseMessage> AuthenticatedUploadDataRequest(string endpoint, byte[] data, string mmAuth)
|
||||
{
|
||||
using HttpRequestMessage? requestMessage = new(HttpMethod.Post, endpoint);
|
||||
requestMessage.Headers.Add("Cookie", mmAuth);
|
||||
requestMessage.Content = new ByteArrayContent(data);
|
||||
return await this.Client.SendAsync(requestMessage);
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.11" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.11"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
@ -27,7 +27,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj" />
|
||||
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
|
||||
<Content Include="ExampleFiles\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
@ -5,10 +5,13 @@ using LBPUnion.ProjectLighthouse.Types;
|
|||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public class AuthenticationTests : LighthouseTest {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public class AuthenticationTests : LighthouseTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ShouldReturnErrorOnNoPostData() {
|
||||
public async Task ShouldReturnErrorOnNoPostData()
|
||||
{
|
||||
HttpResponseMessage response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", null!);
|
||||
Assert.False(response.IsSuccessStatusCode);
|
||||
#if NET6_0_OR_GREATER
|
||||
|
@ -19,7 +22,8 @@ namespace LBPUnion.ProjectLighthouse.Tests {
|
|||
}
|
||||
|
||||
[DatabaseFact]
|
||||
public async Task ShouldReturnWithValidData() {
|
||||
public async Task ShouldReturnWithValidData()
|
||||
{
|
||||
HttpResponseMessage response = await this.AuthenticateResponse();
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
@ -28,9 +32,10 @@ namespace LBPUnion.ProjectLighthouse.Tests {
|
|||
}
|
||||
|
||||
[DatabaseFact]
|
||||
public async Task CanSerializeBack() {
|
||||
public async Task CanSerializeBack()
|
||||
{
|
||||
LoginResult loginResult = await this.Authenticate();
|
||||
|
||||
|
||||
Assert.NotNull(loginResult);
|
||||
Assert.NotNull(loginResult.AuthTicket);
|
||||
Assert.NotNull(loginResult.LbpEnvVer);
|
||||
|
@ -40,18 +45,20 @@ namespace LBPUnion.ProjectLighthouse.Tests {
|
|||
}
|
||||
|
||||
[DatabaseFact]
|
||||
public async Task CanUseToken() {
|
||||
public async Task CanUseToken()
|
||||
{
|
||||
LoginResult loginResult = await this.Authenticate();
|
||||
|
||||
HttpResponseMessage response = await this.AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/eula", loginResult.AuthTicket);
|
||||
string responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
Assert.Contains("You are logged in", responseContent);
|
||||
Assert.Contains("You are now logged in", responseContent);
|
||||
}
|
||||
|
||||
[DatabaseFact]
|
||||
public async Task ShouldReturnForbiddenWhenNotAuthenticated() {
|
||||
public async Task ShouldReturnForbiddenWhenNotAuthenticated()
|
||||
{
|
||||
HttpResponseMessage response = await this.Client.GetAsync("/LITTLEBIGPLANETPS3_XML/eula");
|
||||
Assert.False(response.IsSuccessStatusCode);
|
||||
Assert.True(response.StatusCode == HttpStatusCode.Forbidden);
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public class DatabaseTests : LighthouseTest {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public class DatabaseTests : LighthouseTest
|
||||
{
|
||||
[DatabaseFact]
|
||||
public async Task CanCreateUserTwice() {
|
||||
public async Task CanCreateUserTwice()
|
||||
{
|
||||
await using Database database = new();
|
||||
int rand = new Random().Next();
|
||||
|
||||
|
|
|
@ -4,47 +4,56 @@ using System.Text;
|
|||
using LBPUnion.ProjectLighthouse.Types.Files;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public class FileTypeTests {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public class FileTypeTests
|
||||
{
|
||||
[Fact]
|
||||
public void ShouldRecognizeLevel() {
|
||||
public void ShouldRecognizeLevel()
|
||||
{
|
||||
LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestLevel.lvl"));
|
||||
Assert.True(file.FileType == LbpFileType.Level);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldRecognizeScript() {
|
||||
public void ShouldRecognizeScript()
|
||||
{
|
||||
LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestScript.ff"));
|
||||
Assert.True(file.FileType == LbpFileType.Script);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldRecognizeTexture() {
|
||||
public void ShouldRecognizeTexture()
|
||||
{
|
||||
LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestTexture.tex"));
|
||||
Assert.True(file.FileType == LbpFileType.Texture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldRecognizeFileArchive() {
|
||||
public void ShouldRecognizeFileArchive()
|
||||
{
|
||||
LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestFarc.farc"));
|
||||
Assert.True(file.FileType == LbpFileType.FileArchive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldNotRecognizeFileArchiveAsScript() {
|
||||
public void ShouldNotRecognizeFileArchiveAsScript()
|
||||
{
|
||||
LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestFarc.farc"));
|
||||
Assert.False(file.FileType == LbpFileType.Script);
|
||||
Assert.True(file.FileType == LbpFileType.FileArchive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldRecognizeNothingAsUnknown() {
|
||||
public void ShouldRecognizeNothingAsUnknown()
|
||||
{
|
||||
LbpFile file = new(Array.Empty<byte>());
|
||||
Assert.True(file.FileType == LbpFileType.Unknown);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShouldRecognizeGarbageAsUnknown() {
|
||||
public void ShouldRecognizeGarbageAsUnknown()
|
||||
{
|
||||
LbpFile file = new(Encoding.ASCII.GetBytes("free pc only $900"));
|
||||
Assert.True(file.FileType == LbpFileType.Unknown);
|
||||
}
|
||||
|
|
|
@ -1,39 +1,59 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public class MatchTests : LighthouseTest {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public class MatchTests : LighthouseTest
|
||||
{
|
||||
private static readonly SemaphoreSlim semaphore = new(1, 1);
|
||||
|
||||
[DatabaseFact]
|
||||
public async Task ShouldReturnOk() {
|
||||
public async Task ShouldRejectEmptyData()
|
||||
{
|
||||
LoginResult loginResult = await this.Authenticate();
|
||||
await semaphore.WaitAsync();
|
||||
|
||||
HttpResponseMessage result = await this.AuthenticatedUploadDataRequest("LITTLEBIGPLANETPS3_XML/match", Array.Empty<byte>(), loginResult.AuthTicket);
|
||||
Assert.True(result.IsSuccessStatusCode);
|
||||
|
||||
semaphore.Release();
|
||||
Assert.False(result.IsSuccessStatusCode);
|
||||
}
|
||||
|
||||
[DatabaseFact]
|
||||
public async Task ShouldReturnOk()
|
||||
{
|
||||
LoginResult loginResult = await this.Authenticate();
|
||||
await semaphore.WaitAsync();
|
||||
|
||||
HttpResponseMessage result = await this.AuthenticatedUploadDataRequest
|
||||
("LITTLEBIGPLANETPS3_XML/match", Encoding.ASCII.GetBytes("[UpdateMyPlayerData,[\"Player\":\"1984\"]]"), loginResult.AuthTicket);
|
||||
|
||||
semaphore.Release();
|
||||
Assert.True(result.IsSuccessStatusCode);
|
||||
}
|
||||
public async Task<int> GetPlayerCount() => Convert.ToInt32(await this.Client.GetStringAsync("LITTLEBIGPLANETPS3_XML/totalPlayerCount"));
|
||||
|
||||
[DatabaseFact]
|
||||
public async Task ShouldIncrementPlayerCount() {
|
||||
public async Task ShouldIncrementPlayerCount()
|
||||
{
|
||||
LoginResult loginResult = await this.Authenticate(new Random().Next());
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
|
||||
int oldPlayerCount = await this.GetPlayerCount();
|
||||
|
||||
HttpResponseMessage result = await this.AuthenticatedUploadDataRequest("LITTLEBIGPLANETPS3_XML/match", Array.Empty<byte>(), loginResult.AuthTicket);
|
||||
HttpResponseMessage result = await this.AuthenticatedUploadDataRequest
|
||||
("LITTLEBIGPLANETPS3_XML/match", Encoding.ASCII.GetBytes("[UpdateMyPlayerData,[\"Player\":\"1984\"]]"), loginResult.AuthTicket);
|
||||
|
||||
Assert.True(result.IsSuccessStatusCode);
|
||||
|
||||
int playerCount = await this.GetPlayerCount();
|
||||
|
||||
|
||||
semaphore.Release();
|
||||
Assert.Equal(oldPlayerCount + 1, playerCount);
|
||||
}
|
||||
|
|
|
@ -2,30 +2,42 @@ using System.Collections.Generic;
|
|||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public class SerializerTests : LighthouseTest {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public class SerializerTests : LighthouseTest
|
||||
{
|
||||
[Fact]
|
||||
public void BlankElementWorks() {
|
||||
public void BlankElementWorks()
|
||||
{
|
||||
Assert.Equal("<test></test>", LbpSerializer.BlankElement("test"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StringElementWorks() {
|
||||
public void StringElementWorks()
|
||||
{
|
||||
Assert.Equal("<test>asd</test>", LbpSerializer.StringElement("test", "asd"));
|
||||
Assert.Equal("<test>asd</test>", LbpSerializer.StringElement(new KeyValuePair<string, object>("test", "asd")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaggedStringElementWorks() {
|
||||
public void TaggedStringElementWorks()
|
||||
{
|
||||
Assert.Equal("<test foo=\"bar\">asd</test>", LbpSerializer.TaggedStringElement("test", "asd", "foo", "bar"));
|
||||
Assert.Equal("<test foo=\"bar\">asd</test>", LbpSerializer.TaggedStringElement(new KeyValuePair<string, object>("test", "asd"),
|
||||
new KeyValuePair<string, object>("foo", "bar")));
|
||||
Assert.Equal
|
||||
(
|
||||
"<test foo=\"bar\">asd</test>",
|
||||
LbpSerializer.TaggedStringElement(new KeyValuePair<string, object>("test", "asd"), new KeyValuePair<string, object>("foo", "bar"))
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ElementsWorks() {
|
||||
Assert.Equal("<test>asd</test><foo>bar</foo>", LbpSerializer.Elements(new KeyValuePair<string, object>("test", "asd"),
|
||||
new KeyValuePair<string, object>("foo", "bar")));
|
||||
public void ElementsWorks()
|
||||
{
|
||||
Assert.Equal
|
||||
(
|
||||
"<test>asd</test><foo>bar</foo>",
|
||||
LbpSerializer.Elements(new KeyValuePair<string, object>("test", "asd"), new KeyValuePair<string, object>("foo", "bar"))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,10 +4,13 @@ using LBPUnion.ProjectLighthouse.Types.Levels;
|
|||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public class SlotTests : LighthouseTest {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public class SlotTests : LighthouseTest
|
||||
{
|
||||
[DatabaseFact]
|
||||
public async Task ShouldOnlyShowUsersLevels() {
|
||||
public async Task ShouldOnlyShowUsersLevels()
|
||||
{
|
||||
await using Database database = new();
|
||||
|
||||
User userA = await database.CreateUser("unitTestUser0");
|
||||
|
@ -17,7 +20,8 @@ namespace LBPUnion.ProjectLighthouse.Tests {
|
|||
database.Locations.Add(l);
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
Slot slotA = new() {
|
||||
Slot slotA = new()
|
||||
{
|
||||
Creator = userA,
|
||||
Name = "slotA",
|
||||
Location = l,
|
||||
|
@ -25,7 +29,8 @@ namespace LBPUnion.ProjectLighthouse.Tests {
|
|||
ResourceCollection = "",
|
||||
};
|
||||
|
||||
Slot slotB = new() {
|
||||
Slot slotB = new()
|
||||
{
|
||||
Creator = userB,
|
||||
Name = "slotB",
|
||||
Location = l,
|
||||
|
@ -47,7 +52,7 @@ namespace LBPUnion.ProjectLighthouse.Tests {
|
|||
Assert.NotEqual(respA, respB);
|
||||
Assert.DoesNotContain(respA, "slotB");
|
||||
Assert.DoesNotContain(respB, "slotA");
|
||||
|
||||
|
||||
// Cleanup
|
||||
|
||||
database.Slots.Remove(slotA);
|
||||
|
|
|
@ -4,39 +4,47 @@ using System.Net.Http;
|
|||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Tests {
|
||||
public class UploadTests : LighthouseTest {
|
||||
public UploadTests() {
|
||||
namespace LBPUnion.ProjectLighthouse.Tests
|
||||
{
|
||||
public class UploadTests : LighthouseTest
|
||||
{
|
||||
public UploadTests()
|
||||
{
|
||||
string assetsDirectory = Path.Combine(Environment.CurrentDirectory, "r");
|
||||
if(Directory.Exists(assetsDirectory)) Directory.Delete(assetsDirectory, true);
|
||||
if (Directory.Exists(assetsDirectory)) Directory.Delete(assetsDirectory, true);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ShouldNotAcceptScript() {
|
||||
public async Task ShouldNotAcceptScript()
|
||||
{
|
||||
HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/scriptTest", "ExampleFiles/TestScript.ff");
|
||||
Assert.False(response.IsSuccessStatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ShouldNotAcceptFarc() {
|
||||
public async Task ShouldNotAcceptFarc()
|
||||
{
|
||||
HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/farcTest", "ExampleFiles/TestFarc.farc");
|
||||
Assert.False(response.IsSuccessStatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ShouldNotAcceptGarbage() {
|
||||
public async Task ShouldNotAcceptGarbage()
|
||||
{
|
||||
HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/garbageTest", "ExampleFiles/TestGarbage.bin");
|
||||
Assert.False(response.IsSuccessStatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ShouldAcceptTexture() {
|
||||
public async Task ShouldAcceptTexture()
|
||||
{
|
||||
HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/textureTest", "ExampleFiles/TestTexture.tex");
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ShouldAcceptLevel() {
|
||||
public async Task ShouldAcceptLevel()
|
||||
{
|
||||
HttpResponseMessage response = await this.UploadFileRequest("/LITTLEBIGPLANETPS3_XML/upload/levelTest", "ExampleFiles/TestLevel.lvl");
|
||||
Assert.True(response.IsSuccessStatusCode);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,81 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeConstructorOrDestructorBody/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeLocalFunctionBody/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeMethodOrOperatorBody/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeNotEvident/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTrailingCommaInMultilineLists/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTrailingCommaInSinglelineLists/@EntryIndexedValue">SUGGESTION</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">ERROR</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/LOCAL_FUNCTION_BODY/@EntryValue">ExpressionBody</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/METHOD_OR_OPERATOR_BODY/@EntryValue">ExpressionBody</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_MEMBERS/@EntryValue">Field, Property, Event, Method</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/TRAILING_COMMA_IN_MULTILINE_LISTS/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/TRAILING_COMMA_IN_SINGLELINE_LISTS/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/CASE_BLOCK_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/EMPTY_BLOCK_STYLE/@EntryValue">TOGETHER</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_INSIDE_NAMESPACE/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_PREPROCESSOR_IF/@EntryValue">USUAL_INDENT</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_PREPROCESSOR_OTHER/@EntryValue">USUAL_INDENT</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INITIALIZER_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INVOCABLE_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_DECLARATION_PARENS_ARRANGEMENT/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_EMBEDDED_ARRANGEMENT/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_EXPR_MEMBER_ARRANGEMENT/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_INITIALIZER_ARRANGEMENT/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_PROPERTY_PATTERNS_ARRANGEMENT/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_SWITCH_EXPRESSION_ARRANGEMENT/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_USER_LINEBREAKS/@EntryValue">False</s:Boolean>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/MAX_FORMAL_PARAMETERS_ON_LINE/@EntryValue">5</s:Int64>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/MAX_INITIALIZER_ELEMENTS_ON_LINE/@EntryValue">1</s:Int64>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/NESTED_TERNARY_STYLE/@EntryValue">EXPANDED</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/OTHER_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_CASE_STATEMENT_ON_SAME_LINE/@EntryValue">IF_OWNER_IS_SINGLE_LINE</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_INITIALIZER_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_PROPERTY_PATTERN_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_ARROW_OP/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_FOREACH_PARENTHESES/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_IF_PARENTHESES/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_SWITCH_PARENTHESES/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_USING_PARENTHESES/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_WHILE_PARENTHESES/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/TYPE_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_AFTER_DECLARATION_LPAR/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_AFTER_INVOCATION_LPAR/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARRAY_INITIALIZER_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_FIRST_TYPE_PARAMETER_CONSTRAINT/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_LINQ_EXPRESSION/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_CHAINED_BINARY_EXPRESSIONS/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_CHAINED_METHOD_CALLS/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_EXTENDS_LIST_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_OBJECT_AND_COLLECTION_INITIALIZER_STYLE/@EntryValue">CHOP_ALWAYS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_PARAMETERS_STYLE/@EntryValue">CHOP_IF_LONG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_PROPERTY_PATTERN/@EntryValue">CHOP_ALWAYS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForBuiltInTypes/@EntryValue">UseExplicitType</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MM/@EntryIndexedValue">MM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Method/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /></s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Affero/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Braaains/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=brun/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=ezoiar/@EntryIndexedValue">True</s:Boolean>
|
||||
|
@ -11,6 +84,7 @@
|
|||
<s:Boolean x:Key="/Default/UserDictionary/Words/=lbpme/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=LBPU/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=lolcatftw/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=mmpick/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Swingy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=thumbsup/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=unfavourite/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
|
@ -13,24 +14,20 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||
public IActionResult NetworkSettings()
|
||||
{
|
||||
var hostname = this.Request.Host;
|
||||
return this.Ok(
|
||||
"ProbabilityOfPacketDelay 0.0\nMinPacketDelayFrames 0\nMaxPacketDelayFrames 3\nProbabilityOfPacketDrop 0.0\nEnableFakeConditionsForLoopback true\nNumberOfFramesPredictionAllowedForNonLocalPlayer 1000\nEnablePrediction true\nMinPredictedFrames 0\nMaxPredictedFrames 10\nAllowGameRendCameraSplit true\nFramesBeforeAgressiveCatchup 30\nPredictionPadSides 200\nPredictionPadTop 200\nPredictionPadBottom 200\nShowErrorNumbers true\nAllowModeratedLevels true\nAllowModeratedPoppetItems true\nShowLevelBoos true\nTIMEOUT_WAIT_FOR_JOIN_RESPONSE_FROM_PREV_PARTY_HOST 50.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_HOST 30.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_MEMBER 45.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN_FRIEND 15.0\nTIMEOUT_WAIT_FOR_CONNECTION_FROM_HOST 30.0\nTIMEOUT_WAIT_FOR_ROOM_ID_TO_JOIN 60.0\nTIMEOUT_WAIT_FOR_GET_NUM_PLAYERS_ONLINE 60.0\nTIMEOUT_WAIT_FOR_SIGNALLING_CONNECTIONS 120.0\nTIMEOUT_WAIT_FOR_PARTY_DATA 60.0\nTIME_TO_WAIT_FOR_LEAVE_MESSAGE_TO_COME_BACK 20.0\nTIME_TO_WAIT_FOR_FOLLOWING_REQUESTS_TO_ARRIVE 30.0\nTIMEOUT_WAIT_FOR_FINISHED_MIGRATING_HOST 30.0\nTIMEOUT_WAIT_FOR_PARTY_LEADER_FINISH_JOINING 45.0\nTIMEOUT_WAIT_FOR_QUICKPLAY_LEVEL 60.0\nTIMEOUT_WAIT_FOR_PLAYERS_TO_JOIN 30.0\nTIMEOUT_WAIT_FOR_DIVE_IN_PLAYERS 120.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 30.0\nTIMEOUT_DIVE_IN_TOTAL 1000000.0\nTIMEOUT_WAIT_FOR_SOCKET_CONNECTION 120.0\nTIMEOUT_WAIT_FOR_REQUEST_RESOURCE_MESSAGE 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_GET_RESOURCE_LIST 120.0\nTIMEOUT_WAIT_FOR_CLIENT_TO_LOAD_RESOURCES 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_SAVE_GAME_STATE 30.0\nTIMEOUT_WAIT_FOR_ADD_PLAYERS_TO_TAKE 30.0\nTIMEOUT_WAIT_FOR_UPDATE_FROM_CLIENT 90.0\nTIMEOUT_WAIT_FOR_HOST_TO_GET_RESOURCE_LIST 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_SAVE_GAME_STATE 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_ADD_US 30.0\nTIMEOUT_WAIT_FOR_UPDATE 60.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN 50.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_PRESENCE 60.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_CONNECTION 120.0\nSECONDS_BETWEEN_PINS_AWARDED_UPLOADS 300.0\nEnableKeepAlive true\nAllowVoIPRecordingPlayback true\nCDNHostName localhost\nTelemetryServer localhost\nOverheatingThresholdDisallowMidgameJoin 0.95\nMaxCatchupFrames 3\nMaxLagBeforeShowLoading 23\nMinLagBeforeHideLoading 30\nLagImprovementInflectionPoint -1.0\nFlickerThreshold 2.0\nClosedDemo2014Version 1\nClosedDemo2014Expired false\nEnablePlayedFilter true\nEnableCommunityDecorations true\nGameStateUpdateRate 10.0\nGameStateUpdateRateWithConsumers 1.0\nDisableDLCPublishCheck false\nEnableDiveIn true\nEnableHackChecks false\n"
|
||||
+ $"TelemetryServer {hostname}\nCDNHostName {hostname}");
|
||||
HostString hostname = this.Request.Host;
|
||||
return this.Ok
|
||||
(
|
||||
"ProbabilityOfPacketDelay 0.0\nMinPacketDelayFrames 0\nMaxPacketDelayFrames 3\nProbabilityOfPacketDrop 0.0\nEnableFakeConditionsForLoopback true\nNumberOfFramesPredictionAllowedForNonLocalPlayer 1000\nEnablePrediction true\nMinPredictedFrames 0\nMaxPredictedFrames 10\nAllowGameRendCameraSplit true\nFramesBeforeAgressiveCatchup 30\nPredictionPadSides 200\nPredictionPadTop 200\nPredictionPadBottom 200\nShowErrorNumbers true\nAllowModeratedLevels true\nAllowModeratedPoppetItems true\nShowLevelBoos true\nTIMEOUT_WAIT_FOR_JOIN_RESPONSE_FROM_PREV_PARTY_HOST 50.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_HOST 30.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_MEMBER 45.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN_FRIEND 15.0\nTIMEOUT_WAIT_FOR_CONNECTION_FROM_HOST 30.0\nTIMEOUT_WAIT_FOR_ROOM_ID_TO_JOIN 60.0\nTIMEOUT_WAIT_FOR_GET_NUM_PLAYERS_ONLINE 60.0\nTIMEOUT_WAIT_FOR_SIGNALLING_CONNECTIONS 120.0\nTIMEOUT_WAIT_FOR_PARTY_DATA 60.0\nTIME_TO_WAIT_FOR_LEAVE_MESSAGE_TO_COME_BACK 20.0\nTIME_TO_WAIT_FOR_FOLLOWING_REQUESTS_TO_ARRIVE 30.0\nTIMEOUT_WAIT_FOR_FINISHED_MIGRATING_HOST 30.0\nTIMEOUT_WAIT_FOR_PARTY_LEADER_FINISH_JOINING 45.0\nTIMEOUT_WAIT_FOR_QUICKPLAY_LEVEL 60.0\nTIMEOUT_WAIT_FOR_PLAYERS_TO_JOIN 30.0\nTIMEOUT_WAIT_FOR_DIVE_IN_PLAYERS 120.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 30.0\nTIMEOUT_DIVE_IN_TOTAL 1000000.0\nTIMEOUT_WAIT_FOR_SOCKET_CONNECTION 120.0\nTIMEOUT_WAIT_FOR_REQUEST_RESOURCE_MESSAGE 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_GET_RESOURCE_LIST 120.0\nTIMEOUT_WAIT_FOR_CLIENT_TO_LOAD_RESOURCES 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_SAVE_GAME_STATE 30.0\nTIMEOUT_WAIT_FOR_ADD_PLAYERS_TO_TAKE 30.0\nTIMEOUT_WAIT_FOR_UPDATE_FROM_CLIENT 90.0\nTIMEOUT_WAIT_FOR_HOST_TO_GET_RESOURCE_LIST 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_SAVE_GAME_STATE 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_ADD_US 30.0\nTIMEOUT_WAIT_FOR_UPDATE 60.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN 50.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_PRESENCE 60.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_CONNECTION 120.0\nSECONDS_BETWEEN_PINS_AWARDED_UPLOADS 300.0\nEnableKeepAlive true\nAllowVoIPRecordingPlayback true\nCDNHostName localhost\nTelemetryServer localhost\nOverheatingThresholdDisallowMidgameJoin 0.95\nMaxCatchupFrames 3\nMaxLagBeforeShowLoading 23\nMinLagBeforeHideLoading 30\nLagImprovementInflectionPoint -1.0\nFlickerThreshold 2.0\nClosedDemo2014Version 1\nClosedDemo2014Expired false\nEnablePlayedFilter true\nEnableCommunityDecorations true\nGameStateUpdateRate 10.0\nGameStateUpdateRateWithConsumers 1.0\nDisableDLCPublishCheck false\nEnableDiveIn true\nEnableHackChecks false\n" +
|
||||
$"TelemetryServer {hostname}\nCDNHostName {hostname}"
|
||||
);
|
||||
}
|
||||
|
||||
[HttpGet("t_conf")]
|
||||
[Produces("text/json")]
|
||||
public IActionResult Conf()
|
||||
{
|
||||
return this.Ok("[{\"StatusCode\":200}]");
|
||||
}
|
||||
public IActionResult Conf() => this.Ok("[{\"StatusCode\":200}]");
|
||||
|
||||
[HttpGet("farc_hashes")]
|
||||
public IActionResult FarcHashes()
|
||||
{
|
||||
return this.Ok();
|
||||
}
|
||||
public IActionResult FarcHashes() => this.Ok();
|
||||
|
||||
[HttpGet("privacySettings")]
|
||||
[Produces("text/xml")]
|
||||
|
|
|
@ -3,28 +3,34 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class CommentController : ControllerBase {
|
||||
public class CommentController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public CommentController(Database database) {
|
||||
public CommentController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpGet("userComments/{username}")]
|
||||
public async Task<IActionResult> GetComments(string username) {
|
||||
List<Comment> comments = await this.database.Comments
|
||||
.Include(c => c.Target)
|
||||
public async Task<IActionResult> GetComments(string username)
|
||||
{
|
||||
List<Comment> comments = await this.database.Comments.Include
|
||||
(c => c.Target)
|
||||
.Include(c => c.Poster)
|
||||
.Where(c => c.Target.Username == username)
|
||||
.OrderByDescending(c => c.Timestamp)
|
||||
.ToListAsync();
|
||||
|
||||
string outputXml = comments.Aggregate(string.Empty, (current, comment) => current + comment.Serialize());
|
||||
|
@ -32,7 +38,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
}
|
||||
|
||||
[HttpPost("postUserComment/{username}")]
|
||||
public async Task<IActionResult> PostComment(string username) {
|
||||
public async Task<IActionResult> PostComment(string username)
|
||||
{
|
||||
this.Request.Body.Position = 0;
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
|
@ -41,18 +48,36 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
|
||||
User poster = await this.database.UserFromRequest(this.Request);
|
||||
|
||||
if(poster == null) return this.StatusCode(403, "");
|
||||
|
||||
if (poster == null) return this.StatusCode(403, "");
|
||||
|
||||
User target = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||
|
||||
if(comment == null || target == null) return this.BadRequest();
|
||||
|
||||
if (comment == null || target == null) return this.BadRequest();
|
||||
|
||||
comment.PosterUserId = poster.UserId;
|
||||
comment.TargetUserId = target.UserId;
|
||||
|
||||
comment.Timestamp = TimeHelper.UnixTimeMilliseconds();
|
||||
|
||||
this.database.Comments.Add(comment);
|
||||
await this.database.SaveChangesAsync();
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
[HttpPost("deleteUserComment/{username}")]
|
||||
public async Task<IActionResult> DeleteComment([FromQuery] int commentId, string username)
|
||||
{
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
Comment comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
|
||||
|
||||
if (comment.TargetUserId != user.UserId && comment.PosterUserId != user.UserId) return this.StatusCode(403, "");
|
||||
|
||||
this.database.Comments.Remove(comment);
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
return this.Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
|
@ -8,9 +7,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
public class DeveloperController : Controller
|
||||
{
|
||||
[HttpGet("/developer_videos")]
|
||||
public IActionResult DeveloperVideos()
|
||||
{
|
||||
return this.Ok();
|
||||
}
|
||||
public IActionResult DeveloperVideos() => this.Ok();
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/enterLevel")]
|
||||
// [Produces("text/plain")]
|
||||
public class EnterLevelController : ControllerBase {
|
||||
public class EnterLevelController : ControllerBase
|
||||
{
|
||||
[HttpGet("enterLevel/{id}")]
|
||||
public IActionResult EnterLevel(string id) {
|
||||
return this.Ok();
|
||||
}
|
||||
public IActionResult EnterLevel(string id) => this.Ok();
|
||||
}
|
||||
}
|
|
@ -2,17 +2,21 @@ using System;
|
|||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/tags")]
|
||||
[Produces("text/plain")]
|
||||
public class LevelTagsController : ControllerBase {
|
||||
public class LevelTagsController : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public IActionResult Get() {
|
||||
public IActionResult Get()
|
||||
{
|
||||
string[] tags = Enum.GetNames(typeof(LevelTags));
|
||||
|
||||
int i = 0;
|
||||
foreach(string tag in tags) {
|
||||
foreach (string tag in tags)
|
||||
{
|
||||
tags[i] = $"TAG_{tag.Replace("_", "-")}";
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -8,23 +8,28 @@ using LBPUnion.ProjectLighthouse.Types.Levels;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class ListController : ControllerBase {
|
||||
public class ListController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public ListController(Database database) {
|
||||
public ListController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
#region Levels
|
||||
|
||||
#region Level Queue (lolcatftw)
|
||||
|
||||
[HttpGet("slots/lolcatftw/{username}")]
|
||||
public IActionResult GetLevelQueue(string username) {
|
||||
IEnumerable<QueuedLevel> queuedLevels = new Database().QueuedLevels
|
||||
.Include(q => q.User)
|
||||
public IActionResult GetLevelQueue(string username)
|
||||
{
|
||||
IEnumerable<QueuedLevel> queuedLevels = new Database().QueuedLevels.Include
|
||||
(q => q.User)
|
||||
.Include(q => q.Slot)
|
||||
.Include(q => q.Slot.Location)
|
||||
.Where(q => q.User.Username == username)
|
||||
|
@ -36,30 +41,36 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
}
|
||||
|
||||
[HttpPost("lolcatftw/add/user/{id:int}")]
|
||||
public async Task<IActionResult> AddQueuedLevel(int id) {
|
||||
public async Task<IActionResult> AddQueuedLevel(int id)
|
||||
{
|
||||
User? user = await this.database.UserFromRequest(this.Request);
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
QueuedLevel queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id);
|
||||
if(queuedLevel != null) return this.Ok();
|
||||
if (queuedLevel != null) return this.Ok();
|
||||
|
||||
this.database.QueuedLevels.Add(new QueuedLevel {
|
||||
SlotId = id,
|
||||
UserId = user.UserId,
|
||||
});
|
||||
this.database.QueuedLevels.Add
|
||||
(
|
||||
new QueuedLevel
|
||||
{
|
||||
SlotId = id,
|
||||
UserId = user.UserId,
|
||||
}
|
||||
);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("lolcatftw/remove/user/{id:int}")]
|
||||
public async Task<IActionResult> RemoveQueuedLevel(int id) {
|
||||
public async Task<IActionResult> RemoveQueuedLevel(int id)
|
||||
{
|
||||
User? user = await this.database.UserFromRequest(this.Request);
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
QueuedLevel queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id);
|
||||
if(queuedLevel != null) this.database.QueuedLevels.Remove(queuedLevel);
|
||||
if (queuedLevel != null) this.database.QueuedLevels.Remove(queuedLevel);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
|
@ -71,9 +82,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
#region Hearted Levels
|
||||
|
||||
[HttpGet("favouriteSlots/{username}")]
|
||||
public IActionResult GetFavouriteSlots(string username) {
|
||||
IEnumerable<HeartedLevel> heartedLevels = new Database().HeartedLevels
|
||||
.Include(q => q.User)
|
||||
public IActionResult GetFavouriteSlots(string username)
|
||||
{
|
||||
IEnumerable<HeartedLevel> heartedLevels = new Database().HeartedLevels.Include
|
||||
(q => q.User)
|
||||
.Include(q => q.Slot)
|
||||
.Include(q => q.Slot.Location)
|
||||
.Include(q => q.Slot.Creator)
|
||||
|
@ -86,17 +98,22 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
}
|
||||
|
||||
[HttpPost("favourite/slot/user/{id:int}")]
|
||||
public async Task<IActionResult> AddFavouriteSlot(int id) {
|
||||
public async Task<IActionResult> AddFavouriteSlot(int id)
|
||||
{
|
||||
User? user = await this.database.UserFromRequest(this.Request);
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
HeartedLevel heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id);
|
||||
if(heartedLevel != null) return this.Ok();
|
||||
if (heartedLevel != null) return this.Ok();
|
||||
|
||||
this.database.HeartedLevels.Add(new HeartedLevel {
|
||||
SlotId = id,
|
||||
UserId = user.UserId,
|
||||
});
|
||||
this.database.HeartedLevels.Add
|
||||
(
|
||||
new HeartedLevel
|
||||
{
|
||||
SlotId = id,
|
||||
UserId = user.UserId,
|
||||
}
|
||||
);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
|
@ -104,12 +121,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
}
|
||||
|
||||
[HttpPost("unfavourite/slot/user/{id:int}")]
|
||||
public async Task<IActionResult> RemoveFavouriteSlot(int id) {
|
||||
public async Task<IActionResult> RemoveFavouriteSlot(int id)
|
||||
{
|
||||
User? user = await this.database.UserFromRequest(this.Request);
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
HeartedLevel heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id);
|
||||
if(heartedLevel != null) this.database.HeartedLevels.Remove(heartedLevel);
|
||||
if (heartedLevel != null) this.database.HeartedLevels.Remove(heartedLevel);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
|
@ -117,16 +135,16 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion Levels
|
||||
|
||||
#region Users
|
||||
|
||||
|
||||
|
||||
[HttpGet("favouriteUsers/{username}")]
|
||||
public IActionResult GetFavouriteUsers(string username) {
|
||||
IEnumerable<HeartedProfile> heartedProfiles = new Database().HeartedProfiles
|
||||
.Include(q => q.User)
|
||||
public IActionResult GetFavouriteUsers(string username)
|
||||
{
|
||||
IEnumerable<HeartedProfile> heartedProfiles = new Database().HeartedProfiles.Include
|
||||
(q => q.User)
|
||||
.Include(q => q.HeartedUser)
|
||||
.Include(q => q.HeartedUser.Location)
|
||||
.Where(q => q.User.Username == username)
|
||||
|
@ -136,42 +154,46 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
|
||||
return this.Ok(LbpSerializer.TaggedStringElement("favouriteUsers", response, "total", 1));
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("favourite/user/{username}")]
|
||||
public async Task<IActionResult> AddFavouriteUser(string username) {
|
||||
public async Task<IActionResult> AddFavouriteUser(string username)
|
||||
{
|
||||
User? user = await this.database.UserFromRequest(this.Request);
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
User? heartedUser = await this.database.Users
|
||||
.FirstOrDefaultAsync(u => u.Username == username);
|
||||
if(heartedUser == null) return this.NotFound();
|
||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||
if (heartedUser == null) return this.NotFound();
|
||||
|
||||
HeartedProfile heartedProfile = await this.database.HeartedProfiles
|
||||
.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
||||
if(heartedProfile != null) return this.Ok();
|
||||
HeartedProfile heartedProfile = await this.database.HeartedProfiles.FirstOrDefaultAsync
|
||||
(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
||||
if (heartedProfile != null) return this.Ok();
|
||||
|
||||
this.database.HeartedProfiles.Add(new HeartedProfile {
|
||||
HeartedUserId = heartedUser.UserId,
|
||||
UserId = user.UserId,
|
||||
});
|
||||
this.database.HeartedProfiles.Add
|
||||
(
|
||||
new HeartedProfile
|
||||
{
|
||||
HeartedUserId = heartedUser.UserId,
|
||||
UserId = user.UserId,
|
||||
}
|
||||
);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("unfavourite/user/{username}")]
|
||||
public async Task<IActionResult> RemoveFavouriteUser(string username) {
|
||||
public async Task<IActionResult> RemoveFavouriteUser(string username)
|
||||
{
|
||||
User? user = await this.database.UserFromRequest(this.Request);
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
User? heartedUser = await this.database.Users
|
||||
.FirstOrDefaultAsync(u => u.Username == username);
|
||||
if(heartedUser == null) return this.NotFound();
|
||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||
if (heartedUser == null) return this.NotFound();
|
||||
|
||||
HeartedProfile heartedProfile = await this.database.HeartedProfiles
|
||||
.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
||||
if(heartedProfile != null) this.database.HeartedProfiles.Remove(heartedProfile);
|
||||
HeartedProfile heartedProfile = await this.database.HeartedProfiles.FirstOrDefaultAsync
|
||||
(q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId);
|
||||
if (heartedProfile != null) this.database.HeartedProfiles.Remove(heartedProfile);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
|
@ -179,5 +201,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
|
@ -24,25 +24,30 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
{
|
||||
string body = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
LoginData loginData;
|
||||
LoginData? loginData;
|
||||
try
|
||||
{
|
||||
loginData = LoginData.CreateFromString(body);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return this.BadRequest();
|
||||
loginData = null;
|
||||
}
|
||||
|
||||
if (loginData == null) return this.BadRequest();
|
||||
|
||||
Token? token = await this.database.AuthenticateUser(loginData);
|
||||
|
||||
if (token == null) return this.StatusCode(403, "");
|
||||
|
||||
return this.Ok(new LoginResult
|
||||
{
|
||||
AuthTicket = "MM_AUTH=" + token.UserToken,
|
||||
LbpEnvVer = ServerSettings.ServerName,
|
||||
}.Serialize());
|
||||
return this.Ok
|
||||
(
|
||||
new LoginResult
|
||||
{
|
||||
AuthTicket = "MM_AUTH=" + token.UserToken,
|
||||
LbpEnvVer = ServerSettings.ServerName,
|
||||
}.Serialize()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,10 +40,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
if (bodyString.Contains("FindBestRoom"))
|
||||
{
|
||||
return this.Ok(
|
||||
"[{\"StatusCode\":200},{\"Players\":[{\"PlayerId\":\"literally1984\",\"matching_res\":0},{\"PlayerId\":\"jvyden\",\"matching_res\":1}],\"Slots\":[[5,0]],\"RoomState\":\"E_ROOM_IN_POD\",\"HostMood\":\"E_MOOD_EVERYONE\",\"LevelCompletionEstimate\":0,\"PassedNoJoinPoint\":0,\"MoveConnected\":false,\"Location\":[\"127.0.0.1\"],\"BuildVersion\":289,\"Language\":1,\"FirstSeenTimestamp\":1427331263756,\"LastSeenTimestamp\":1635112546000,\"GameId\":1,\"NatType\":2,\"Friends\":[],\"Blocked\":[],\"RecentlyLeft\":[],\"FailedJoin\":[]}]");
|
||||
}
|
||||
return this.Ok
|
||||
(
|
||||
"[{\"StatusCode\":200},{\"Players\":[{\"PlayerId\":\"literally1984\",\"matching_res\":0},{\"PlayerId\":\"jvyden\",\"matching_res\":1}],\"Slots\":[[5,0]],\"RoomState\":\"E_ROOM_IN_POD\",\"HostMood\":\"E_MOOD_EVERYONE\",\"LevelCompletionEstimate\":0,\"PassedNoJoinPoint\":0,\"MoveConnected\":false,\"Location\":[\"127.0.0.1\"],\"BuildVersion\":289,\"Language\":1,\"FirstSeenTimestamp\":1427331263756,\"LastSeenTimestamp\":1635112546000,\"GameId\":1,\"NatType\":2,\"Friends\":[],\"Blocked\":[],\"RecentlyLeft\":[],\"FailedJoin\":[]}]"
|
||||
);
|
||||
|
||||
if (bodyString[0] != '[') return this.BadRequest();
|
||||
|
||||
|
@ -52,7 +52,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
{
|
||||
matchData = MatchHelper.Deserialize(bodyString);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch(Exception e)
|
||||
{
|
||||
Logger.Log("Exception while parsing MatchData: " + e);
|
||||
Logger.Log("Data: " + bodyString);
|
||||
|
@ -66,8 +66,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
|
||||
#region Update LastMatch
|
||||
|
||||
LastMatch? lastMatch = await this.database.LastMatches
|
||||
.Where(l => l.UserId == user.UserId).FirstOrDefaultAsync();
|
||||
LastMatch? lastMatch = await this.database.LastMatches.Where(l => l.UserId == user.UserId).FirstOrDefaultAsync();
|
||||
|
||||
// below makes it not look like trash
|
||||
// ReSharper disable once ConvertIfStatementToNullCoalescingExpression
|
||||
|
@ -88,16 +87,5 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
|
||||
return this.Ok("[{\"StatusCode\":200}]");
|
||||
}
|
||||
|
||||
[HttpGet("playersInPodCount")]
|
||||
[HttpGet("totalPlayerCount")]
|
||||
public async Task<IActionResult> TotalPlayerCount()
|
||||
{
|
||||
int recentMatches = await this.database.LastMatches
|
||||
.Where(l => TimestampHelper.Timestamp - l.Timestamp < 60)
|
||||
.CountAsync();
|
||||
|
||||
return this.Ok(recentMatches.ToString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -22,34 +25,36 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
{
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
return user == null
|
||||
? this.Forbid()
|
||||
: this.Ok($"You are now logged in as user {user.Username} (id {user.UserId}).\n" +
|
||||
"This is a private testing instance. Please do not make anything public for now, and keep in mind security isn't as tight as a full release would.");
|
||||
? this.StatusCode(403, "")
|
||||
: this.Ok
|
||||
(
|
||||
$"You are now logged in as user {user.Username} (id {user.UserId}).\n" +
|
||||
// ReSharper disable once UnreachableCode
|
||||
(EulaHelper.ShowPrivateInstanceNotice ? "\n" + EulaHelper.PrivateInstanceNotice : "") +
|
||||
"\n" +
|
||||
$"{EulaHelper.License}\n"
|
||||
);
|
||||
}
|
||||
|
||||
[HttpGet("announce")]
|
||||
public async Task<IActionResult> Announce()
|
||||
{
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
return user == null
|
||||
? this.Forbid()
|
||||
: this.Ok($"You are now logged in as user {user.Username} (id {user.UserId}).\n" +
|
||||
"This is a private testing instance. Please do not make anything public for now, and keep in mind security isn't as tight as a full release would.");
|
||||
}
|
||||
public IActionResult Announce() => this.Ok("");
|
||||
|
||||
[HttpGet("notification")]
|
||||
public IActionResult Notification()
|
||||
{
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
public IActionResult Notification() => this.Ok();
|
||||
/// <summary>
|
||||
/// Filters chat messages sent by a user.
|
||||
/// Filters chat messages sent by a user.
|
||||
/// The reponse sent is the text that will appear in-game.
|
||||
/// </summary>
|
||||
[HttpPost("filter")]
|
||||
public async Task<IActionResult> Filter()
|
||||
{
|
||||
return this.Ok(await new StreamReader(this.Request.Body).ReadToEndAsync());
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
string loggedText = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
Logger.Log($"{user.Username}: {loggedText}", LoggerLevelFilter.Instance);
|
||||
return this.Ok(loggedText);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.News;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -13,20 +12,24 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
[HttpGet]
|
||||
public IActionResult Get()
|
||||
{
|
||||
string newsEntry = LbpSerializer.StringElement("item", new NewsEntry
|
||||
{
|
||||
Category = "no_category",
|
||||
Summary = "test summary",
|
||||
Image = new NewsImage
|
||||
string newsEntry = LbpSerializer.StringElement
|
||||
(
|
||||
"item",
|
||||
new NewsEntry
|
||||
{
|
||||
Hash = "4947269c5f7061b27225611ee58a9a91a8031bbe",
|
||||
Alignment = "right",
|
||||
},
|
||||
Id = 1,
|
||||
Title = "Test Title",
|
||||
Text = "Test Text",
|
||||
Date = 1348755214000,
|
||||
}.Serialize());
|
||||
Category = "no_category",
|
||||
Summary = "test summary",
|
||||
Image = new NewsImage
|
||||
{
|
||||
Hash = "4947269c5f7061b27225611ee58a9a91a8031bbe",
|
||||
Alignment = "right",
|
||||
},
|
||||
Id = 1,
|
||||
Title = "Test Title",
|
||||
Text = "Test Text",
|
||||
Date = 1348755214000,
|
||||
}.Serialize()
|
||||
);
|
||||
|
||||
return this.Ok(LbpSerializer.StringElement("news", newsEntry));
|
||||
}
|
||||
|
|
|
@ -10,64 +10,102 @@ using LBPUnion.ProjectLighthouse.Types.Profiles;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class PublishController : ControllerBase {
|
||||
public class PublishController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
|
||||
public PublishController(Database database) {
|
||||
|
||||
public PublishController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint the game uses to verify that the level is compatible (?)
|
||||
/// Endpoint the game uses to check what resources need to be uploaded and if the level can be uploaded
|
||||
/// </summary>
|
||||
[HttpPost("startPublish")]
|
||||
public async Task<IActionResult> StartPublish() {
|
||||
Slot slot = await this.GetSlotFromBody();
|
||||
if(slot == null) return this.BadRequest(); // if the level cant be parsed then it obviously cant be uploaded
|
||||
public async Task<IActionResult> StartPublish()
|
||||
{
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
string resources = slot.Resources
|
||||
.Where(hash => !FileHelper.ResourceExists(hash))
|
||||
.Aggregate("", (current, hash) =>
|
||||
current + LbpSerializer.StringElement("resource", hash));
|
||||
Slot slot = await this.GetSlotFromBody();
|
||||
if (slot == null) return this.BadRequest(); // if the level cant be parsed then it obviously cant be uploaded
|
||||
|
||||
// Republish logic
|
||||
if (slot.SlotId != 0)
|
||||
{
|
||||
Slot oldSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
|
||||
if (oldSlot == null) return this.NotFound();
|
||||
if (oldSlot.CreatorId != user.UserId) return this.BadRequest();
|
||||
}
|
||||
|
||||
string resources = slot.Resources.Where
|
||||
(hash => !FileHelper.ResourceExists(hash))
|
||||
.Aggregate("", (current, hash) => current + LbpSerializer.StringElement("resource", hash));
|
||||
|
||||
return this.Ok(LbpSerializer.TaggedStringElement("slot", resources, "type", "user"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint actually used to publish a level
|
||||
/// Endpoint actually used to publish a level
|
||||
/// </summary>
|
||||
[HttpPost("publish")]
|
||||
public async Task<IActionResult> Publish() {
|
||||
public async Task<IActionResult> Publish()
|
||||
{
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
Slot slot = await this.GetSlotFromBody();
|
||||
|
||||
// Republish logic
|
||||
if (slot.SlotId != 0)
|
||||
{
|
||||
Slot oldSlot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
|
||||
if (oldSlot == null) return this.NotFound();
|
||||
if (oldSlot.CreatorId != user.UserId) return this.BadRequest();
|
||||
|
||||
oldSlot.Location.X = slot.Location.X;
|
||||
oldSlot.Location.Y = slot.Location.Y;
|
||||
|
||||
slot.CreatorId = oldSlot.CreatorId;
|
||||
slot.LocationId = oldSlot.LocationId;
|
||||
slot.SlotId = oldSlot.SlotId;
|
||||
slot.FirstUploaded = oldSlot.FirstUploaded;
|
||||
slot.LastUpdated = TimeHelper.UnixTimeMilliseconds();
|
||||
|
||||
this.database.Entry(oldSlot).CurrentValues.SetValues(slot);
|
||||
await this.database.SaveChangesAsync();
|
||||
return this.Ok(oldSlot.Serialize());
|
||||
}
|
||||
|
||||
//TODO: parse location in body
|
||||
Location l = new() {
|
||||
X = 0,
|
||||
Y = 0,
|
||||
Location l = new()
|
||||
{
|
||||
X = slot.Location.X,
|
||||
Y = slot.Location.Y,
|
||||
};
|
||||
this.database.Locations.Add(l);
|
||||
await this.database.SaveChangesAsync();
|
||||
slot.LocationId = l.Id;
|
||||
slot.CreatorId = user.UserId;
|
||||
slot.FirstUploaded = TimeHelper.UnixTimeMilliseconds();
|
||||
slot.LastUpdated = TimeHelper.UnixTimeMilliseconds();
|
||||
|
||||
this.database.Slots.Add(slot);
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
|
||||
return this.Ok(slot.Serialize());
|
||||
}
|
||||
|
||||
[HttpPost("unpublish/{id:int}")]
|
||||
public async Task<IActionResult> Unpublish(int id) {
|
||||
Slot slot = await this.database.Slots
|
||||
.Include(s => s.Location)
|
||||
.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||
public async Task<IActionResult> Unpublish(int id)
|
||||
{
|
||||
Slot slot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == id);
|
||||
|
||||
this.database.Locations.Remove(slot.Location);
|
||||
this.database.Slots.Remove(slot);
|
||||
|
@ -76,8 +114,9 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
public async Task<Slot> GetSlotFromBody() {
|
||||
|
||||
public async Task<Slot> GetSlotFromBody()
|
||||
{
|
||||
this.Request.Body.Position = 0;
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
|
|
|
@ -18,10 +18,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
public class ResourcesController : ControllerBase
|
||||
{
|
||||
[HttpPost("showModerated")]
|
||||
public IActionResult ShowModerated()
|
||||
{
|
||||
return this.Ok(LbpSerializer.BlankElement("resources"));
|
||||
}
|
||||
public IActionResult ShowModerated() => this.Ok(LbpSerializer.BlankElement("resources"));
|
||||
|
||||
[HttpPost("filterResources")]
|
||||
[HttpPost("showNotUploaded")]
|
||||
|
@ -30,14 +27,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
XmlSerializer serializer = new(typeof(ResourceList));
|
||||
ResourceList resourceList = (ResourceList) serializer.Deserialize(new StringReader(bodyString));
|
||||
ResourceList resourceList = (ResourceList)serializer.Deserialize(new StringReader(bodyString));
|
||||
|
||||
if (resourceList == null) return this.BadRequest();
|
||||
|
||||
string resources = resourceList.Resources
|
||||
.Where(s => !FileHelper.ResourceExists(s))
|
||||
.Aggregate("", (current, hash) =>
|
||||
current + LbpSerializer.StringElement("resource", hash));
|
||||
string resources = resourceList.Resources.Where
|
||||
(s => !FileHelper.ResourceExists(s))
|
||||
.Aggregate("", (current, hash) => current + LbpSerializer.StringElement("resource", hash));
|
||||
|
||||
return this.Ok(LbpSerializer.StringElement("resources", resources));
|
||||
}
|
||||
|
@ -47,10 +43,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
{
|
||||
string path = FileHelper.GetResourcePath(hash);
|
||||
|
||||
if (FileHelper.ResourceExists(hash))
|
||||
{
|
||||
return this.File(IOFile.OpenRead(path), "application/octet-stream");
|
||||
}
|
||||
if (FileHelper.ResourceExists(hash)) return this.File(IOFile.OpenRead(path), "application/octet-stream");
|
||||
|
||||
return this.NotFound();
|
||||
}
|
||||
|
@ -68,7 +61,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
if (FileHelper.ResourceExists(hash)) this.Ok(); // no reason to fail if it's already uploaded
|
||||
|
||||
Logger.Log($"Processing resource upload (hash: {hash})");
|
||||
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(Request.BodyReader));
|
||||
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader));
|
||||
|
||||
if (!FileHelper.IsFileSafe(file)) return this.UnprocessableEntity();
|
||||
|
||||
|
|
|
@ -6,18 +6,24 @@ using LBPUnion.ProjectLighthouse.Types.Levels;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class SearchController : ControllerBase {
|
||||
public class SearchController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public SearchController(Database database) {
|
||||
public SearchController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpGet("slots/search")]
|
||||
public async Task<IActionResult> SearchSlots([FromQuery] string query) {
|
||||
public async Task<IActionResult> SearchSlots([FromQuery] string query)
|
||||
{
|
||||
if (query == null) return this.BadRequest();
|
||||
|
||||
query = query.ToLower();
|
||||
|
||||
string[] keywords = query.Split(" ");
|
||||
|
@ -26,16 +32,16 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
.Include(s => s.Creator)
|
||||
.Include(s => s.Location)
|
||||
.Where(s => s.SlotId >= 0); // dumb query to conv into IQueryable
|
||||
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach(string keyword in keywords) {
|
||||
dbQuery = dbQuery.Where(s =>
|
||||
s.Name.ToLower().Contains(keyword) ||
|
||||
s.Description.ToLower().Contains(keyword) ||
|
||||
s.Creator.Username.ToLower().Contains(keyword) ||
|
||||
s.SlotId.ToString().Equals(keyword)
|
||||
foreach (string keyword in keywords)
|
||||
dbQuery = dbQuery.Where
|
||||
(
|
||||
s => s.Name.ToLower().Contains(keyword) ||
|
||||
s.Description.ToLower().Contains(keyword) ||
|
||||
s.Creator.Username.ToLower().Contains(keyword) ||
|
||||
s.SlotId.ToString().Equals(keyword)
|
||||
);
|
||||
}
|
||||
|
||||
List<Slot> slots = await dbQuery.ToListAsync();
|
||||
string response = slots.Aggregate("", (current, slot) => current + slot.Serialize());
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
@ -5,35 +6,54 @@ using LBPUnion.ProjectLighthouse.Types.Levels;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class SlotsController : ControllerBase {
|
||||
public class SlotsController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public SlotsController(Database database) {
|
||||
public SlotsController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpGet("slots/by")]
|
||||
public IActionResult SlotsBy([FromQuery] string u) {
|
||||
string response = Enumerable.Aggregate(
|
||||
this.database.Slots
|
||||
.Include(s => s.Creator)
|
||||
.Include(s => s.Location)
|
||||
.Where(s => s.Creator.Username == u)
|
||||
, string.Empty, (current, slot) => current + slot.Serialize());
|
||||
public IActionResult SlotsBy([FromQuery] string u)
|
||||
{
|
||||
string response = Enumerable.Aggregate
|
||||
(
|
||||
this.database.Slots.Include(s => s.Creator).Include(s => s.Location).Where(s => s.Creator.Username == u),
|
||||
string.Empty,
|
||||
(current, slot) => current + slot.Serialize()
|
||||
);
|
||||
|
||||
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", 1));
|
||||
}
|
||||
|
||||
public async Task<IActionResult> SUser(int id) {
|
||||
Slot slot = await this.database.Slots
|
||||
.Include(s => s.Creator)
|
||||
.Include(s => s.Location)
|
||||
.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||
|
||||
[HttpGet("s/user/{id:int}")]
|
||||
public async Task<IActionResult> SUser(int id)
|
||||
{
|
||||
Slot slot = await this.database.Slots.Include(s => s.Creator).Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == id);
|
||||
|
||||
if (slot == null) return this.NotFound();
|
||||
|
||||
return this.Ok(slot.Serialize());
|
||||
}
|
||||
|
||||
[HttpGet("slots")]
|
||||
public IActionResult NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||
{
|
||||
IQueryable<Slot> slots = this.database.Slots.Include
|
||||
(s => s.Creator)
|
||||
.Include(s => s.Location)
|
||||
.OrderByDescending(s => s.FirstUploaded)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(Math.Min(pageSize, 30));
|
||||
string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize());
|
||||
|
||||
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "hint_start", pageStart + Math.Min(pageSize, 30)));
|
||||
}
|
||||
}
|
||||
}
|
43
ProjectLighthouse/Controllers/StatisticsController.cs
Normal file
43
ProjectLighthouse/Controllers/StatisticsController.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/plain")]
|
||||
public class StatisticsController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public StatisticsController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpGet("playersInPodCount")]
|
||||
[HttpGet("totalPlayerCount")]
|
||||
public async Task<IActionResult> TotalPlayerCount()
|
||||
{
|
||||
int recentMatches = await this.database.LastMatches.Where(l => TimestampHelper.Timestamp - l.Timestamp < 60).CountAsync();
|
||||
|
||||
return this.Ok(recentMatches.ToString());
|
||||
}
|
||||
|
||||
[HttpGet("planetStats")]
|
||||
public async Task<IActionResult> PlanetStats()
|
||||
{
|
||||
int totalSlotCount = await this.database.Slots.CountAsync();
|
||||
const int mmPicksCount = 0;
|
||||
|
||||
return this.Ok
|
||||
(
|
||||
LbpSerializer.StringElement
|
||||
("planetStats", LbpSerializer.StringElement("totalSlotCount", totalSlotCount) + LbpSerializer.StringElement("mmPicksCount", mmPicksCount))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
|
@ -9,9 +8,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
public class StoreController : Controller
|
||||
{
|
||||
[HttpGet("promotions")]
|
||||
public IActionResult Promotions()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
public IActionResult Promotions() => this.Ok();
|
||||
}
|
||||
}
|
|
@ -25,25 +25,18 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
[HttpGet("user/{username}")]
|
||||
public async Task<IActionResult> GetUser(string username)
|
||||
{
|
||||
User user = await this.database.Users
|
||||
.Include(u => u.Location)
|
||||
.FirstOrDefaultAsync(u => u.Username == username);
|
||||
User user = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.Username == username);
|
||||
|
||||
if (user == null) return this.NotFound();
|
||||
|
||||
return this.Ok(user.Serialize());
|
||||
}
|
||||
|
||||
[HttpGet("user/{username}/playlists")]
|
||||
public IActionResult GetUserPlaylists(string username)
|
||||
{
|
||||
return this.Ok();
|
||||
}
|
||||
[HttpGet("users")]
|
||||
public async Task<IActionResult> GetUserAlt([FromQuery] string u) => await this.GetUser(u);
|
||||
|
||||
// [HttpPost("user/{username}")]
|
||||
// public async Task<IActionResult> CreateUser(string username) {
|
||||
// await new Database().CreateUser(username);
|
||||
// return await GetUser(username);
|
||||
// }
|
||||
[HttpGet("user/{username}/playlists")]
|
||||
public IActionResult GetUserPlaylists(string username) => this.Ok();
|
||||
|
||||
[HttpPost("updateUser")]
|
||||
public async Task<IActionResult> UpdateUser()
|
||||
|
@ -77,11 +70,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
// if you find a way to make it not stupid feel free to replace this
|
||||
using (XmlReader reader = XmlReader.Create(this.Request.Body, settings))
|
||||
{
|
||||
List<string>
|
||||
path = new(); // you can think of this as a file path in the XML, like <updateUser> -> <location> -> <x>
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
List<string> path = new(); // you can think of this as a file path in the XML, like <updateUser> -> <location> -> <x>
|
||||
while (await reader.ReadAsync()) // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Element:
|
||||
|
@ -97,21 +87,12 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
}
|
||||
case "location":
|
||||
{
|
||||
locationChanged =
|
||||
true; // if we're here then we're probably about to change the location.
|
||||
locationChanged = true; // if we're here then we're probably about to change the location.
|
||||
// ReSharper disable once ConvertIfStatementToSwitchStatement
|
||||
if (path[2] == "x")
|
||||
{
|
||||
user.Location.X =
|
||||
Convert.ToInt32(
|
||||
await reader
|
||||
.GetValueAsync()); // GetValue only returns a string, i guess we just hope its a number lol
|
||||
}
|
||||
else if (path[2] == "y")
|
||||
{
|
||||
user.Location.Y = Convert.ToInt32(await reader.GetValueAsync());
|
||||
}
|
||||
|
||||
user.Location.X = Convert.ToInt32
|
||||
(await reader.GetValueAsync()); // GetValue only returns a string, i guess we just hope its a number lol
|
||||
else if (path[2] == "y") user.Location.Y = Convert.ToInt32(await reader.GetValueAsync());
|
||||
break;
|
||||
}
|
||||
case "icon":
|
||||
|
@ -131,14 +112,12 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
path.RemoveAt(path.Count - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the way location on a user card works is stupid and will not save with the way below as-is, so we do the following:
|
||||
if (locationChanged) // only modify the database if we modify here
|
||||
{
|
||||
Location l = await this.database.Locations.Where(l => l.Id == user.LocationId)
|
||||
.FirstOrDefaultAsync(); // find the location in the database again
|
||||
Location l = await this.database.Locations.Where(l => l.Id == user.LocationId).FirstOrDefaultAsync(); // find the location in the database again
|
||||
|
||||
// set the location in the database to the one we modified above
|
||||
l.X = user.Location.X;
|
||||
|
@ -147,8 +126,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
|||
// now both are in sync, and will update in the database.
|
||||
}
|
||||
|
||||
if (this.database.ChangeTracker.HasChanges())
|
||||
await this.database.SaveChangesAsync(); // save the user to the database if we changed anything
|
||||
if (this.database.ChangeTracker.HasChanges()) await this.database.SaveChangesAsync(); // save the user to the database if we changed anything
|
||||
return this.Ok();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,16 +23,13 @@ namespace LBPUnion.ProjectLighthouse
|
|||
|
||||
public DbSet<LastMatch> LastMatches { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(
|
||||
ServerSettings.DbConnectionString,
|
||||
MySqlServerVersion.LatestSupportedServerVersion
|
||||
);
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||
=> options.UseMySql(ServerSettings.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion);
|
||||
|
||||
public async Task<User> CreateUser(string username)
|
||||
{
|
||||
User user;
|
||||
if ((user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync()) != null)
|
||||
return user;
|
||||
if ((user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync()) != null) return user;
|
||||
|
||||
Location l = new(); // store to get id after submitting
|
||||
this.Locations.Add(l); // add to table
|
||||
|
@ -51,12 +48,11 @@ namespace LBPUnion.ProjectLighthouse
|
|||
return user;
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
public async Task<Token?> AuthenticateUser(LoginData loginData)
|
||||
{
|
||||
// TODO: don't use psn name to authenticate
|
||||
User user = await this.Users.FirstOrDefaultAsync(u => u.Username == loginData.Username)
|
||||
?? await this.CreateUser(loginData.Username);
|
||||
User user = await this.Users.FirstOrDefaultAsync(u => u.Username == loginData.Username) ?? await this.CreateUser(loginData.Username);
|
||||
|
||||
Token token = new()
|
||||
{
|
||||
|
@ -74,20 +70,16 @@ namespace LBPUnion.ProjectLighthouse
|
|||
{
|
||||
Token? token = await this.Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken);
|
||||
if (token == null) return null;
|
||||
return await this.Users
|
||||
.Include(u => u.Location)
|
||||
.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
||||
|
||||
return await this.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
||||
}
|
||||
|
||||
public async Task<User?> UserFromRequest(HttpRequest request)
|
||||
{
|
||||
if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null;
|
||||
|
||||
return await this.UserFromAuthToken(mmAuth);
|
||||
}
|
||||
#nullable disable
|
||||
#nullable disable
|
||||
}
|
||||
}
|
|
@ -2,17 +2,20 @@ using System;
|
|||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers {
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers
|
||||
{
|
||||
// Yoinked from https://stackoverflow.com/a/68530667
|
||||
// Thanks to T-moty!
|
||||
/// <summary>
|
||||
/// Allows synchronous stream operations for this request.
|
||||
/// Allows synchronous stream operations for this request.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class AllowSynchronousIoAttribute : ActionFilterAttribute {
|
||||
public override void OnResultExecuting(ResultExecutingContext context) {
|
||||
public class AllowSynchronousIoAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnResultExecuting(ResultExecutingContext context)
|
||||
{
|
||||
IHttpBodyControlFeature syncIoFeature = context.HttpContext.Features.Get<IHttpBodyControlFeature>();
|
||||
if(syncIoFeature != null) syncIoFeature.AllowSynchronousIO = true;
|
||||
if (syncIoFeature != null) syncIoFeature.AllowSynchronousIO = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,52 +6,57 @@ using System.IO.Pipelines;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers {
|
||||
public static class BinaryHelper {
|
||||
public static string ReadString(BinaryReader reader) {
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers
|
||||
{
|
||||
public static class BinaryHelper
|
||||
{
|
||||
public static string ReadString(BinaryReader reader)
|
||||
{
|
||||
List<byte> readBytes = new();
|
||||
|
||||
byte readByte;
|
||||
do {
|
||||
readBytes.Add(readByte = reader.ReadByte());
|
||||
} while(readByte != 0x00);
|
||||
do readBytes.Add(readByte = reader.ReadByte());
|
||||
while (readByte != 0x00);
|
||||
|
||||
return Encoding.UTF8.GetString(readBytes.ToArray());
|
||||
}
|
||||
|
||||
public static void ReadUntilByte(BinaryReader reader, byte byteToReadTo) {
|
||||
public static void ReadUntilByte(BinaryReader reader, byte byteToReadTo)
|
||||
{
|
||||
byte readByte;
|
||||
do {
|
||||
readByte = reader.ReadByte();
|
||||
} while(readByte != byteToReadTo);
|
||||
do readByte = reader.ReadByte();
|
||||
while (readByte != byteToReadTo);
|
||||
}
|
||||
|
||||
public static byte[] ReadLastBytes(BinaryReader reader, int count, bool restoreOldPosition = true) {
|
||||
public static byte[] ReadLastBytes(BinaryReader reader, int count, bool restoreOldPosition = true)
|
||||
{
|
||||
long oldPosition = reader.BaseStream.Position;
|
||||
|
||||
if(reader.BaseStream.Length < count) return Array.Empty<byte>();
|
||||
|
||||
if (reader.BaseStream.Length < count) return Array.Empty<byte>();
|
||||
|
||||
reader.BaseStream.Position = reader.BaseStream.Length - count;
|
||||
byte[] data = reader.ReadBytes(count);
|
||||
|
||||
if(restoreOldPosition) reader.BaseStream.Position = oldPosition;
|
||||
|
||||
if (restoreOldPosition) reader.BaseStream.Position = oldPosition;
|
||||
return data;
|
||||
}
|
||||
|
||||
// Written with reference from
|
||||
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/request-response?view=aspnetcore-5.0
|
||||
// Surprisingly doesn't take seconds. (67ms for a 100kb file)
|
||||
public static async Task<byte[]> ReadFromPipeReader(PipeReader reader) {
|
||||
public static async Task<byte[]> ReadFromPipeReader(PipeReader reader)
|
||||
{
|
||||
List<byte> data = new();
|
||||
while(true) {
|
||||
while (true)
|
||||
{
|
||||
ReadResult readResult = await reader.ReadAsync();
|
||||
ReadOnlySequence<byte> buffer = readResult.Buffer;
|
||||
|
||||
if(readResult.IsCompleted && buffer.Length > 0) data.AddRange(buffer.ToArray());
|
||||
|
||||
if (readResult.IsCompleted && buffer.Length > 0) data.AddRange(buffer.ToArray());
|
||||
|
||||
reader.AdvanceTo(buffer.Start, buffer.End);
|
||||
|
||||
if(readResult.IsCompleted) break;
|
||||
|
||||
if (readResult.IsCompleted) break;
|
||||
}
|
||||
|
||||
return data.ToArray();
|
||||
|
|
24
ProjectLighthouse/Helpers/EulaHelper.cs
Normal file
24
ProjectLighthouse/Helpers/EulaHelper.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Helpers
|
||||
{
|
||||
public static class EulaHelper
|
||||
{
|
||||
public const string License = @"
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
||||
|
||||
public const string PrivateInstanceNotice = @"This server is a private testing instance.
|
||||
Please do not make anything public for now, and keep in mind security isn't as tight as a full release would.";
|
||||
|
||||
public const bool ShowPrivateInstanceNotice = false;
|
||||
}
|
||||
}
|
|
@ -3,17 +3,23 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions {
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions
|
||||
{
|
||||
// https://stackoverflow.com/a/8039737
|
||||
public static class ExceptionExtensions {
|
||||
public static string ToDetailedException(this Exception exception) {
|
||||
public static class ExceptionExtensions
|
||||
{
|
||||
public static string ToDetailedException(this Exception exception)
|
||||
{
|
||||
PropertyInfo[] properties = exception.GetType().GetProperties();
|
||||
|
||||
IEnumerable<string> fields = properties
|
||||
.Select(property => new {
|
||||
property.Name,
|
||||
Value = property.GetValue(exception, null),
|
||||
})
|
||||
|
||||
IEnumerable<string> fields = properties.Select
|
||||
(
|
||||
property => new
|
||||
{
|
||||
property.Name,
|
||||
Value = property.GetValue(exception, null),
|
||||
}
|
||||
)
|
||||
.Select(x => $"{x.Name} = {(x.Value != null ? x.Value.ToString() : string.Empty)}");
|
||||
|
||||
return string.Join("\n", fields);
|
||||
|
|
|
@ -4,17 +4,22 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using LBPUnion.ProjectLighthouse.Types.Files;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers {
|
||||
public static class FileHelper {
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers
|
||||
{
|
||||
public static class FileHelper
|
||||
{
|
||||
public static readonly string ResourcePath = Path.Combine(Environment.CurrentDirectory, "r");
|
||||
|
||||
public static string GetResourcePath(string hash) => Path.Combine(ResourcePath, hash);
|
||||
|
||||
public static bool IsFileSafe(LbpFile file) {
|
||||
if(file.FileType == LbpFileType.Unknown) file.FileType = DetermineFileType(file.Data);
|
||||
|
||||
return file.FileType switch {
|
||||
|
||||
public static bool IsFileSafe(LbpFile file)
|
||||
{
|
||||
if (file.FileType == LbpFileType.Unknown) file.FileType = DetermineFileType(file.Data);
|
||||
|
||||
return file.FileType switch
|
||||
{
|
||||
LbpFileType.FileArchive => false,
|
||||
LbpFileType.Painting => true,
|
||||
LbpFileType.Unknown => false,
|
||||
LbpFileType.Texture => true,
|
||||
LbpFileType.Script => false,
|
||||
|
@ -29,16 +34,19 @@ namespace LBPUnion.ProjectLighthouse.Helpers {
|
|||
};
|
||||
}
|
||||
|
||||
public static LbpFileType DetermineFileType(byte[] data) {
|
||||
public static LbpFileType DetermineFileType(byte[] data)
|
||||
{
|
||||
using MemoryStream ms = new(data);
|
||||
using BinaryReader reader = new(ms);
|
||||
|
||||
string footer = Encoding.ASCII.GetString(BinaryHelper.ReadLastBytes(reader, 4));
|
||||
if(footer == "FARC") return LbpFileType.FileArchive;
|
||||
if (footer == "FARC") return LbpFileType.FileArchive;
|
||||
|
||||
byte[] header = reader.ReadBytes(3);
|
||||
|
||||
return Encoding.ASCII.GetString(header) switch {
|
||||
return Encoding.ASCII.GetString(header) switch
|
||||
{
|
||||
"PTG" => LbpFileType.Painting,
|
||||
"TEX" => LbpFileType.Texture,
|
||||
"FSH" => LbpFileType.Script,
|
||||
"VOP" => LbpFileType.Voice,
|
||||
|
@ -50,8 +58,9 @@ namespace LBPUnion.ProjectLighthouse.Helpers {
|
|||
|
||||
public static bool ResourceExists(string hash) => File.Exists(GetResourcePath(hash));
|
||||
|
||||
public static void EnsureDirectoryCreated(string path) {
|
||||
if(!Directory.Exists(path)) Directory.CreateDirectory(path ?? throw new ArgumentNullException(nameof(path)));
|
||||
public static void EnsureDirectoryCreated(string path)
|
||||
{
|
||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path ?? throw new ArgumentNullException(nameof(path)));
|
||||
}
|
||||
|
||||
public static string[] ResourcesNotUploaded(params string[] hashes) => hashes.Where(hash => !ResourceExists(hash)).ToArray();
|
||||
|
|
|
@ -6,32 +6,22 @@ using System.Security.Cryptography;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers {
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers
|
||||
{
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
public static class HashHelper {
|
||||
public static class HashHelper
|
||||
{
|
||||
// private static readonly SHA1 sha1 = SHA1.Create();
|
||||
private static readonly SHA256 sha256 = SHA256.Create();
|
||||
private static readonly Random random = new();
|
||||
|
||||
#region Hash Functions
|
||||
public static string Sha256Hash(string str) => Sha256Hash(Encoding.UTF8.GetBytes(str));
|
||||
|
||||
public static string Sha256Hash(byte[] bytes) {
|
||||
byte[] hash = sha256.ComputeHash(bytes);
|
||||
return Encoding.UTF8.GetString(hash, 0, hash.Length);
|
||||
}
|
||||
|
||||
public static string BCryptHash(string str) => BCrypt.Net.BCrypt.HashPassword(str);
|
||||
|
||||
public static string BCryptHash(byte[] bytes) => BCrypt.Net.BCrypt.HashPassword(Encoding.UTF8.GetString(bytes));
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Generates a specified amount of random bytes in an array.
|
||||
/// Generates a specified amount of random bytes in an array.
|
||||
/// </summary>
|
||||
/// <param name="count">The amount of bytes to generate.</param>
|
||||
/// <returns>The bytes generated</returns>
|
||||
public static IEnumerable<byte> GenerateRandomBytes(int count) {
|
||||
public static IEnumerable<byte> GenerateRandomBytes(int count)
|
||||
{
|
||||
byte[] b = new byte[count];
|
||||
random.NextBytes(b);
|
||||
|
||||
|
@ -39,34 +29,31 @@ namespace LBPUnion.ProjectLighthouse.Helpers {
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random SHA256 & BCrypted token
|
||||
/// Generates a random SHA256 & BCrypted token
|
||||
/// </summary>
|
||||
/// <returns>The token as a string.</returns>
|
||||
public static string GenerateAuthToken() {
|
||||
byte[] bytes = (byte[]) GenerateRandomBytes(256);
|
||||
public static string GenerateAuthToken()
|
||||
{
|
||||
byte[] bytes = (byte[])GenerateRandomBytes(256);
|
||||
|
||||
return BCryptHash(Sha256Hash(bytes));
|
||||
}
|
||||
|
||||
public static async Task<string> ComputeDigest(string path, string authCookie, Stream body,
|
||||
string digestKey)
|
||||
|
||||
public static async Task<string> ComputeDigest(string path, string authCookie, Stream body, string digestKey)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
MemoryStream memoryStream = new();
|
||||
|
||||
byte[] pathBytes = Encoding.UTF8.GetBytes(path);
|
||||
byte[] cookieBytes = string.IsNullOrEmpty(authCookie)
|
||||
? Array.Empty<byte>()
|
||||
: Encoding.UTF8.GetBytes(authCookie);
|
||||
byte[] cookieBytes = string.IsNullOrEmpty(authCookie) ? Array.Empty<byte>() : Encoding.UTF8.GetBytes(authCookie);
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes(digestKey);
|
||||
|
||||
|
||||
await body.CopyToAsync(memoryStream);
|
||||
|
||||
byte[] bodyBytes = memoryStream.ToArray();
|
||||
|
||||
using IncrementalHash sha1 = IncrementalHash.CreateHash(HashAlgorithmName.SHA1);
|
||||
sha1.AppendData(bodyBytes);
|
||||
if (cookieBytes.Length > 0)
|
||||
sha1.AppendData(cookieBytes);
|
||||
if (cookieBytes.Length > 0) sha1.AppendData(cookieBytes);
|
||||
sha1.AppendData(pathBytes);
|
||||
sha1.AppendData(keyBytes);
|
||||
|
||||
|
@ -75,5 +62,22 @@ namespace LBPUnion.ProjectLighthouse.Helpers {
|
|||
|
||||
return digestString;
|
||||
}
|
||||
|
||||
#region Hash Functions
|
||||
|
||||
public static string Sha256Hash(string str) => Sha256Hash(Encoding.UTF8.GetBytes(str));
|
||||
|
||||
public static string Sha256Hash(byte[] bytes)
|
||||
{
|
||||
byte[] hash = sha256.ComputeHash(bytes);
|
||||
return Encoding.UTF8.GetString(hash, 0, hash.Length);
|
||||
}
|
||||
|
||||
public static string BCryptHash(string str) => BCrypt.Net.BCrypt.HashPassword(str);
|
||||
|
||||
public static string BCryptHash(byte[] bytes) => BCrypt.Net.BCrypt.HashPassword(Encoding.UTF8.GetString(bytes));
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
13
ProjectLighthouse/Helpers/TimeHelper.cs
Normal file
13
ProjectLighthouse/Helpers/TimeHelper.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers
|
||||
{
|
||||
public static class TimeHelper
|
||||
{
|
||||
public static long UnixTimeMilliseconds() => DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||
public static long UnixTimeSeconds() => DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||
}
|
||||
}
|
||||
|
||||
// 1397109686193
|
||||
// 1635389749454
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers {
|
||||
public static class TimestampHelper {
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers
|
||||
{
|
||||
public static class TimestampHelper
|
||||
{
|
||||
public static long Timestamp => (long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
}
|
||||
}
|
|
@ -3,32 +3,23 @@ using Kettu;
|
|||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Logging {
|
||||
public class AspNetToKettuLogger : ILogger {
|
||||
namespace LBPUnion.ProjectLighthouse.Logging
|
||||
{
|
||||
public class AspNetToKettuLogger : ILogger
|
||||
{
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state) {
|
||||
return NullScope.Instance;
|
||||
}
|
||||
public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
|
||||
public bool IsEnabled(LogLevel logLevel) => true;
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) {
|
||||
LoggerLevel loggerLevel = logLevel switch {
|
||||
|
||||
LogLevel.Trace => LoggerLevelAspNetTrace.Instance,
|
||||
LogLevel.Debug => LoggerLevelAspNetDebug.Instance,
|
||||
LogLevel.Information => LoggerLevelAspNetInformation.Instance,
|
||||
LogLevel.Warning => LoggerLevelAspNetWarning.Instance,
|
||||
LogLevel.Error => LoggerLevelAspNetError.Instance,
|
||||
LogLevel.Critical => LoggerLevelAspNetCritical.Instance,
|
||||
LogLevel.None => LoggerLevelAspNetNone.Instance,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null),
|
||||
};
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
LoggerLevel loggerLevel = new LoggerLevelAspNet(logLevel);
|
||||
|
||||
Logger.Log(state.ToString(), loggerLevel);
|
||||
if(exception == null) return;
|
||||
if (exception == null) return;
|
||||
|
||||
string[] lines = exception.ToDetailedException().Replace("\r", "").Split("\n");
|
||||
foreach(string line in lines) Logger.Log(line, loggerLevel);
|
||||
foreach (string line in lines) Logger.Log(line, loggerLevel);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Logging {
|
||||
namespace LBPUnion.ProjectLighthouse.Logging
|
||||
{
|
||||
[ProviderAlias("Kettu")]
|
||||
public class AspNetToKettuLoggerProvider : ILoggerProvider, IDisposable {
|
||||
public void Dispose() {
|
||||
public class AspNetToKettuLoggerProvider : ILoggerProvider, IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName) {
|
||||
return new AspNetToKettuLogger();
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName) => new AspNetToKettuLogger();
|
||||
}
|
||||
}
|
|
@ -3,16 +3,23 @@ using System.IO;
|
|||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Logging {
|
||||
public class LighthouseFileLogger : LoggerBase {
|
||||
namespace LBPUnion.ProjectLighthouse.Logging
|
||||
{
|
||||
public class LighthouseFileLogger : LoggerBase
|
||||
{
|
||||
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
|
||||
|
||||
|
||||
public override void Send(LoggerLine line)
|
||||
{
|
||||
FileHelper.EnsureDirectoryCreated(logsDirectory);
|
||||
|
||||
File.AppendAllText(Path.Combine(logsDirectory, line.LoggerLevel + ".log"), line.LineData + "\n");
|
||||
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), line.LineData + "\n");
|
||||
|
||||
string channel = string.IsNullOrEmpty(line.LoggerLevel.Channel) ? "" : $"[{line.LoggerLevel.Channel}] ";
|
||||
|
||||
string contentFile = $"{channel}{line.LineData}\n";
|
||||
string contentAll = $"[{$"{line.LoggerLevel.Name} {channel}".TrimEnd()}] {line.LineData}\n";
|
||||
|
||||
File.AppendAllText(Path.Combine(logsDirectory, line.LoggerLevel.Name + ".log"), contentFile);
|
||||
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,55 +1,39 @@
|
|||
using Kettu;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Logging {
|
||||
public class LoggerLevelStartup : LoggerLevel {
|
||||
public override string Name => "Startup";
|
||||
namespace LBPUnion.ProjectLighthouse.Logging
|
||||
{
|
||||
public class LoggerLevelStartup : LoggerLevel
|
||||
{
|
||||
public static readonly LoggerLevelStartup Instance = new();
|
||||
public override string Name => "Startup";
|
||||
}
|
||||
|
||||
public class LoggerLevelDatabase : LoggerLevel {
|
||||
public override string Name => "Database";
|
||||
public class LoggerLevelDatabase : LoggerLevel
|
||||
{
|
||||
public static readonly LoggerLevelDatabase Instance = new();
|
||||
public override string Name => "Database";
|
||||
}
|
||||
|
||||
public class LoggerLevelHttp : LoggerLevel {
|
||||
public override string Name => "HTTP";
|
||||
public class LoggerLevelHttp : LoggerLevel
|
||||
{
|
||||
public static readonly LoggerLevelHttp Instance = new();
|
||||
public override string Name => "HTTP";
|
||||
}
|
||||
|
||||
#region ASP.NET
|
||||
public class LoggerLevelAspNetTrace : LoggerLevel {
|
||||
public override string Name => "ASP.NET: Trace";
|
||||
public static readonly LoggerLevelAspNetTrace Instance = new();
|
||||
public class LoggerLevelFilter : LoggerLevel
|
||||
{
|
||||
public static readonly LoggerLevelFilter Instance = new();
|
||||
public override string Name => "Filter";
|
||||
}
|
||||
|
||||
public class LoggerLevelAspNetDebug : LoggerLevel {
|
||||
public override string Name => "ASP.NET: Debug";
|
||||
public static readonly LoggerLevelAspNetDebug Instance = new();
|
||||
|
||||
public class LoggerLevelAspNet : LoggerLevel
|
||||
{
|
||||
|
||||
public LoggerLevelAspNet(LogLevel level)
|
||||
{
|
||||
this.Channel = level.ToString();
|
||||
}
|
||||
public override string Name => "AspNet";
|
||||
}
|
||||
|
||||
public class LoggerLevelAspNetInformation : LoggerLevel {
|
||||
public override string Name => "ASP.NET: Information";
|
||||
public static readonly LoggerLevelAspNetInformation Instance = new();
|
||||
}
|
||||
|
||||
public class LoggerLevelAspNetWarning : LoggerLevel {
|
||||
public override string Name => "ASP.NET: Warning";
|
||||
public static readonly LoggerLevelAspNetWarning Instance = new();
|
||||
}
|
||||
|
||||
public class LoggerLevelAspNetError : LoggerLevel {
|
||||
public override string Name => "ASP.NET: Error";
|
||||
public static readonly LoggerLevelAspNetError Instance = new();
|
||||
}
|
||||
|
||||
public class LoggerLevelAspNetCritical : LoggerLevel {
|
||||
public override string Name => "ASP.NET: Critical";
|
||||
public static readonly LoggerLevelAspNetCritical Instance = new();
|
||||
}
|
||||
|
||||
public class LoggerLevelAspNetNone : LoggerLevel {
|
||||
public override string Name => "ASP.NET: None";
|
||||
public static readonly LoggerLevelAspNetNone Instance = new();
|
||||
}
|
||||
#endregion
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Logging {
|
||||
public class NullScope : IDisposable{
|
||||
namespace LBPUnion.ProjectLighthouse.Logging
|
||||
{
|
||||
public class NullScope : IDisposable
|
||||
{
|
||||
|
||||
private NullScope()
|
||||
{}
|
||||
public static NullScope Instance { get; } = new();
|
||||
|
||||
private NullScope() {}
|
||||
|
||||
public void Dispose() {
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
|
421
ProjectLighthouse/Migrations/20211028015915_AddSlotTimestamp.Designer.cs
generated
Normal file
421
ProjectLighthouse/Migrations/20211028015915_AddSlotTimestamp.Designer.cs
generated
Normal file
|
@ -0,0 +1,421 @@
|
|||
// <auto-generated />
|
||||
using LBPUnion.ProjectLighthouse;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
[DbContext(typeof(Database))]
|
||||
[Migration("20211028015915_AddSlotTimestamp")]
|
||||
partial class AddSlotTimestamp
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64)
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.Property<int>("HeartedProfileId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartedUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedProfileId");
|
||||
|
||||
b.HasIndex("HeartedUserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedProfiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.Property<int>("HeartedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.Property<int>("QueuedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("QueuedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("QueuedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.Property<int>("SlotId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("AuthorLabels")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BackgroundHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CreatorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("InitiallyLocked")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<bool>("Lbp1Only")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MaximumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MinimumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("MoveRequired")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ResourceCollection")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("RootLevel")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Shareable")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("SubLevel")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("SlotId");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Slots");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.Property<int>("CommentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("PosterUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("TargetUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsDown")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsUp")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("CommentId");
|
||||
|
||||
b.HasIndex("PosterUserId");
|
||||
|
||||
b.HasIndex("TargetUserId");
|
||||
|
||||
b.ToTable("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("LastMatches");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("X")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Y")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Locations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b =>
|
||||
{
|
||||
b.Property<int>("TokenId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("UserToken")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("TokenId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Biography")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BooHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CommentCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("CommentsEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("FavouriteSlotCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("FavouriteUserCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Game")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Lists")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LolCatFtwCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosByMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosWithMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Pins")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PlanetHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("ReviewCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeBronzeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeGoldCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeSilverCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UsedSlots")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("YayHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("HeartedUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("HeartedUser");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster")
|
||||
.WithMany()
|
||||
.HasForeignKey("PosterUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Poster");
|
||||
|
||||
b.Navigation("Target");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
public partial class AddSlotTimestamp : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<long>(
|
||||
name: "Timestamp",
|
||||
table: "Slots",
|
||||
type: "bigint",
|
||||
nullable: false,
|
||||
defaultValue: TimeHelper.UnixTimeMilliseconds());
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Timestamp",
|
||||
table: "Slots");
|
||||
}
|
||||
}
|
||||
}
|
424
ProjectLighthouse/Migrations/20211028021513_AddSlotFirstUploadedAndLastUpdated.Designer.cs
generated
Normal file
424
ProjectLighthouse/Migrations/20211028021513_AddSlotFirstUploadedAndLastUpdated.Designer.cs
generated
Normal file
|
@ -0,0 +1,424 @@
|
|||
// <auto-generated />
|
||||
using LBPUnion.ProjectLighthouse;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
[DbContext(typeof(Database))]
|
||||
[Migration("20211028021513_AddSlotFirstUploadedAndLastUpdated")]
|
||||
partial class AddSlotFirstUploadedAndLastUpdated
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64)
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.Property<int>("HeartedProfileId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartedUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedProfileId");
|
||||
|
||||
b.HasIndex("HeartedUserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedProfiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.Property<int>("HeartedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.Property<int>("QueuedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("QueuedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("QueuedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.Property<int>("SlotId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("AuthorLabels")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BackgroundHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CreatorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("FirstUploaded")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("InitiallyLocked")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<long>("LastUpdated")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("Lbp1Only")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MaximumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MinimumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("MoveRequired")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ResourceCollection")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("RootLevel")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Shareable")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("SubLevel")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("SlotId");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Slots");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.Property<int>("CommentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("PosterUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("TargetUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsDown")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsUp")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("CommentId");
|
||||
|
||||
b.HasIndex("PosterUserId");
|
||||
|
||||
b.HasIndex("TargetUserId");
|
||||
|
||||
b.ToTable("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("LastMatches");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("X")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Y")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Locations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b =>
|
||||
{
|
||||
b.Property<int>("TokenId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("UserToken")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("TokenId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Biography")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BooHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CommentCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("CommentsEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("FavouriteSlotCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("FavouriteUserCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Game")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Lists")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LolCatFtwCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosByMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosWithMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Pins")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PlanetHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("ReviewCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeBronzeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeGoldCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeSilverCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UsedSlots")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("YayHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("HeartedUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("HeartedUser");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster")
|
||||
.WithMany()
|
||||
.HasForeignKey("PosterUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Poster");
|
||||
|
||||
b.Navigation("Target");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
public partial class AddSlotFirstUploadedAndLastUpdated : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "Timestamp",
|
||||
table: "Slots",
|
||||
newName: "LastUpdated");
|
||||
|
||||
migrationBuilder.AddColumn<long>(
|
||||
name: "FirstUploaded",
|
||||
table: "Slots",
|
||||
type: "bigint",
|
||||
nullable: false,
|
||||
defaultValue: TimeHelper.UnixTimeMilliseconds());
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FirstUploaded",
|
||||
table: "Slots");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "LastUpdated",
|
||||
table: "Slots",
|
||||
newName: "Timestamp");
|
||||
}
|
||||
}
|
||||
}
|
421
ProjectLighthouse/Migrations/20211029213334_RemoveUsedSlotsFromDb.Designer.cs
generated
Normal file
421
ProjectLighthouse/Migrations/20211029213334_RemoveUsedSlotsFromDb.Designer.cs
generated
Normal file
|
@ -0,0 +1,421 @@
|
|||
// <auto-generated />
|
||||
using LBPUnion.ProjectLighthouse;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
[DbContext(typeof(Database))]
|
||||
[Migration("20211029213334_RemoveUsedSlotsFromDb")]
|
||||
partial class RemoveUsedSlotsFromDb
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64)
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.Property<int>("HeartedProfileId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartedUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedProfileId");
|
||||
|
||||
b.HasIndex("HeartedUserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedProfiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.Property<int>("HeartedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.Property<int>("QueuedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("QueuedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("QueuedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.Property<int>("SlotId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("AuthorLabels")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BackgroundHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CreatorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("FirstUploaded")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("InitiallyLocked")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<long>("LastUpdated")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("Lbp1Only")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MaximumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MinimumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("MoveRequired")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ResourceCollection")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("RootLevel")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Shareable")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("SubLevel")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("SlotId");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Slots");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.Property<int>("CommentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("PosterUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("TargetUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsDown")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsUp")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("CommentId");
|
||||
|
||||
b.HasIndex("PosterUserId");
|
||||
|
||||
b.HasIndex("TargetUserId");
|
||||
|
||||
b.ToTable("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("LastMatches");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("X")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Y")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Locations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b =>
|
||||
{
|
||||
b.Property<int>("TokenId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("UserToken")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("TokenId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Biography")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BooHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CommentCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("CommentsEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("FavouriteSlotCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("FavouriteUserCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Game")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Lists")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LolCatFtwCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosByMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosWithMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Pins")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PlanetHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("ReviewCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeBronzeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeGoldCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeSilverCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("YayHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("HeartedUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("HeartedUser");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster")
|
||||
.WithMany()
|
||||
.HasForeignKey("PosterUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Poster");
|
||||
|
||||
b.Navigation("Target");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
public partial class RemoveUsedSlotsFromDb : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "UsedSlots",
|
||||
table: "Users");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "UsedSlots",
|
||||
table: "Users",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
}
|
||||
}
|
424
ProjectLighthouse/Migrations/20211030203837_AddMMPickToSlot.Designer.cs
generated
Normal file
424
ProjectLighthouse/Migrations/20211030203837_AddMMPickToSlot.Designer.cs
generated
Normal file
|
@ -0,0 +1,424 @@
|
|||
// <auto-generated />
|
||||
using LBPUnion.ProjectLighthouse;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
[DbContext(typeof(Database))]
|
||||
[Migration("20211030203837_AddMMPickToSlot")]
|
||||
partial class AddMMPickToSlot
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64)
|
||||
.HasAnnotation("ProductVersion", "5.0.11");
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.Property<int>("HeartedProfileId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartedUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedProfileId");
|
||||
|
||||
b.HasIndex("HeartedUserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedProfiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.Property<int>("HeartedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("HeartedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("HeartedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.Property<int>("QueuedLevelId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SlotId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("QueuedLevelId");
|
||||
|
||||
b.HasIndex("SlotId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("QueuedLevels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.Property<int>("SlotId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("AuthorLabels")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BackgroundHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CreatorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("FirstUploaded")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("InitiallyLocked")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<long>("LastUpdated")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("Lbp1Only")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("MMPick")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("MaximumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MinimumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("MoveRequired")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ResourceCollection")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("RootLevel")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Shareable")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("SubLevel")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.HasKey("SlotId");
|
||||
|
||||
b.HasIndex("CreatorId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Slots");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.Property<int>("CommentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("PosterUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("TargetUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsDown")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ThumbsUp")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("CommentId");
|
||||
|
||||
b.HasIndex("PosterUserId");
|
||||
|
||||
b.HasIndex("TargetUserId");
|
||||
|
||||
b.ToTable("Comments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("LastMatches");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("X")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Y")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Locations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b =>
|
||||
{
|
||||
b.Property<int>("TokenId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("UserToken")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("TokenId");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Biography")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("BooHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("CommentCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("CommentsEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("FavouriteSlotCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("FavouriteUserCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Game")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("HeartCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("Lists")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("LolCatFtwCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosByMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PhotosWithMeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Pins")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PlanetHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("ReviewCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeBronzeCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeGoldCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("StaffChallengeSilverCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("YayHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.HasIndex("LocationId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("HeartedUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("HeartedUser");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
|
||||
.WithMany()
|
||||
.HasForeignKey("SlotId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Slot");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatorId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Creator");
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster")
|
||||
.WithMany()
|
||||
.HasForeignKey("PosterUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetUserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Poster");
|
||||
|
||||
b.Navigation("Target");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
|
||||
{
|
||||
b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
|
||||
.WithMany()
|
||||
.HasForeignKey("LocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Location");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
public partial class AddMMPickToSlot : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "MMPick",
|
||||
table: "Slots",
|
||||
type: "tinyint(1)",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MMPick",
|
||||
table: "Slots");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -97,18 +97,27 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<string>("Description")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("FirstUploaded")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("IconHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("InitiallyLocked")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<long>("LastUpdated")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<bool>("Lbp1Only")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("LocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("MMPick")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<int>("MaximumPlayers")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
@ -289,9 +298,6 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<int>("StaffChallengeSilverCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UsedSlots")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -17,8 +21,8 @@ namespace LBPUnion.ProjectLighthouse
|
|||
public static void Main(string[] args)
|
||||
{
|
||||
// Log startup time
|
||||
Stopwatch startupStopwatch = new();
|
||||
startupStopwatch.Start();
|
||||
Stopwatch stopwatch = new();
|
||||
stopwatch.Start();
|
||||
|
||||
// Setup logging
|
||||
|
||||
|
@ -30,39 +34,67 @@ namespace LBPUnion.ProjectLighthouse
|
|||
Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance);
|
||||
Logger.Log("Determining if the database is available...", LoggerLevelStartup.Instance);
|
||||
bool dbConnected = ServerSettings.DbConnected;
|
||||
Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.",
|
||||
LoggerLevelStartup.Instance);
|
||||
Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.", LoggerLevelStartup.Instance);
|
||||
|
||||
if (dbConnected)
|
||||
{
|
||||
Stopwatch migrationStopwatch = new();
|
||||
migrationStopwatch.Start();
|
||||
if (!dbConnected) Environment.Exit(1);
|
||||
using Database database = new();
|
||||
|
||||
Logger.Log("Migrating database...", LoggerLevelDatabase.Instance);
|
||||
using Database database = new();
|
||||
database.Database.Migrate();
|
||||
Logger.Log("Migrating database...", LoggerLevelDatabase.Instance);
|
||||
MigrateDatabase(database);
|
||||
|
||||
migrationStopwatch.Stop();
|
||||
Logger.Log($"Migration took {migrationStopwatch.ElapsedMilliseconds}ms.", LoggerLevelDatabase.Instance);
|
||||
}
|
||||
else Environment.Exit(1);
|
||||
Logger.Log("Fixing broken timestamps...", LoggerLevelDatabase.Instance);
|
||||
FixTimestamps(database);
|
||||
|
||||
startupStopwatch.Stop();
|
||||
Logger.Log(
|
||||
$"Ready! Startup took {startupStopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...",
|
||||
LoggerLevelStartup.Instance);
|
||||
stopwatch.Stop();
|
||||
Logger.Log($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LoggerLevelStartup.Instance);
|
||||
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.Services.TryAddEnumerable(ServiceDescriptor
|
||||
.Singleton<ILoggerProvider, AspNetToKettuLoggerProvider>());
|
||||
});
|
||||
public static void MigrateDatabase(Database database)
|
||||
{
|
||||
Stopwatch stopwatch = new();
|
||||
stopwatch.Start();
|
||||
|
||||
database.Database.Migrate();
|
||||
|
||||
stopwatch.Stop();
|
||||
Logger.Log($"Migration took {stopwatch.ElapsedMilliseconds}ms.", LoggerLevelDatabase.Instance);
|
||||
}
|
||||
|
||||
public static void FixTimestamps(Database database)
|
||||
{
|
||||
Stopwatch stopwatch = new();
|
||||
stopwatch.Start();
|
||||
|
||||
foreach (Slot slot in database.Slots.Where(s => s.FirstUploaded == 0)) slot.FirstUploaded = TimeHelper.UnixTimeMilliseconds();
|
||||
|
||||
foreach (Slot slot in database.Slots.Where(s => s.LastUpdated == 0)) slot.LastUpdated = TimeHelper.UnixTimeMilliseconds();
|
||||
|
||||
foreach (Comment comment in database.Comments.Where(c => c.Timestamp == 0)) comment.Timestamp = TimeHelper.UnixTimeMilliseconds();
|
||||
|
||||
database.SaveChanges();
|
||||
|
||||
stopwatch.Stop();
|
||||
Logger.Log($"Fixing timestamps took {stopwatch.ElapsedMilliseconds}ms.", LoggerLevelDatabase.Instance);
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
=> Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults
|
||||
(
|
||||
webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
}
|
||||
)
|
||||
.ConfigureLogging
|
||||
(
|
||||
logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToKettuLoggerProvider>());
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -8,19 +8,23 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
|
||||
<PackageReference Include="Kettu" Version="1.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.11" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2"/>
|
||||
<PackageReference Include="Kettu" Version="1.1.0"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.11"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.11"/>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.11">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Types\SlotXsd.cs" />
|
||||
<Compile Remove="Types\SlotXsd.cs"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="logs"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"ProjectLighthouse": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"applicationUrl": "http://localhost:10060;http://localhost:10061;http://localhost:1062",
|
||||
"applicationUrl": "http://localhost:10060",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"LIGHTHOUSE_DB_CONNECTION_STRING": "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"
|
||||
|
|
|
@ -2,26 +2,30 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Serialization {
|
||||
namespace LBPUnion.ProjectLighthouse.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// LBP doesn't like the XML serializer by C# that much, and it cant be controlled that much (cant have two root elements),
|
||||
/// so I wrote my own crappy one.
|
||||
/// LBP doesn't like the XML serializer by C# that much, and it cant be controlled that much (cant have two root
|
||||
/// elements),
|
||||
/// so I wrote my own crappy one.
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
public static class LbpSerializer {
|
||||
public static class LbpSerializer
|
||||
{
|
||||
public static string BlankElement(string key) => $"<{key}></{key}>";
|
||||
|
||||
public static string StringElement(KeyValuePair<string, object> pair) => $"<{pair.Key}>{pair.Value}</{pair.Key}>";
|
||||
|
||||
public static string StringElement(string key, object value) => $"<{key}>{value}</{key}>";
|
||||
|
||||
public static string TaggedStringElement(KeyValuePair<string, object> pair, KeyValuePair<string, object> tagPair) =>
|
||||
$"<{pair.Key} {tagPair.Key}=\"{tagPair.Value}\">{pair.Value}</{pair.Key}>";
|
||||
|
||||
public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) =>
|
||||
$"<{key} {tagKey}=\"{tagValue}\">{value}</{key}>";
|
||||
|
||||
public static string Elements(params KeyValuePair<string, object>[] pairs) =>
|
||||
pairs.Aggregate(string.Empty, (current, pair) => current + StringElement(pair));
|
||||
public static string TaggedStringElement
|
||||
(KeyValuePair<string, object> pair, KeyValuePair<string, object> tagPair)
|
||||
=> $"<{pair.Key} {tagPair.Key}=\"{tagPair.Value}\">{pair.Value}</{pair.Key}>";
|
||||
|
||||
public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}</{key}>";
|
||||
|
||||
public static string Elements
|
||||
(params KeyValuePair<string, object>[] pairs)
|
||||
=> pairs.Aggregate(string.Empty, (current, pair) => current + StringElement(pair));
|
||||
}
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Serialization {
|
||||
public class XmlOutputFormatter : StringOutputFormatter {
|
||||
public XmlOutputFormatter() {
|
||||
namespace LBPUnion.ProjectLighthouse.Serialization
|
||||
{
|
||||
public class XmlOutputFormatter : StringOutputFormatter
|
||||
{
|
||||
public XmlOutputFormatter()
|
||||
{
|
||||
this.SupportedMediaTypes.Add("text/xml");
|
||||
this.SupportedMediaTypes.Add("application/xml");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
@ -14,7 +12,7 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse
|
||||
{
|
||||
|
@ -31,8 +29,8 @@ namespace LBPUnion.ProjectLighthouse
|
|||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers();
|
||||
services.AddMvc(options =>
|
||||
options.OutputFormatters.Add(new XmlOutputFormatter()));
|
||||
|
||||
services.AddMvc(options => options.OutputFormatters.Add(new XmlOutputFormatter()));
|
||||
|
||||
services.AddDbContext<Database>();
|
||||
}
|
||||
|
@ -44,100 +42,96 @@ namespace LBPUnion.ProjectLighthouse
|
|||
string serverDigestKey = Environment.GetEnvironmentVariable("SERVER_DIGEST_KEY");
|
||||
if (string.IsNullOrWhiteSpace(serverDigestKey))
|
||||
{
|
||||
Logger.Log(
|
||||
Logger.Log
|
||||
(
|
||||
"The SERVER_DIGEST_KEY environment variable wasn't set, so digest headers won't be set or verified. This will prevent LBP 1 and LBP 3 from working. " +
|
||||
"To increase security, it is recommended that you find and set this variable."
|
||||
);
|
||||
computeDigests = false;
|
||||
}
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
|
||||
|
||||
// Logs every request and the response to it
|
||||
// Example: "200, 13ms: GET /LITTLEBIGPLANETPS3_XML/news"
|
||||
// Example: "404, 127ms: GET /asdasd?query=osucookiezi727ppbluezenithtopplayhdhr"
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
Stopwatch requestStopwatch = new();
|
||||
requestStopwatch.Start();
|
||||
|
||||
// Log all headers.
|
||||
foreach (var header in context.Request.Headers)
|
||||
Logger.Log($"{header.Key}: {header.Value}");
|
||||
|
||||
context.Request.EnableBuffering(); // Allows us to reset the position of Request.Body for later logging
|
||||
|
||||
// Client digest check.
|
||||
string authCookie;
|
||||
if (!context.Request.Cookies.TryGetValue("MM_AUTH", out authCookie))
|
||||
authCookie = string.Empty;
|
||||
string digestPath = context.Request.Path;
|
||||
Stream body = context.Request.Body;
|
||||
|
||||
if (computeDigests)
|
||||
app.Use
|
||||
(
|
||||
async (context, next) =>
|
||||
{
|
||||
string clientRequestDigest =
|
||||
await HashHelper.ComputeDigest(digestPath, authCookie, body, serverDigestKey);
|
||||
Stopwatch requestStopwatch = new();
|
||||
requestStopwatch.Start();
|
||||
|
||||
// Check the digest we've just calculated against the X-Digest-A header if the game set the header. They should match.
|
||||
if (context.Request.Headers.TryGetValue("X-Digest-A", out var sentDigest))
|
||||
// Log all headers.
|
||||
foreach (KeyValuePair<string, StringValues> header in context.Request.Headers) Logger.Log($"{header.Key}: {header.Value}");
|
||||
|
||||
context.Request.EnableBuffering(); // Allows us to reset the position of Request.Body for later logging
|
||||
|
||||
// Client digest check.
|
||||
string authCookie;
|
||||
if (!context.Request.Cookies.TryGetValue("MM_AUTH", out authCookie)) authCookie = string.Empty;
|
||||
string digestPath = context.Request.Path;
|
||||
Stream body = context.Request.Body;
|
||||
|
||||
if (computeDigests)
|
||||
{
|
||||
if (clientRequestDigest != sentDigest)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
context.Abort();
|
||||
return;
|
||||
}
|
||||
string clientRequestDigest = await HashHelper.ComputeDigest(digestPath, authCookie, body, serverDigestKey);
|
||||
|
||||
// Check the digest we've just calculated against the X-Digest-A header if the game set the header. They should match.
|
||||
if (context.Request.Headers.TryGetValue("X-Digest-A", out StringValues sentDigest))
|
||||
if (clientRequestDigest != sentDigest)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
context.Abort();
|
||||
return;
|
||||
}
|
||||
|
||||
context.Response.Headers.Add("X-Digest-B", clientRequestDigest);
|
||||
context.Request.Body.Position = 0;
|
||||
}
|
||||
|
||||
context.Response.Headers.Add("X-Digest-B", clientRequestDigest);
|
||||
context.Request.Body.Position = 0;
|
||||
}
|
||||
// This does the same as above, but for the response stream.
|
||||
using MemoryStream responseBuffer = new();
|
||||
Stream oldResponseStream = context.Response.Body;
|
||||
context.Response.Body = responseBuffer;
|
||||
|
||||
// This does the same as above, but for the response stream.
|
||||
using MemoryStream responseBuffer = new MemoryStream();
|
||||
Stream oldResponseStream = context.Response.Body;
|
||||
context.Response.Body = responseBuffer;
|
||||
await next(); // Handle the request so we can get the status code from it
|
||||
|
||||
await next(); // Handle the request so we can get the status code from it
|
||||
// Compute the server digest hash.
|
||||
if (computeDigests)
|
||||
{
|
||||
responseBuffer.Position = 0;
|
||||
|
||||
// Compute the server digest hash.
|
||||
if (computeDigests)
|
||||
{
|
||||
// Compute the digest for the response.
|
||||
string serverDigest = await HashHelper.ComputeDigest(context.Request.Path, authCookie, responseBuffer, serverDigestKey);
|
||||
context.Response.Headers.Add("X-Digest-A", serverDigest);
|
||||
}
|
||||
|
||||
// Set the X-Original-Content-Length header to the length of the response buffer.
|
||||
context.Response.Headers.Add("X-Original-Content-Length", responseBuffer.Length.ToString());
|
||||
|
||||
// Copy the buffered response to the actual respose stream.
|
||||
responseBuffer.Position = 0;
|
||||
|
||||
// Compute the digest for the response.
|
||||
string serverDigest = await HashHelper.ComputeDigest(context.Request.Path, authCookie,
|
||||
responseBuffer, serverDigestKey);
|
||||
context.Response.Headers.Add("X-Digest-A", serverDigest);
|
||||
|
||||
await responseBuffer.CopyToAsync(oldResponseStream);
|
||||
|
||||
context.Response.Body = oldResponseStream;
|
||||
|
||||
requestStopwatch.Stop();
|
||||
|
||||
Logger.Log
|
||||
(
|
||||
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
|
||||
LoggerLevelHttp.Instance
|
||||
);
|
||||
|
||||
if (context.Request.Method == "POST")
|
||||
{
|
||||
context.Request.Body.Position = 0;
|
||||
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the X-Original-Content-Length header to the length of the response buffer.
|
||||
context.Response.Headers.Add("X-Original-Content-Length", responseBuffer.Length.ToString());
|
||||
|
||||
// Copy the buffered response to the actual respose stream.
|
||||
responseBuffer.Position = 0;
|
||||
|
||||
await responseBuffer.CopyToAsync(oldResponseStream);
|
||||
|
||||
context.Response.Body = oldResponseStream;
|
||||
|
||||
requestStopwatch.Stop();
|
||||
|
||||
Logger.Log(
|
||||
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
|
||||
LoggerLevelHttp.Instance
|
||||
);
|
||||
|
||||
if (context.Request.Method == "POST")
|
||||
{
|
||||
context.Request.Body.Position = 0;
|
||||
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance);
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Files {
|
||||
public class LbpFile {
|
||||
public LbpFile(byte[] data) {
|
||||
this.Data = data;
|
||||
this.FileType = FileHelper.DetermineFileType(this.Data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of file.
|
||||
/// </summary>
|
||||
public LbpFileType FileType;
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Files
|
||||
{
|
||||
public class LbpFile
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A buffer of the file's data.
|
||||
/// A buffer of the file's data.
|
||||
/// </summary>
|
||||
public readonly byte[] Data;
|
||||
|
||||
/// <summary>
|
||||
/// The type of file.
|
||||
/// </summary>
|
||||
public LbpFileType FileType;
|
||||
|
||||
public LbpFile(byte[] data)
|
||||
{
|
||||
this.Data = data;
|
||||
this.FileType = FileHelper.DetermineFileType(this.Data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Files {
|
||||
public enum LbpFileType {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Files
|
||||
{
|
||||
public enum LbpFileType
|
||||
{
|
||||
Script, // .ff, FSH
|
||||
Texture, // TEX
|
||||
Level, // LVL
|
||||
FileArchive, // .farc, (ends with FARC)
|
||||
Plan, // PLN, uploaded with levels
|
||||
Voice, // VOP, voice data
|
||||
Painting, // PTG, paintings
|
||||
Unknown,
|
||||
}
|
||||
}
|
|
@ -2,22 +2,27 @@ using System;
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types {
|
||||
public class HeartedProfile {
|
||||
namespace LBPUnion.ProjectLighthouse.Types
|
||||
{
|
||||
public class HeartedProfile
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
#if NET6_0_OR_GREATER
|
||||
[Obsolete($"Use {nameof(HeartedUserId)} instead, this is a key which you should never need to use.")]
|
||||
#else
|
||||
[Obsolete("Use HeartedUserId instead, this is a key which you should never need to use.")]
|
||||
#endif
|
||||
[Key] public int HeartedProfileId { get; set; }
|
||||
[Key]
|
||||
public int HeartedProfileId { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(UserId))] public User User { get; set; }
|
||||
[ForeignKey(nameof(UserId))]
|
||||
public User User { get; set; }
|
||||
|
||||
public int HeartedUserId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(HeartedUserId))] public User HeartedUser { get; set; }
|
||||
[ForeignKey(nameof(HeartedUserId))]
|
||||
public User HeartedUser { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,17 +1,22 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels {
|
||||
public class HeartedLevel {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels
|
||||
{
|
||||
public class HeartedLevel
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
[Key] public int HeartedLevelId { get; set; }
|
||||
[Key]
|
||||
public int HeartedLevelId { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(UserId))] public User User { get; set; }
|
||||
[ForeignKey(nameof(UserId))]
|
||||
public User User { get; set; }
|
||||
|
||||
public int SlotId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(SlotId))] public Slot Slot { get; set; }
|
||||
[ForeignKey(nameof(SlotId))]
|
||||
public Slot Slot { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels
|
||||
{
|
||||
/// <summary>
|
||||
/// A series of tags that can be applied to a level
|
||||
/// A series of tags that can be applied to a level
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
public enum LevelTags {
|
||||
public enum LevelTags
|
||||
{
|
||||
Brilliant,
|
||||
Beautiful,
|
||||
Funky,
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels {
|
||||
public class QueuedLevel {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels
|
||||
{
|
||||
public class QueuedLevel
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
[Key] public int QueuedLevelId { get; set; }
|
||||
|
||||
[Key]
|
||||
public int QueuedLevelId { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(UserId))]
|
||||
public User User { get; set; }
|
||||
|
||||
|
||||
public int SlotId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(SlotId))]
|
||||
|
|
|
@ -5,92 +5,103 @@ using System.Xml.Serialization;
|
|||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Levels
|
||||
{
|
||||
/// <summary>
|
||||
/// A LittleBigPlanet level.
|
||||
/// A LittleBigPlanet level.
|
||||
/// </summary>
|
||||
[XmlRoot("slot"), XmlType("slot")]
|
||||
public class Slot {
|
||||
[XmlRoot("slot")]
|
||||
[XmlType("slot")]
|
||||
public class Slot
|
||||
{
|
||||
[XmlAttribute("type")]
|
||||
[NotMapped]
|
||||
public string Type { get; set; }
|
||||
|
||||
[Key]
|
||||
[XmlIgnore]
|
||||
[XmlElement("id")]
|
||||
public int SlotId { get; set; }
|
||||
|
||||
|
||||
[XmlElement("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
[XmlElement("description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
|
||||
[XmlElement("icon")]
|
||||
public string IconHash { get; set; }
|
||||
|
||||
|
||||
[XmlElement("rootLevel")]
|
||||
public string RootLevel { get; set; }
|
||||
|
||||
public string ResourceCollection { get; set; }
|
||||
|
||||
|
||||
[NotMapped]
|
||||
[XmlElement("resource")]
|
||||
public string[] Resources {
|
||||
get => this.ResourceCollection.Split(",");
|
||||
set => this.ResourceCollection = string.Join(',', value);
|
||||
}
|
||||
|
||||
|
||||
[XmlIgnore]
|
||||
public int LocationId { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
[XmlIgnore]
|
||||
public int CreatorId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(CreatorId))]
|
||||
public User Creator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location of the level on the creator's earth
|
||||
/// The location of the level on the creator's earth
|
||||
/// </summary>
|
||||
[XmlElement("location")]
|
||||
[ForeignKey(nameof(LocationId))]
|
||||
public Location Location { get; set; }
|
||||
|
||||
|
||||
[XmlElement("initiallyLocked")]
|
||||
public bool InitiallyLocked { get; set; }
|
||||
|
||||
|
||||
[XmlElement("isSubLevel")]
|
||||
public bool SubLevel { get; set; }
|
||||
|
||||
|
||||
[XmlElement("isLBP1Only")]
|
||||
public bool Lbp1Only { get; set; }
|
||||
|
||||
|
||||
[XmlElement("shareable")]
|
||||
public int Shareable { get; set; }
|
||||
|
||||
|
||||
[XmlElement("authorLabels")]
|
||||
public string AuthorLabels { get; set; }
|
||||
|
||||
[XmlElement("background")]
|
||||
[XmlElement("background")]
|
||||
public string BackgroundHash { get; set; } = "";
|
||||
|
||||
|
||||
[XmlElement("minPlayers")]
|
||||
public int MinimumPlayers { get; set; }
|
||||
|
||||
|
||||
[XmlElement("maxPlayers")]
|
||||
public int MaximumPlayers { get; set; }
|
||||
|
||||
|
||||
[XmlElement("moveRequired")]
|
||||
public bool MoveRequired { get; set; }
|
||||
|
||||
public string SerializeResources() {
|
||||
return this.Resources
|
||||
.Aggregate("", (current, resource) =>
|
||||
current + LbpSerializer.StringElement("resource", resource));
|
||||
[XmlIgnore]
|
||||
public long FirstUploaded { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public long LastUpdated { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public bool MMPick { get; set; }
|
||||
|
||||
public string SerializeResources()
|
||||
{
|
||||
return this.Resources.Aggregate("", (current, resource) => current + LbpSerializer.StringElement("resource", resource));
|
||||
}
|
||||
|
||||
public string Serialize() {
|
||||
public string Serialize()
|
||||
{
|
||||
string slotData = LbpSerializer.StringElement("name", this.Name) +
|
||||
LbpSerializer.StringElement("id", this.SlotId) +
|
||||
LbpSerializer.StringElement("game", 1) +
|
||||
|
@ -107,8 +118,11 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels {
|
|||
LbpSerializer.StringElement("background", this.BackgroundHash) +
|
||||
LbpSerializer.StringElement("minPlayers", this.MinimumPlayers) +
|
||||
LbpSerializer.StringElement("maxPlayers", this.MaximumPlayers) +
|
||||
LbpSerializer.StringElement("moveRequired", this.MoveRequired);
|
||||
|
||||
LbpSerializer.StringElement("moveRequired", this.MoveRequired) +
|
||||
LbpSerializer.StringElement("firstPublished", this.FirstUploaded) +
|
||||
LbpSerializer.StringElement("lastUpdated", this.LastUpdated) +
|
||||
LbpSerializer.StringElement("mmpick", this.MMPick);
|
||||
|
||||
return LbpSerializer.TaggedStringElement("slot", slotData, "type", "user");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +1,43 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types {
|
||||
// This is all the information I can understand for now. More testing is required.
|
||||
// Example data:
|
||||
// - LBP2 digital, with the RPCN username `literally1984`
|
||||
// POST /LITTLEBIGPLANETPS3_XML/login?applicationID=21414&languageID=1&lbp2=1&beta=0&titleID=NPUA80662&country=us
|
||||
// !<21>0256333||x||<7C><>Y literally198bruUP9000-NPUA80662_008D
|
||||
// - LBP2 digital, with the RPCN username `jvyden`
|
||||
// POST /LITTLEBIGPLANETPS3_XML/login?applicationID=21414&languageID=1&lbp2=1&beta=0&titleID=NPUA80662&country=us
|
||||
// !<21>0220333||/u||=0<> jvydebruUP9000-NPUA80662_008D
|
||||
namespace LBPUnion.ProjectLighthouse.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// The data sent from POST /LOGIN.
|
||||
/// The data sent from POST /LOGIN.
|
||||
/// </summary>
|
||||
public class LoginData {
|
||||
public string Username { get; set; }
|
||||
// public string GameVersion { get; set; }
|
||||
// public int UnknownNumber { get; set; } // Seems to increment by 1000 every login attempt
|
||||
public class LoginData
|
||||
{
|
||||
|
||||
public static LoginData CreateFromString(string str) {
|
||||
do {
|
||||
str = str.Replace("\b", string.Empty); // Trim backspace characters
|
||||
} while(str.Contains('\b'));
|
||||
public static readonly string UsernamePrefix = Encoding.ASCII.GetString
|
||||
(
|
||||
new byte[]
|
||||
{
|
||||
0x04, 0x00, 0x20,
|
||||
}
|
||||
);
|
||||
|
||||
public string Username { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Converts a X-I-5 Ticket into `LoginData`.
|
||||
/// https://www.psdevwiki.com/ps3/X-I-5-Ticket
|
||||
/// </summary>
|
||||
public static LoginData? CreateFromString(string str)
|
||||
{
|
||||
str = str.Replace("\b", ""); // Remove backspace characters
|
||||
|
||||
using MemoryStream ms = new(Encoding.ASCII.GetBytes(str));
|
||||
using BinaryReader reader = new(ms);
|
||||
|
||||
if (!str.Contains(UsernamePrefix)) return null;
|
||||
|
||||
LoginData loginData = new();
|
||||
|
||||
BinaryHelper.ReadUntilByte(reader, 0x20); // Skips to relevant part
|
||||
|
||||
// byte[] endBytes = reader.ReadBytes((int)(ms.Length - reader.BaseStream.Position));
|
||||
// string end = Encoding.ASCII.GetString(endBytes);
|
||||
|
||||
reader.BaseStream.Position = str.IndexOf(UsernamePrefix, StringComparison.Ordinal) + UsernamePrefix.Length;
|
||||
loginData.Username = BinaryHelper.ReadString(reader).Replace("\0", string.Empty);
|
||||
|
||||
return loginData;
|
||||
|
|
|
@ -2,23 +2,23 @@ using System.Collections.Generic;
|
|||
using System.Xml.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types {
|
||||
namespace LBPUnion.ProjectLighthouse.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Response to POST /login
|
||||
/// Response to POST /login
|
||||
/// </summary>
|
||||
[XmlRoot("loginResult"), XmlType("loginResult")]
|
||||
public class LoginResult {
|
||||
[XmlRoot("loginResult")]
|
||||
[XmlType("loginResult")]
|
||||
public class LoginResult
|
||||
{
|
||||
[XmlElement("authTicket")]
|
||||
public string AuthTicket { get; set; }
|
||||
|
||||
[XmlElement("lbpEnvVer")]
|
||||
public string LbpEnvVer { get; set; }
|
||||
|
||||
public string Serialize() {
|
||||
return LbpSerializer.Elements(
|
||||
new KeyValuePair<string, object>("authTicket", this.AuthTicket),
|
||||
new KeyValuePair<string, object>("lbpEnvVer", this.LbpEnvVer)
|
||||
);
|
||||
}
|
||||
public string Serialize()
|
||||
=> LbpSerializer.Elements
|
||||
(new KeyValuePair<string, object>("authTicket", this.AuthTicket), new KeyValuePair<string, object>("lbpEnvVer", this.LbpEnvVer));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Match {
|
||||
public interface IMatchData {
|
||||
|
||||
}
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Match
|
||||
{
|
||||
public interface IMatchData
|
||||
{}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Match {
|
||||
public enum RoomState {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Match
|
||||
{
|
||||
public enum RoomState
|
||||
{
|
||||
Idle = 0,
|
||||
LookingForPlayersForLevel = 1,
|
||||
Unknown = 2,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Match {
|
||||
public class UpdateMyPlayerData : IMatchData {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Match
|
||||
{
|
||||
public class UpdateMyPlayerData : IMatchData
|
||||
{
|
||||
public string Player;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Match {
|
||||
public class UpdatePlayersInRoom : IMatchData {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Match
|
||||
{
|
||||
public class UpdatePlayersInRoom : IMatchData
|
||||
{
|
||||
public List<string> Players;
|
||||
public List<string> Reservations;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.News {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.News
|
||||
{
|
||||
/// <summary>
|
||||
/// Used on the info moon on LBP1. Broken for unknown reasons
|
||||
/// Used on the info moon on LBP1. Broken for unknown reasons
|
||||
/// </summary>
|
||||
public class NewsEntry {
|
||||
public class NewsEntry
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Summary { get; set; }
|
||||
|
@ -13,14 +15,13 @@ namespace LBPUnion.ProjectLighthouse.Types.News {
|
|||
public string Category { get; set; }
|
||||
public long Date { get; set; }
|
||||
|
||||
public string Serialize() {
|
||||
return LbpSerializer.StringElement("id", this.Id) +
|
||||
LbpSerializer.StringElement("title", this.Title) +
|
||||
LbpSerializer.StringElement("summary", this.Summary) +
|
||||
LbpSerializer.StringElement("text", this.Text) +
|
||||
LbpSerializer.StringElement("date", this.Date) +
|
||||
this.Image.Serialize() +
|
||||
LbpSerializer.StringElement("category", this.Category);
|
||||
}
|
||||
public string Serialize()
|
||||
=> LbpSerializer.StringElement("id", this.Id) +
|
||||
LbpSerializer.StringElement("title", this.Title) +
|
||||
LbpSerializer.StringElement("summary", this.Summary) +
|
||||
LbpSerializer.StringElement("text", this.Text) +
|
||||
LbpSerializer.StringElement("date", this.Date) +
|
||||
this.Image.Serialize() +
|
||||
LbpSerializer.StringElement("category", this.Category);
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.News {
|
||||
public class NewsImage {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.News
|
||||
{
|
||||
public class NewsImage
|
||||
{
|
||||
public string Hash { get; set; }
|
||||
public string Alignment { get; set; }
|
||||
|
||||
public string Serialize() {
|
||||
return LbpSerializer.StringElement("image",
|
||||
LbpSerializer.StringElement("hash", this.Hash) +
|
||||
LbpSerializer.StringElement("alignment", this.Alignment));
|
||||
}
|
||||
public string Serialize()
|
||||
=> LbpSerializer.StringElement("image", LbpSerializer.StringElement("hash", this.Hash) + LbpSerializer.StringElement("alignment", this.Alignment));
|
||||
}
|
||||
}
|
|
@ -1,22 +1,26 @@
|
|||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles
|
||||
{
|
||||
[Keyless]
|
||||
public class ClientsConnected {
|
||||
public class ClientsConnected
|
||||
{
|
||||
public bool Lbp1 { get; set; }
|
||||
public bool Lbp2 { get; set; }
|
||||
public bool LbpMe { get; set; }
|
||||
public bool Lbp3Ps3 { get; set; }
|
||||
public bool Lbp3Ps4 { get; set; }
|
||||
|
||||
public string Serialize() {
|
||||
return LbpSerializer.StringElement("clientsConnected",
|
||||
public string Serialize()
|
||||
=> LbpSerializer.StringElement
|
||||
(
|
||||
"clientsConnected",
|
||||
LbpSerializer.StringElement("lbp1", this.Lbp1) +
|
||||
LbpSerializer.StringElement("lbp2", this.Lbp2) +
|
||||
LbpSerializer.StringElement("lbpme", this.LbpMe) +
|
||||
LbpSerializer.StringElement("lbp3ps3", this.Lbp3Ps3) +
|
||||
LbpSerializer.StringElement("lbp3ps4", this.Lbp3Ps4));
|
||||
}
|
||||
LbpSerializer.StringElement("lbp3ps4", this.Lbp3Ps4)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,20 +3,23 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||
using System.Xml.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles {
|
||||
[XmlRoot("comment"), XmlType("comment")]
|
||||
public class Comment {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles
|
||||
{
|
||||
[XmlRoot("comment")]
|
||||
[XmlType("comment")]
|
||||
public class Comment
|
||||
{
|
||||
[Key]
|
||||
[XmlAttribute("id")]
|
||||
public int CommentId { get; set; }
|
||||
|
||||
|
||||
public int PosterUserId { get; set; }
|
||||
|
||||
|
||||
public int TargetUserId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(PosterUserId))]
|
||||
public User Poster { get; set; }
|
||||
|
||||
|
||||
[ForeignKey(nameof(TargetUserId))]
|
||||
public User Target { get; set; }
|
||||
|
||||
|
@ -24,24 +27,22 @@ namespace LBPUnion.ProjectLighthouse.Types.Profiles {
|
|||
|
||||
[XmlElement("message")]
|
||||
public string Message { get; set; }
|
||||
|
||||
public int ThumbsUp { get; set; }
|
||||
public int ThumbsDown { get; set; }
|
||||
|
||||
private string serialize() {
|
||||
return LbpSerializer.StringElement("id", this.CommentId) +
|
||||
LbpSerializer.StringElement("npHandle", this.Poster.Username) +
|
||||
LbpSerializer.StringElement("timestamp", this.Timestamp) +
|
||||
LbpSerializer.StringElement("message", this.Message) +
|
||||
LbpSerializer.StringElement("thumbsup", this.ThumbsUp) +
|
||||
LbpSerializer.StringElement("thumbsdown", this.ThumbsDown);
|
||||
}
|
||||
private string serialize()
|
||||
=> LbpSerializer.StringElement("id", this.CommentId) +
|
||||
LbpSerializer.StringElement("npHandle", this.Poster.Username) +
|
||||
LbpSerializer.StringElement("timestamp", this.Timestamp) +
|
||||
LbpSerializer.StringElement("message", this.Message) +
|
||||
LbpSerializer.StringElement("thumbsup", this.ThumbsUp) +
|
||||
LbpSerializer.StringElement("thumbsdown", this.ThumbsDown);
|
||||
|
||||
public string Serialize(int yourThumb) {
|
||||
return LbpSerializer.StringElement("comment", this.serialize() + LbpSerializer.StringElement("yourthumb", yourThumb));
|
||||
}
|
||||
public string Serialize
|
||||
(int yourThumb)
|
||||
=> LbpSerializer.StringElement("comment", this.serialize() + LbpSerializer.StringElement("yourthumb", yourThumb));
|
||||
|
||||
public string Serialize() {
|
||||
return LbpSerializer.StringElement("comment", this.serialize());
|
||||
}
|
||||
public string Serialize() => LbpSerializer.StringElement("comment", this.serialize());
|
||||
}
|
||||
}
|
|
@ -1,8 +1,12 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles {
|
||||
public class LastMatch {
|
||||
[Key] public int UserId { get; set; }
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles
|
||||
{
|
||||
public class LastMatch
|
||||
{
|
||||
[Key]
|
||||
public int UserId { get; set; }
|
||||
|
||||
public long Timestamp { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,17 +1,24 @@
|
|||
using System.Xml.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles
|
||||
{
|
||||
/// <summary>
|
||||
/// The location of a slot on a planet.
|
||||
/// The location of a slot on a planet.
|
||||
/// </summary>
|
||||
public class Location {
|
||||
[XmlRoot("location")]
|
||||
[XmlType("location")]
|
||||
public class Location
|
||||
{
|
||||
[XmlIgnore]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement("x")]
|
||||
public int X { get; set; }
|
||||
|
||||
[XmlElement("y")]
|
||||
public int Y { get; set; }
|
||||
|
||||
public string Serialize() {
|
||||
return LbpSerializer.StringElement("x", this.X) +
|
||||
LbpSerializer.StringElement("y", this.Y);
|
||||
}
|
||||
public string Serialize() => LbpSerializer.StringElement("x", this.X) + LbpSerializer.StringElement("y", this.Y);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
using System.Xml.Serialization;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types {
|
||||
[XmlRoot("resources"), XmlType("resources")]
|
||||
public class ResourceList {
|
||||
[XmlElement("resource")]
|
||||
namespace LBPUnion.ProjectLighthouse.Types
|
||||
{
|
||||
[XmlRoot("resources")]
|
||||
[XmlType("resources")]
|
||||
public class ResourceList
|
||||
{
|
||||
[XmlElement("resource")]
|
||||
public string[] Resources;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,17 @@
|
|||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings {
|
||||
public class PrivacySettings {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings
|
||||
{
|
||||
public class PrivacySettings
|
||||
{
|
||||
public string LevelVisibility { get; set; }
|
||||
public string ProfileVisibility { get; set; }
|
||||
|
||||
public string Serialize() {
|
||||
return LbpSerializer.StringElement("privacySettings",
|
||||
LbpSerializer.StringElement("levelVisibility", this.LevelVisibility) +
|
||||
LbpSerializer.StringElement("profileVisibility", this.ProfileVisibility)
|
||||
public string Serialize()
|
||||
=> LbpSerializer.StringElement
|
||||
(
|
||||
"privacySettings",
|
||||
LbpSerializer.StringElement("levelVisibility", this.LevelVisibility) + LbpSerializer.StringElement("profileVisibility", this.ProfileVisibility)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,23 +3,25 @@ using System;
|
|||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings {
|
||||
public static class ServerSettings {
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Settings
|
||||
{
|
||||
public static class ServerSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum amount of slots allowed on users' earth
|
||||
/// The maximum amount of slots allowed on users' earth
|
||||
/// </summary>
|
||||
public const int EntitledSlots = int.MaxValue;
|
||||
public const int EntitledSlots = 50;
|
||||
|
||||
public const int ListsQuota = 20;
|
||||
public const int ListsQuota = 50;
|
||||
|
||||
public const string ServerName = "ProjectLighthouse";
|
||||
|
||||
private static string? dbConnectionString;
|
||||
|
||||
public static string DbConnectionString {
|
||||
get {
|
||||
if(dbConnectionString == null) {
|
||||
return dbConnectionString = Environment.GetEnvironmentVariable("LIGHTHOUSE_DB_CONNECTION_STRING") ?? "";
|
||||
}
|
||||
if (dbConnectionString == null) return dbConnectionString = Environment.GetEnvironmentVariable("LIGHTHOUSE_DB_CONNECTION_STRING") ?? "";
|
||||
|
||||
return dbConnectionString;
|
||||
}
|
||||
set => dbConnectionString = value;
|
||||
|
@ -27,10 +29,12 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings {
|
|||
|
||||
public static bool DbConnected {
|
||||
get {
|
||||
try {
|
||||
try
|
||||
{
|
||||
return new Database().Database.CanConnect();
|
||||
}
|
||||
catch(Exception e) {
|
||||
catch(Exception e)
|
||||
{
|
||||
Logger.Log(e.ToString(), LoggerLevelDatabase.Instance);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types {
|
||||
public class Token {
|
||||
namespace LBPUnion.ProjectLighthouse.Types
|
||||
{
|
||||
public class Token
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
[Key] public int TokenId { get; set; }
|
||||
[Key]
|
||||
public int TokenId { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
public string UserToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types {
|
||||
public class User {
|
||||
namespace LBPUnion.ProjectLighthouse.Types
|
||||
{
|
||||
public class User
|
||||
{
|
||||
|
||||
// [NotMapped]
|
||||
public readonly ClientsConnected ClientsConnected = new();
|
||||
public int UserId { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string IconHash { get; set; }
|
||||
|
@ -13,21 +19,22 @@ namespace LBPUnion.ProjectLighthouse.Types {
|
|||
public int HeartCount { get; set; }
|
||||
public string YayHash { get; set; }
|
||||
public string BooHash { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A user-customizable biography shown on the profile card
|
||||
/// A user-customizable biography shown on the profile card
|
||||
/// </summary>
|
||||
public string Biography { get; set; }
|
||||
|
||||
public int ReviewCount { get; set; }
|
||||
public int CommentCount { get; set; }
|
||||
public int PhotosByMeCount { get; set; }
|
||||
public int PhotosWithMeCount { get; set; }
|
||||
public bool CommentsEnabled { get; set; }
|
||||
|
||||
|
||||
public int LocationId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The location of the profile card on the user's earth
|
||||
/// The location of the profile card on the user's earth
|
||||
/// </summary>
|
||||
[ForeignKey("LocationId")]
|
||||
public Location Location { get; set; }
|
||||
|
@ -41,50 +48,9 @@ namespace LBPUnion.ProjectLighthouse.Types {
|
|||
public int StaffChallengeBronzeCount { get; set; }
|
||||
|
||||
public string PlanetHash { get; set; } = "";
|
||||
|
||||
// [NotMapped]
|
||||
public readonly ClientsConnected ClientsConnected = new();
|
||||
|
||||
#region Slots
|
||||
|
||||
/// <summary>
|
||||
/// The number of used slots on the earth
|
||||
/// </summary>
|
||||
public int UsedSlots { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of slots remaining on the earth
|
||||
/// </summary>
|
||||
public int FreeSlots => ServerSettings.EntitledSlots - this.UsedSlots;
|
||||
|
||||
private static readonly string[] slotTypes = {
|
||||
// "lbp1",
|
||||
"lbp2",
|
||||
"lbp3",
|
||||
"crossControl",
|
||||
};
|
||||
|
||||
private string SerializeSlots() {
|
||||
string slots = string.Empty;
|
||||
|
||||
slots += LbpSerializer.StringElement("lbp1UsedSlots", this.UsedSlots);
|
||||
slots += LbpSerializer.StringElement("entitledSlots", ServerSettings.EntitledSlots);
|
||||
slots += LbpSerializer.StringElement("freeSlots", this.FreeSlots);
|
||||
|
||||
foreach(string slotType in slotTypes) {
|
||||
slots += LbpSerializer.StringElement(slotType + "UsedSlots", this.UsedSlots);
|
||||
slots += LbpSerializer.StringElement(slotType + "EntitledSlots", ServerSettings.EntitledSlots);
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
slots += LbpSerializer.StringElement(slotType + slotType == "crossControl" ? "PurchsedSlots" : "PurchasedSlots", 0);
|
||||
slots += LbpSerializer.StringElement(slotType + "FreeSlots", this.FreeSlots);
|
||||
}
|
||||
return slots;
|
||||
|
||||
}
|
||||
|
||||
#endregion Slots
|
||||
|
||||
public string Serialize() {
|
||||
public string Serialize()
|
||||
{
|
||||
string user = LbpSerializer.TaggedStringElement("npHandle", this.Username, "icon", this.IconHash) +
|
||||
LbpSerializer.StringElement("game", this.Game) +
|
||||
this.SerializeSlots() +
|
||||
|
@ -110,8 +76,55 @@ namespace LBPUnion.ProjectLighthouse.Types {
|
|||
LbpSerializer.StringElement("planets", this.PlanetHash) +
|
||||
LbpSerializer.BlankElement("photos") +
|
||||
this.ClientsConnected.Serialize();
|
||||
|
||||
|
||||
return LbpSerializer.TaggedStringElement("user", user, "type", "user");
|
||||
}
|
||||
|
||||
#region Slots
|
||||
|
||||
/// <summary>
|
||||
/// The number of used slots on the earth
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public int UsedSlots {
|
||||
get {
|
||||
using Database database = new();
|
||||
return database.Slots.Count(s => s.CreatorId == this.UserId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of slots remaining on the earth
|
||||
/// </summary>
|
||||
public int FreeSlots => ServerSettings.EntitledSlots - this.UsedSlots;
|
||||
|
||||
private static readonly string[] slotTypes =
|
||||
{
|
||||
// "lbp1",
|
||||
"lbp2", "lbp3", "crossControl",
|
||||
};
|
||||
|
||||
private string SerializeSlots()
|
||||
{
|
||||
string slots = string.Empty;
|
||||
|
||||
slots += LbpSerializer.StringElement("lbp1UsedSlots", this.UsedSlots);
|
||||
slots += LbpSerializer.StringElement("entitledSlots", ServerSettings.EntitledSlots);
|
||||
slots += LbpSerializer.StringElement("freeSlots", this.FreeSlots);
|
||||
|
||||
foreach (string slotType in slotTypes)
|
||||
{
|
||||
slots += LbpSerializer.StringElement(slotType + "UsedSlots", this.UsedSlots);
|
||||
slots += LbpSerializer.StringElement(slotType + "EntitledSlots", ServerSettings.EntitledSlots);
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
slots += LbpSerializer.StringElement(slotType + slotType == "crossControl" ? "PurchsedSlots" : "PurchasedSlots", 0);
|
||||
slots += LbpSerializer.StringElement(slotType + "FreeSlots", this.FreeSlots);
|
||||
}
|
||||
return slots;
|
||||
|
||||
}
|
||||
|
||||
#endregion Slots
|
||||
|
||||
}
|
||||
}
|
64
README.md
64
README.md
|
@ -1,58 +1,84 @@
|
|||
# Project Lighthouse
|
||||
|
||||
Project Lighthouse is an umbrella project for all work to investigate and develop private servers for LittleBigPlanet.
|
||||
This project is the main server component that LittleBigPlanet games connect to.
|
||||
|
||||
## WARNING!
|
||||
This is beta software, and thus is not ready for public use yet.
|
||||
We're not responsible if someone connects and hacks your entire machine and deletes all your files.
|
||||
|
||||
This is beta software, and thus is not ready for public use yet. We're not responsible if someone connects and hacks
|
||||
your entire machine and deletes all your files.
|
||||
|
||||
That said, feel free to develop privately!
|
||||
|
||||
## Building
|
||||
|
||||
This will be written when we're out of beta. Consider this your barrier to entry ;).
|
||||
|
||||
## Running
|
||||
Lighthouse requires a MySQL database at this time.
|
||||
For Linux users running docker, one can be set up using the `docker-compose.yml` file in the root of the project folder.
|
||||
|
||||
Next, make sure the `LIGHTHOUSE_DB_CONNECTION_STRING` environment variable is set correctly.
|
||||
By default, it is `server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse`. If you are running the database via
|
||||
the above `docker-compose.yml` you shouldn't need to change this. For other development/especially production environments
|
||||
Lighthouse requires a MySQL database at this time. For Linux users running docker, one can be set up using
|
||||
the `docker-compose.yml` file in the root of the project folder.
|
||||
|
||||
Next, make sure the `LIGHTHOUSE_DB_CONNECTION_STRING` environment variable is set correctly. By default, it
|
||||
is `server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse`. If you are running the database via the
|
||||
above `docker-compose.yml` you shouldn't need to change this. For other development/especially production environments
|
||||
you will need to change this.
|
||||
|
||||
Once you've gotten MySQL running you can run Lighthouse. It will take care of the rest.
|
||||
|
||||
## Connecting
|
||||
PS3 is difficult to set up, so I will be going over how to set up RPCS3 instead. A guide will be coming for PS3 closer to release.
|
||||
You can also follow this guide if you want to learn how to modify your EBOOT.
|
||||
|
||||
*Note: This requires a modified copy of RPCS3. You can find a working patch [here](https://gist.github.com/jvyden/0d9619f7dd3dbc49f7583486bdacad75).*
|
||||
PS3 is difficult to set up, so I will be going over how to set up RPCS3 instead. A guide will be coming for PS3 closer
|
||||
to release. You can also follow this guide if you want to learn how to modify your EBOOT.
|
||||
|
||||
Start by getting a copy of LittleBigPlanet 2 installed. It can be digital (NPUA80662) or disc (BCUS98245).
|
||||
I won't get into how because if you got this far you should already know what you're doing. For those that don't, the [RPCS3 Quickstart Guide](https://rpcs3.net/quickstart) should cover it.
|
||||
*Note: This requires a modified copy of RPCS3. You can find a working
|
||||
patch [here](https://gist.github.com/jvyden/0d9619f7dd3dbc49f7583486bdacad75).*
|
||||
|
||||
Next, download [UnionPatcher](https://github.com/LBPUnion/UnionPatcher/). Binaries can be found by reading the README.md file.
|
||||
Start by getting a copy of LittleBigPlanet 2 installed. It can be digital (NPUA80662) or disc (BCUS98245). I won't get
|
||||
into how because if you got this far you should already know what you're doing. For those that don't,
|
||||
the [RPCS3 Quickstart Guide](https://rpcs3.net/quickstart) should cover it.
|
||||
|
||||
You should have everything you need now, so open up RPCS3 and go to Utilities -> Decrypt PS3 Binaries. Point this to `rpcs3/dev_hdd0/game/(title id)/USRDIR/EBOOT.BIN`.
|
||||
Next, download [UnionPatcher](https://github.com/LBPUnion/UnionPatcher/). Binaries can be found by reading the README.md
|
||||
file.
|
||||
|
||||
This should give you a file named `EBOOT.elf` in the same folder. Next, fire up UnionPatcher (making sure to select the correct project to start, e.g. on Mac launch `UnionPatcher.Gui.MacOS`.)
|
||||
You should have everything you need now, so open up RPCS3 and go to Utilities -> Decrypt PS3 Binaries. Point this
|
||||
to `rpcs3/dev_hdd0/game/(title id)/USRDIR/EBOOT.BIN`.
|
||||
|
||||
Now that you have your decrypted eboot, open UnionPatcher and select the `EBOOT.elf` you got earlier in the top box, enter `http://localhost:10060/LITTLEBIGPLANETPS3_XML` in the second, and the output filename in the third.
|
||||
For this guide I'll use `EBOOTlocalhost.elf`.
|
||||
This should give you a file named `EBOOT.elf` in the same folder. Next, fire up UnionPatcher (making sure to select the
|
||||
correct project to start, e.g. on Mac launch `UnionPatcher.Gui.MacOS`.)
|
||||
|
||||
Now that you have your decrypted eboot, open UnionPatcher and select the `EBOOT.elf` you got earlier in the top box,
|
||||
enter `http://localhost:10060/LITTLEBIGPLANETPS3_XML` in the second, and the output filename in the third. For this
|
||||
guide I'll use `EBOOTlocalhost.elf`.
|
||||
|
||||
Now, copy the `EBOOTlocalhost.elf` file to where you got your `EBOOT.elf` file from, and you're now good to go.
|
||||
|
||||
To launch the game with the patched EBOOT, open up RPCS3, go to File, Boot SELF/ELF, and open up `EBOOTlocalhost.elf`.
|
||||
|
||||
Assuming you are running the patched version of RPCS3, you patched the file correctly, the database is migrated, and Lighthouse is running, the game should now connect.
|
||||
Assuming you are running the patched version of RPCS3, you patched the file correctly, the database is migrated, and
|
||||
Lighthouse is running, the game should now connect.
|
||||
|
||||
Finally, take a break. Chances are that took a while.
|
||||
|
||||
## Contributing Tips
|
||||
|
||||
### Database
|
||||
|
||||
Some modifications may require updates to the database schema. You can automatically create a migration file by:
|
||||
|
||||
1. Making sure the tools are installed. You can do this by running `dotnet tool restore`.
|
||||
2. Making sure `LIGHTHOUSE_DB_CONNECTION_STRING` is set correctly. See the `Running` section for more details.
|
||||
3. Making your changes to the database. I won't cover this since if you're making database changes you should know what you're doing.
|
||||
3. Making your changes to the database. I won't cover this since if you're making database changes you should know what
|
||||
you're doing.
|
||||
4. Running `dotnet ef migrations add <NameOfMigrationInPascalCase> --project ProjectLighthouse`.
|
||||
|
||||
## Compatibility across games and platforms
|
||||
|
||||
| Game | Console (PS3/Vita) | Emulator (RPCS3) | Next-Gen (PS4/PS5) |
|
||||
|----------|------------------------|------------------------------------------------|--------------------|
|
||||
| LBP1 | Somewhat compatible | Incompatible, crashes on entering pod computer | N/A |
|
||||
| LBP2 | Compatible | Compatible with patched RPCS3 | N/A |
|
||||
| LBP3 | Somewhat compatible | Somewhat compatible with workaround | Incompatible |
|
||||
| LBP Vita | Potentially compatible | N/A | N/A |
|
||||
|
||||
Project Lighthouse is still a heavy work in progress, so this is subject to change at any point.
|
|
@ -14,6 +14,6 @@ services:
|
|||
- '3306' # Expose port to localhost:3306
|
||||
volumes:
|
||||
- lighthouse-db:/var/lib/mysql
|
||||
|
||||
|
||||
volumes:
|
||||
lighthouse-db:
|
Loading…
Add table
Add a link
Reference in a new issue