diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccaf4961..0248ba60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -on: [push] +on: [ push ] name: Continuous Integration # Inspired by osu! lazer's CI @@ -31,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: @@ -47,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" @@ -79,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: | diff --git a/.run/Development Database.run.xml b/.run/Development Database.run.xml index 12a3e5fe..deac13d8 100644 --- a/.run/Development Database.run.xml +++ b/.run/Development Database.run.xml @@ -1,11 +1,12 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/ProjectLighthouse.Tests/DatabaseFact.cs b/ProjectLighthouse.Tests/DatabaseFact.cs index 93e2b07d..7fdc1524 100644 --- a/ProjectLighthouse.Tests/DatabaseFact.cs +++ b/ProjectLighthouse.Tests/DatabaseFact.cs @@ -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(); } diff --git a/ProjectLighthouse.Tests/LighthouseTest.cs b/ProjectLighthouse.Tests/LighthouseTest.cs index bf705a2c..e3966fe1 100644 --- a/ProjectLighthouse.Tests/LighthouseTest.cs +++ b/ProjectLighthouse.Tests/LighthouseTest.cs @@ -8,29 +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()); - public LighthouseTest() { - this.Server = new TestServer(new WebHostBuilder() - .UseStartup()); - this.Client = this.Server.CreateClient(); } - public async Task AuthenticateResponse(int number = 0) { + public async Task AuthenticateResponse(int number = 0) + { const string username = "unitTestUser"; 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 Authenticate(int number = 0) { + + public async Task Authenticate(int number = 0) + { HttpResponseMessage response = await this.AuthenticateResponse(number); string responseContent = LbpSerializer.StringElement("loginResult", await response.Content.ReadAsStringAsync()); @@ -41,30 +45,31 @@ namespace LBPUnion.ProjectLighthouse.Tests { public Task AuthenticatedRequest(string endpoint, string mmAuth) => this.AuthenticatedRequest(endpoint, mmAuth, HttpMethod.Get); - public Task AuthenticatedRequest(string endpoint, string mmAuth, HttpMethod method) { - using var requestMessage = new HttpRequestMessage(method, endpoint); + public Task 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 UploadFileRequest(string endpoint, string filePath) { - return await this.Client.PostAsync(endpoint, new StringContent(await File.ReadAllTextAsync(filePath))); - } + public async Task UploadFileRequest(string endpoint, string filePath) + => await this.Client.PostAsync(endpoint, new StringContent(await File.ReadAllTextAsync(filePath))); - public async Task UploadDataRequest(string endpoint, byte[] data) { - return await this.Client.PostAsync(endpoint, new ByteArrayContent(data)); - } + public async Task UploadDataRequest(string endpoint, byte[] data) + => await this.Client.PostAsync(endpoint, new ByteArrayContent(data)); - public async Task AuthenticatedUploadFileRequest(string endpoint, string filePath, string mmAuth) { - using var requestMessage = new HttpRequestMessage(HttpMethod.Post, endpoint); + public async Task 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 AuthenticatedUploadDataRequest(string endpoint, byte[] data, string mmAuth) { - using var requestMessage = new HttpRequestMessage(HttpMethod.Post, endpoint); + public async Task 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); diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj index 67903271..99d6e9bc 100644 --- a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj @@ -13,9 +13,9 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -27,7 +27,7 @@ - + PreserveNewest diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs index ea51884b..87bdf599 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs @@ -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 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); diff --git a/ProjectLighthouse.Tests/Tests/DatabaseTests.cs b/ProjectLighthouse.Tests/Tests/DatabaseTests.cs index 1e2cf60e..90551c5d 100644 --- a/ProjectLighthouse.Tests/Tests/DatabaseTests.cs +++ b/ProjectLighthouse.Tests/Tests/DatabaseTests.cs @@ -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(); diff --git a/ProjectLighthouse.Tests/Tests/FileTypeTests.cs b/ProjectLighthouse.Tests/Tests/FileTypeTests.cs index 61960ebe..b7229aa2 100644 --- a/ProjectLighthouse.Tests/Tests/FileTypeTests.cs +++ b/ProjectLighthouse.Tests/Tests/FileTypeTests.cs @@ -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()); 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); } diff --git a/ProjectLighthouse.Tests/Tests/MatchTests.cs b/ProjectLighthouse.Tests/Tests/MatchTests.cs index d14b6250..5c52f9f5 100644 --- a/ProjectLighthouse.Tests/Tests/MatchTests.cs +++ b/ProjectLighthouse.Tests/Tests/MatchTests.cs @@ -6,12 +6,15 @@ 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 ShouldRejectEmptyData() { + public async Task ShouldRejectEmptyData() + { LoginResult loginResult = await this.Authenticate(); await semaphore.WaitAsync(); @@ -22,16 +25,13 @@ namespace LBPUnion.ProjectLighthouse.Tests { } [DatabaseFact] - public async Task ShouldReturnOk() { + 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 - ); - + HttpResponseMessage result = await this.AuthenticatedUploadDataRequest + ("LITTLEBIGPLANETPS3_XML/match", Encoding.ASCII.GetBytes("[UpdateMyPlayerData,[\"Player\":\"1984\"]]"), loginResult.AuthTicket); semaphore.Release(); Assert.True(result.IsSuccessStatusCode); @@ -39,23 +39,21 @@ namespace LBPUnion.ProjectLighthouse.Tests { public async Task 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", - Encoding.ASCII.GetBytes("[UpdateMyPlayerData,[\"Player\":\"1984\"]]"), - 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); } diff --git a/ProjectLighthouse.Tests/Tests/SerializerTests.cs b/ProjectLighthouse.Tests/Tests/SerializerTests.cs index 14c1f5c8..2c8af05e 100644 --- a/ProjectLighthouse.Tests/Tests/SerializerTests.cs +++ b/ProjectLighthouse.Tests/Tests/SerializerTests.cs @@ -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("", LbpSerializer.BlankElement("test")); } [Fact] - public void StringElementWorks() { + public void StringElementWorks() + { Assert.Equal("asd", LbpSerializer.StringElement("test", "asd")); Assert.Equal("asd", LbpSerializer.StringElement(new KeyValuePair("test", "asd"))); } [Fact] - public void TaggedStringElementWorks() { + public void TaggedStringElementWorks() + { Assert.Equal("asd", LbpSerializer.TaggedStringElement("test", "asd", "foo", "bar")); - Assert.Equal("asd", LbpSerializer.TaggedStringElement(new KeyValuePair("test", "asd"), - new KeyValuePair("foo", "bar"))); + Assert.Equal + ( + "asd", + LbpSerializer.TaggedStringElement(new KeyValuePair("test", "asd"), new KeyValuePair("foo", "bar")) + ); } [Fact] - public void ElementsWorks() { - Assert.Equal("asdbar", LbpSerializer.Elements(new KeyValuePair("test", "asd"), - new KeyValuePair("foo", "bar"))); + public void ElementsWorks() + { + Assert.Equal + ( + "asdbar", + LbpSerializer.Elements(new KeyValuePair("test", "asd"), new KeyValuePair("foo", "bar")) + ); } } } \ No newline at end of file diff --git a/ProjectLighthouse.Tests/Tests/SlotTests.cs b/ProjectLighthouse.Tests/Tests/SlotTests.cs index 3b136857..ae5a8b9b 100644 --- a/ProjectLighthouse.Tests/Tests/SlotTests.cs +++ b/ProjectLighthouse.Tests/Tests/SlotTests.cs @@ -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); diff --git a/ProjectLighthouse.Tests/Tests/UploadTests.cs b/ProjectLighthouse.Tests/Tests/UploadTests.cs index 30190fc3..41612256 100644 --- a/ProjectLighthouse.Tests/Tests/UploadTests.cs +++ b/ProjectLighthouse.Tests/Tests/UploadTests.cs @@ -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); } diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index dd04ad09..8b093e41 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -1,8 +1,80 @@  + HINT + HINT + SUGGESTION + WARNING + SUGGESTION + SUGGESTION + WARNING + ERROR + ExpressionBody + ExpressionBody + Field, Property, Event, Method + True + True + NEXT_LINE + NEXT_LINE + TOGETHER + True + USUAL_INDENT + USUAL_INDENT + NEXT_LINE + NEXT_LINE + 1 + 1 + False + False + False + False + False + False + False + 5 + 1 + EXPANDED + NEXT_LINE + NEVER + NEVER + NEVER + False + IF_OWNER_IS_SINGLE_LINE + False + False + True + True + True + True + True + True + True + NEXT_LINE + True + True + CHOP_IF_LONG + CHOP_IF_LONG + True + True + True + True + True + True + CHOP_IF_LONG + CHOP_IF_LONG + CHOP_IF_LONG + CHOP_ALWAYS + CHOP_IF_LONG + CHOP_ALWAYS + UseExplicitType + UseExplicitType + UseExplicitType MM <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + True + True + True + True True True True diff --git a/ProjectLighthouse/Controllers/ClientConfigurationController.cs b/ProjectLighthouse/Controllers/ClientConfigurationController.cs index 7e5aefce..acf08f0f 100644 --- a/ProjectLighthouse/Controllers/ClientConfigurationController.cs +++ b/ProjectLighthouse/Controllers/ClientConfigurationController.cs @@ -2,36 +2,38 @@ using System.Diagnostics.CodeAnalysis; using LBPUnion.ProjectLighthouse.Types.Settings; using Microsoft.AspNetCore.Mvc; -namespace LBPUnion.ProjectLighthouse.Controllers { +namespace LBPUnion.ProjectLighthouse.Controllers +{ [ApiController] [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/plain")] - public class ClientConfigurationController : ControllerBase { + public class ClientConfigurationController : ControllerBase + { [HttpGet("network_settings.nws")] [SuppressMessage("ReSharper", "StringLiteralTypo")] - public IActionResult NetworkSettings() { - 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"); - } + public IActionResult NetworkSettings() + => 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" + ); [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")] - public IActionResult PrivacySettings() { - PrivacySettings ps = new() { + public IActionResult PrivacySettings() + { + PrivacySettings ps = new() + { LevelVisibility = "all", ProfileVisibility = "all", }; - + return this.Ok(ps.Serialize()); } } diff --git a/ProjectLighthouse/Controllers/CommentController.cs b/ProjectLighthouse/Controllers/CommentController.cs index 524e601b..5d673e5e 100644 --- a/ProjectLighthouse/Controllers/CommentController.cs +++ b/ProjectLighthouse/Controllers/CommentController.cs @@ -10,20 +10,24 @@ 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 GetComments(string username) { - List comments = await this.database.Comments - .Include(c => c.Target) + public async Task GetComments(string username) + { + List comments = await this.database.Comments.Include + (c => c.Target) .Include(c => c.Poster) .Where(c => c.Target.Username == username) .OrderByDescending(c => c.Timestamp) @@ -34,7 +38,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers { } [HttpPost("postUserComment/{username}")] - public async Task PostComment(string username) { + public async Task PostComment(string username) + { this.Request.Body.Position = 0; string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); @@ -43,11 +48,11 @@ 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; @@ -60,15 +65,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers { } [HttpPost("deleteUserComment/{username}")] - public async Task DeleteComment([FromQuery] int commentId, string username) { + public async Task DeleteComment([FromQuery] int commentId, string username) + { User user = await this.database.UserFromRequest(this.Request); - if(user == null) return this.StatusCode(403, ""); + if (user == null) return this.StatusCode(403, ""); - Comment comment = await this.database.Comments - .FirstOrDefaultAsync(c => c.CommentId == commentId); + Comment comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId); - if(comment.TargetUserId != user.UserId && comment.PosterUserId != user.UserId) - return this.StatusCode(403, ""); + if (comment.TargetUserId != user.UserId && comment.PosterUserId != user.UserId) return this.StatusCode(403, ""); this.database.Comments.Remove(comment); await this.database.SaveChangesAsync(); diff --git a/ProjectLighthouse/Controllers/EnterLevelController.cs b/ProjectLighthouse/Controllers/EnterLevelController.cs index 88d3933f..4b6c5236 100644 --- a/ProjectLighthouse/Controllers/EnterLevelController.cs +++ b/ProjectLighthouse/Controllers/EnterLevelController.cs @@ -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(); } } \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/LevelTagsController.cs b/ProjectLighthouse/Controllers/LevelTagsController.cs index 1ed96dc6..1795a868 100644 --- a/ProjectLighthouse/Controllers/LevelTagsController.cs +++ b/ProjectLighthouse/Controllers/LevelTagsController.cs @@ -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++; } diff --git a/ProjectLighthouse/Controllers/ListController.cs b/ProjectLighthouse/Controllers/ListController.cs index ede363be..0b1deefb 100644 --- a/ProjectLighthouse/Controllers/ListController.cs +++ b/ProjectLighthouse/Controllers/ListController.cs @@ -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 queuedLevels = new Database().QueuedLevels - .Include(q => q.User) + public IActionResult GetLevelQueue(string username) + { + IEnumerable 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 AddQueuedLevel(int id) { + public async Task 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 RemoveQueuedLevel(int id) { + public async Task 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 heartedLevels = new Database().HeartedLevels - .Include(q => q.User) + public IActionResult GetFavouriteSlots(string username) + { + IEnumerable 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 AddFavouriteSlot(int id) { + public async Task 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 RemoveFavouriteSlot(int id) { + public async Task 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 heartedProfiles = new Database().HeartedProfiles - .Include(q => q.User) + public IActionResult GetFavouriteUsers(string username) + { + IEnumerable 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 AddFavouriteUser(string username) { + public async Task 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 RemoveFavouriteUser(string username) { + public async Task 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 + } } \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/LoginController.cs b/ProjectLighthouse/Controllers/LoginController.cs index 60f8b741..057771c2 100644 --- a/ProjectLighthouse/Controllers/LoginController.cs +++ b/ProjectLighthouse/Controllers/LoginController.cs @@ -5,39 +5,49 @@ using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Settings; using Microsoft.AspNetCore.Mvc; -namespace LBPUnion.ProjectLighthouse.Controllers { +namespace LBPUnion.ProjectLighthouse.Controllers +{ [ApiController] [Route("LITTLEBIGPLANETPS3_XML/login")] [Produces("text/xml")] - public class LoginController : ControllerBase { + public class LoginController : ControllerBase + { private readonly Database database; - public LoginController(Database database) { + public LoginController(Database database) + { this.database = database; } - + [HttpPost] - public async Task Login() { + public async Task Login() + { string body = await new StreamReader(this.Request.Body).ReadToEndAsync(); LoginData? loginData; - try { + try + { loginData = LoginData.CreateFromString(body); } - catch { + catch + { loginData = null; } - if(loginData == null) return this.BadRequest(); + if (loginData == null) return this.BadRequest(); Token? token = await this.database.AuthenticateUser(loginData); - if(token == null) return this.StatusCode(403, ""); + 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() + ); } } } \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/MatchController.cs b/ProjectLighthouse/Controllers/MatchController.cs index a5aec1cb..a4af9f5d 100644 --- a/ProjectLighthouse/Controllers/MatchController.cs +++ b/ProjectLighthouse/Controllers/MatchController.cs @@ -11,57 +11,69 @@ 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 MatchController : ControllerBase { + public class MatchController : ControllerBase + { private readonly Database database; - public MatchController(Database database) { + public MatchController(Database database) + { this.database = database; } [HttpPost("match")] [Produces("text/json")] - public async Task Match() { + public async Task Match() + { User? user = await this.database.UserFromRequest(this.Request); - if(user == null) return this.StatusCode(403, ""); + if (user == null) return this.StatusCode(403, ""); #region Parse match data + // Example POST /match: [UpdateMyPlayerData,["Player":"FireGamer9872"]] - + 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\":[]}]"); - } - - if(string.IsNullOrEmpty(bodyString) || bodyString[0] != '[') return this.BadRequest(); + 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\":[]}]" + ); + + if (string.IsNullOrEmpty(bodyString) || bodyString[0] != '[') return this.BadRequest(); IMatchData? matchData; - try { + try + { matchData = MatchHelper.Deserialize(bodyString); } - catch(Exception e) { + catch(Exception e) + { Logger.Log("Exception while parsing MatchData: " + e); Logger.Log("Data: " + bodyString); return this.BadRequest(); } - if(matchData == null) return this.BadRequest(); - + if (matchData == null) return this.BadRequest(); + #endregion #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 - if(lastMatch == null) { - lastMatch = new LastMatch { + if (lastMatch == null) + { + lastMatch = new LastMatch + { UserId = user.UserId, }; this.database.LastMatches.Add(lastMatch); @@ -70,8 +82,9 @@ namespace LBPUnion.ProjectLighthouse.Controllers { lastMatch.Timestamp = TimestampHelper.Timestamp; await this.database.SaveChangesAsync(); + #endregion - + return this.Ok("[{\"StatusCode\":200}]"); } } diff --git a/ProjectLighthouse/Controllers/MessageController.cs b/ProjectLighthouse/Controllers/MessageController.cs index a21b15f1..a96317eb 100644 --- a/ProjectLighthouse/Controllers/MessageController.cs +++ b/ProjectLighthouse/Controllers/MessageController.cs @@ -6,47 +6,52 @@ using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Types; using Microsoft.AspNetCore.Mvc; -namespace LBPUnion.ProjectLighthouse.Controllers { +namespace LBPUnion.ProjectLighthouse.Controllers +{ [ApiController] [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/plain")] - public class MessageController : ControllerBase { + public class MessageController : ControllerBase + { private readonly Database database; - public MessageController(Database database) { + public MessageController(Database database) + { this.database = database; } [HttpGet("eula")] - public async Task Eula() { + public async Task Eula() + { User user = await this.database.UserFromRequest(this.Request); return user == null ? 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"); + : 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 IActionResult Announce() { - return this.Ok(""); - } + public IActionResult Announce() => this.Ok(""); [HttpGet("notification")] - public IActionResult Notification() { - return this.Ok(); - } + public IActionResult Notification() => this.Ok(); /// - /// Filters chat messages sent by a user. - /// The reponse sent is the text that will appear in-game. + /// Filters chat messages sent by a user. + /// The reponse sent is the text that will appear in-game. /// [HttpPost("filter")] - public async Task Filter() { + public async Task Filter() + { User user = await this.database.UserFromRequest(this.Request); - if(user == null) return this.StatusCode(403, ""); - + 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); } diff --git a/ProjectLighthouse/Controllers/NewsController.cs b/ProjectLighthouse/Controllers/NewsController.cs index 5fa6e8f3..ee0342d2 100644 --- a/ProjectLighthouse/Controllers/NewsController.cs +++ b/ProjectLighthouse/Controllers/NewsController.cs @@ -2,26 +2,35 @@ using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types.News; using Microsoft.AspNetCore.Mvc; -namespace LBPUnion.ProjectLighthouse.Controllers { +namespace LBPUnion.ProjectLighthouse.Controllers +{ [ApiController] [Route("LITTLEBIGPLANETPS3_XML/news")] [Produces("text/xml")] - public class NewsController : ControllerBase { + public class NewsController : ControllerBase + { [HttpGet] - public IActionResult Get() { - string newsEntry = LbpSerializer.StringElement("item", new NewsEntry { - Category = "no_category", - Summary = "test summary", - Image = new NewsImage { - Hash = "4947269c5f7061b27225611ee58a9a91a8031bbe", - Alignment = "right", - }, - Id = 1, - Title = "Test Title", - Text = "Test Text", - Date = 1348755214000, - }.Serialize()); - + public IActionResult Get() + { + string newsEntry = LbpSerializer.StringElement + ( + "item", + new NewsEntry + { + 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)); } } diff --git a/ProjectLighthouse/Controllers/PublishController.cs b/ProjectLighthouse/Controllers/PublishController.cs index 5a90bbd3..4efb4176 100644 --- a/ProjectLighthouse/Controllers/PublishController.cs +++ b/ProjectLighthouse/Controllers/PublishController.cs @@ -10,60 +10,64 @@ 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; } /// - /// Endpoint the game uses to check what resources need to be uploaded and if the level can be uploaded + /// Endpoint the game uses to check what resources need to be uploaded and if the level can be uploaded /// [HttpPost("startPublish")] - public async Task StartPublish() { + public async Task StartPublish() + { 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(); - if(slot == null) return this.BadRequest(); // if the level cant be parsed then it obviously cant be uploaded + if (slot == null) return this.BadRequest(); // if the level cant be parsed then it obviously cant be uploaded // Republish logic - if(slot.SlotId != 0) { + 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(); + 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)); + 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")); } /// - /// Endpoint actually used to publish a level + /// Endpoint actually used to publish a level /// [HttpPost("publish")] - public async Task Publish() { + public async Task 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(); + 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; @@ -73,14 +77,15 @@ namespace LBPUnion.ProjectLighthouse.Controllers { 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() { + Location l = new() + { X = slot.Location.X, Y = slot.Location.Y, }; @@ -93,15 +98,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers { this.database.Slots.Add(slot); await this.database.SaveChangesAsync(); - + return this.Ok(slot.Serialize()); } [HttpPost("unpublish/{id:int}")] - public async Task Unpublish(int id) { - Slot slot = await this.database.Slots - .Include(s => s.Location) - .FirstOrDefaultAsync(s => s.SlotId == id); + public async Task 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); @@ -110,8 +114,9 @@ namespace LBPUnion.ProjectLighthouse.Controllers { return this.Ok(); } - - public async Task GetSlotFromBody() { + + public async Task GetSlotFromBody() + { this.Request.Body.Position = 0; string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); diff --git a/ProjectLighthouse/Controllers/ResourcesController.cs b/ProjectLighthouse/Controllers/ResourcesController.cs index 7b80c591..dcb1a4d8 100644 --- a/ProjectLighthouse/Controllers/ResourcesController.cs +++ b/ProjectLighthouse/Controllers/ResourcesController.cs @@ -10,60 +10,61 @@ using LBPUnion.ProjectLighthouse.Types.Files; using Microsoft.AspNetCore.Mvc; using IOFile = System.IO.File; -namespace LBPUnion.ProjectLighthouse.Controllers { +namespace LBPUnion.ProjectLighthouse.Controllers +{ [ApiController] [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/xml")] - public class ResourcesController : ControllerBase { + 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")] - public async Task FilterResources() { - string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); - + public async Task FilterResources() + { + string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); + XmlSerializer serializer = new(typeof(ResourceList)); ResourceList resourceList = (ResourceList)serializer.Deserialize(new StringReader(bodyString)); - if(resourceList == null) return this.BadRequest(); + 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)); } [HttpGet("r/{hash}")] - public IActionResult GetResource(string hash) { + public IActionResult GetResource(string hash) + { 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(); } // TODO: check if this is a valid hash [HttpPost("upload/{hash}")] [AllowSynchronousIo] - public async Task UploadResource(string hash) { + public async Task UploadResource(string hash) + { string assetsDirectory = FileHelper.ResourcePath; string path = FileHelper.GetResourcePath(hash); - + FileHelper.EnsureDirectoryCreated(assetsDirectory); - if(FileHelper.ResourceExists(hash)) this.Ok(); // no reason to fail if it's already uploaded + 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(); - if(!FileHelper.IsFileSafe(file)) return this.UnprocessableEntity(); - await IOFile.WriteAllBytesAsync(path, file.Data); return this.Ok(); } diff --git a/ProjectLighthouse/Controllers/SearchController.cs b/ProjectLighthouse/Controllers/SearchController.cs index 823a89cf..573d3480 100644 --- a/ProjectLighthouse/Controllers/SearchController.cs +++ b/ProjectLighthouse/Controllers/SearchController.cs @@ -6,19 +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 SearchSlots([FromQuery] string query) { - if(query == null) return this.BadRequest(); + public async Task SearchSlots([FromQuery] string query) + { + if (query == null) return this.BadRequest(); + query = query.ToLower(); string[] keywords = query.Split(" "); @@ -27,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 slots = await dbQuery.ToListAsync(); string response = slots.Aggregate("", (current, slot) => current + slot.Serialize()); diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs index d4733dbd..ede1ae56 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -6,44 +6,47 @@ 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)); } [HttpGet("s/user/{id:int}")] - public async Task SUser(int id) { - Slot slot = await this.database.Slots - .Include(s => s.Creator) - .Include(s => s.Location) - .FirstOrDefaultAsync(s => s.SlotId == id); + public async Task 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(); + if (slot == null) return this.NotFound(); return this.Ok(slot.Serialize()); } [HttpGet("slots")] - public IActionResult NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize) { - IQueryable slots = this.database.Slots - .Include(s => s.Creator) + public IActionResult NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize) + { + IQueryable slots = this.database.Slots.Include + (s => s.Creator) .Include(s => s.Location) .OrderByDescending(s => s.FirstUploaded) .Skip(pageStart - 1) diff --git a/ProjectLighthouse/Controllers/StatisticsController.cs b/ProjectLighthouse/Controllers/StatisticsController.cs index d71a9222..0bacbd4a 100644 --- a/ProjectLighthouse/Controllers/StatisticsController.cs +++ b/ProjectLighthouse/Controllers/StatisticsController.cs @@ -5,35 +5,39 @@ using LBPUnion.ProjectLighthouse.Serialization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -namespace LBPUnion.ProjectLighthouse.Controllers { +namespace LBPUnion.ProjectLighthouse.Controllers +{ [ApiController] [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/plain")] - public class StatisticsController : ControllerBase { + public class StatisticsController : ControllerBase + { private readonly Database database; - public StatisticsController(Database database) { + public StatisticsController(Database database) + { this.database = database; } [HttpGet("playersInPodCount")] [HttpGet("totalPlayerCount")] - public async Task TotalPlayerCount() { - int recentMatches = await this.database.LastMatches - .Where(l => TimestampHelper.Timestamp - l.Timestamp < 60) - .CountAsync(); + public async Task 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 PlanetStats() { + public async Task 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) - )); + return this.Ok + ( + LbpSerializer.StringElement + ("planetStats", LbpSerializer.StringElement("totalSlotCount", totalSlotCount) + LbpSerializer.StringElement("mmPicksCount", mmPicksCount)) + ); } } } \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/UserController.cs b/ProjectLighthouse/Controllers/UserController.cs index d3cc5794..1938f6cd 100644 --- a/ProjectLighthouse/Controllers/UserController.cs +++ b/ProjectLighthouse/Controllers/UserController.cs @@ -8,44 +8,41 @@ 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 UserController : ControllerBase { + public class UserController : ControllerBase + { private readonly Database database; - public UserController(Database database) { + public UserController(Database database) + { this.database = database; } [HttpGet("user/{username}")] - public async Task GetUser(string username) { - User user = await this.database.Users - .Include(u => u.Location) - .FirstOrDefaultAsync(u => u.Username == username); + public async Task GetUser(string username) + { + User user = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.Username == username); + + if (user == null) return this.NotFound(); - if(user == null) return this.NotFound(); return this.Ok(user.Serialize()); } [HttpGet("users")] - public async Task GetUserAlt([FromQuery] string u) { - return await GetUser(u); - } - -// [HttpPost("user/{username}")] -// public async Task CreateUser(string username) { -// await new Database().CreateUser(username); -// return await GetUser(username); -// } + public async Task GetUserAlt([FromQuery] string u) => await this.GetUser(u); [HttpPost("updateUser")] - public async Task UpdateUser() { + public async Task UpdateUser() + { User user = await this.database.UserFromRequest(this.Request); - if(user == null) return this.StatusCode(403, ""); + if (user == null) return this.StatusCode(403, ""); - XmlReaderSettings settings = new() { + XmlReaderSettings settings = new() + { Async = true, // this is apparently not default }; @@ -67,35 +64,40 @@ 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)) { + using (XmlReader reader = XmlReader.Create(this.Request.Body, settings)) + { List path = new(); // you can think of this as a file path in the XML, like -> -> - while(await reader.ReadAsync()) { - // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault - switch(reader.NodeType) { + while (await reader.ReadAsync()) // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault + switch (reader.NodeType) + { case XmlNodeType.Element: path.Add(reader.Name); break; case XmlNodeType.Text: - switch(path[1]) { - case "biography": { + switch (path[1]) + { + case "biography": + { user.Biography = await reader.GetValueAsync(); break; } - case "location": { + case "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()); - } + 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()); break; } - case "icon": { + case "icon": + { user.IconHash = await reader.GetValueAsync(); break; } - case "planets": { + case "planets": + { user.PlanetHash = await reader.GetValueAsync(); break; } @@ -105,21 +107,21 @@ 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 + 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 // set the location in the database to the one we modified above l.X = user.Location.X; l.Y = user.Location.Y; - + // 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(); } } diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index 4dd23287..c80e6c50 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -8,8 +8,10 @@ using LBPUnion.ProjectLighthouse.Types.Settings; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; -namespace LBPUnion.ProjectLighthouse { - public class Database : DbContext { +namespace LBPUnion.ProjectLighthouse +{ + public class Database : DbContext + { public DbSet Users { get; set; } public DbSet Locations { get; set; } public DbSet Slots { get; set; } @@ -21,21 +23,20 @@ namespace LBPUnion.ProjectLighthouse { public DbSet 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 CreateUser(string username) { + public async Task 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 await this.SaveChangesAsync(); // saving to the database returns the id and sets it on this entity - user = new User { + user = new User + { Username = username, LocationId = l.Id, Biography = username + " hasn't introduced themselves yet.", @@ -46,14 +47,15 @@ namespace LBPUnion.ProjectLighthouse { return user; } - - #nullable enable - public async Task 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); - Token token = new() { + #nullable enable + public async Task 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); + + Token token = new() + { UserToken = HashHelper.GenerateAuthToken(), UserId = user.UserId, }; @@ -64,19 +66,18 @@ namespace LBPUnion.ProjectLighthouse { return token; } - public async Task UserFromAuthToken(string authToken) { + public async Task UserFromAuthToken(string authToken) + { 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); + if (token == null) return null; + + return await this.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == token.UserId); } - public async Task UserFromRequest(HttpRequest request) { - if(!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) { - return null; - } - + public async Task UserFromRequest(HttpRequest request) + { + if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null; + return await this.UserFromAuthToken(mmAuth); } #nullable disable diff --git a/ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs b/ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs index 8cf82612..1054f1a7 100644 --- a/ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs +++ b/ProjectLighthouse/Helpers/AllowSynchronousIOAttribute.cs @@ -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! /// - /// Allows synchronous stream operations for this request. + /// Allows synchronous stream operations for this request. /// [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(); - if(syncIoFeature != null) syncIoFeature.AllowSynchronousIO = true; + if (syncIoFeature != null) syncIoFeature.AllowSynchronousIO = true; } } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/BinaryHelper.cs b/ProjectLighthouse/Helpers/BinaryHelper.cs index 80d0b1cf..3765ef46 100644 --- a/ProjectLighthouse/Helpers/BinaryHelper.cs +++ b/ProjectLighthouse/Helpers/BinaryHelper.cs @@ -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 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(); - + if (reader.BaseStream.Length < count) return Array.Empty(); + 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 ReadFromPipeReader(PipeReader reader) { + public static async Task ReadFromPipeReader(PipeReader reader) + { List data = new(); - while(true) { + while (true) + { ReadResult readResult = await reader.ReadAsync(); ReadOnlySequence 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(); diff --git a/ProjectLighthouse/Helpers/EulaHelper.cs b/ProjectLighthouse/Helpers/EulaHelper.cs index 25c531ba..cfaa3940 100644 --- a/ProjectLighthouse/Helpers/EulaHelper.cs +++ b/ProjectLighthouse/Helpers/EulaHelper.cs @@ -1,5 +1,7 @@ -namespace LBPUnion.ProjectLighthouse.Helpers { - public static class EulaHelper { +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 diff --git a/ProjectLighthouse/Helpers/Extensions/ExceptionExtensions.cs b/ProjectLighthouse/Helpers/Extensions/ExceptionExtensions.cs index 0ea759a3..5a119dbc 100644 --- a/ProjectLighthouse/Helpers/Extensions/ExceptionExtensions.cs +++ b/ProjectLighthouse/Helpers/Extensions/ExceptionExtensions.cs @@ -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 fields = properties - .Select(property => new { - property.Name, - Value = property.GetValue(exception, null), - }) + + IEnumerable 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); diff --git a/ProjectLighthouse/Helpers/FileHelper.cs b/ProjectLighthouse/Helpers/FileHelper.cs index 8bd60898..fbb23117 100644 --- a/ProjectLighthouse/Helpers/FileHelper.cs +++ b/ProjectLighthouse/Helpers/FileHelper.cs @@ -4,16 +4,20 @@ 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, @@ -30,16 +34,18 @@ 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, @@ -52,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(); diff --git a/ProjectLighthouse/Helpers/HashHelper.cs b/ProjectLighthouse/Helpers/HashHelper.cs index b2ea531e..6cf17969 100644 --- a/ProjectLighthouse/Helpers/HashHelper.cs +++ b/ProjectLighthouse/Helpers/HashHelper.cs @@ -4,32 +4,22 @@ using System.Diagnostics.CodeAnalysis; using System.Security.Cryptography; using System.Text; -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 - /// - /// Generates a specified amount of random bytes in an array. + /// Generates a specified amount of random bytes in an array. /// /// The amount of bytes to generate. /// The bytes generated - public static IEnumerable GenerateRandomBytes(int count) { + public static IEnumerable GenerateRandomBytes(int count) + { byte[] b = new byte[count]; random.NextBytes(b); @@ -37,13 +27,31 @@ namespace LBPUnion.ProjectLighthouse.Helpers { } /// - /// Generates a random SHA256 & BCrypted token + /// Generates a random SHA256 & BCrypted token /// /// The token as a string. - public static string GenerateAuthToken() { - byte[] bytes = (byte[]) GenerateRandomBytes(256); + public static string GenerateAuthToken() + { + byte[] bytes = (byte[])GenerateRandomBytes(256); return BCryptHash(Sha256Hash(bytes)); } + + #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 + } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/MatchHelper.cs b/ProjectLighthouse/Helpers/MatchHelper.cs index 22d34ad0..e7e66895 100644 --- a/ProjectLighthouse/Helpers/MatchHelper.cs +++ b/ProjectLighthouse/Helpers/MatchHelper.cs @@ -3,14 +3,18 @@ using System.Linq; using System.Text.Json; using LBPUnion.ProjectLighthouse.Types.Match; -namespace LBPUnion.ProjectLighthouse.Helpers { - public static class MatchHelper { - public static IMatchData? Deserialize(string data) { +namespace LBPUnion.ProjectLighthouse.Helpers +{ + public static class MatchHelper + { + public static IMatchData? Deserialize(string data) + { string matchType = ""; int i = 1; - while(true) { - if(data[i] == ',') break; + while (true) + { + if (data[i] == ',') break; matchType += data[i]; i++; @@ -21,8 +25,10 @@ namespace LBPUnion.ProjectLighthouse.Helpers { return Deserialize(matchType, matchData); } - public static IMatchData? Deserialize(string matchType, string matchData) { - return matchType switch { + public static IMatchData? Deserialize(string matchType, string matchData) + { + return matchType switch + { "UpdateMyPlayerData" => JsonSerializer.Deserialize(matchData), "UpdatePlayersInRoom" => JsonSerializer.Deserialize(matchData), _ => null, diff --git a/ProjectLighthouse/Helpers/TimeHelper.cs b/ProjectLighthouse/Helpers/TimeHelper.cs index 9f51452a..77d8757d 100644 --- a/ProjectLighthouse/Helpers/TimeHelper.cs +++ b/ProjectLighthouse/Helpers/TimeHelper.cs @@ -1,7 +1,9 @@ using System; -namespace LBPUnion.ProjectLighthouse.Helpers { - public static class TimeHelper { +namespace LBPUnion.ProjectLighthouse.Helpers +{ + public static class TimeHelper + { public static long UnixTimeMilliseconds() => DateTimeOffset.Now.ToUnixTimeMilliseconds(); public static long UnixTimeSeconds() => DateTimeOffset.Now.ToUnixTimeSeconds(); } diff --git a/ProjectLighthouse/Helpers/TimestampHelper.cs b/ProjectLighthouse/Helpers/TimestampHelper.cs index 62ac5d60..3a3e9d48 100644 --- a/ProjectLighthouse/Helpers/TimestampHelper.cs +++ b/ProjectLighthouse/Helpers/TimestampHelper.cs @@ -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; } } \ No newline at end of file diff --git a/ProjectLighthouse/Logging/AspNetToKettuLogger.cs b/ProjectLighthouse/Logging/AspNetToKettuLogger.cs index f1af4bb7..b20ce5a7 100644 --- a/ProjectLighthouse/Logging/AspNetToKettuLogger.cs +++ b/ProjectLighthouse/Logging/AspNetToKettuLogger.cs @@ -3,22 +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 state) { - return NullScope.Instance; - } + public IDisposable BeginScope(TState state) => NullScope.Instance; public bool IsEnabled(LogLevel logLevel) => true; - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func 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); } } } \ No newline at end of file diff --git a/ProjectLighthouse/Logging/AspNetToKettuLoggerProvider.cs b/ProjectLighthouse/Logging/AspNetToKettuLoggerProvider.cs index 557b4462..84039bfe 100644 --- a/ProjectLighthouse/Logging/AspNetToKettuLoggerProvider.cs +++ b/ProjectLighthouse/Logging/AspNetToKettuLoggerProvider.cs @@ -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(); } } \ No newline at end of file diff --git a/ProjectLighthouse/Logging/LighthouseFileLogger.cs b/ProjectLighthouse/Logging/LighthouseFileLogger.cs index 88f7a4f2..1075dd0f 100644 --- a/ProjectLighthouse/Logging/LighthouseFileLogger.cs +++ b/ProjectLighthouse/Logging/LighthouseFileLogger.cs @@ -3,11 +3,14 @@ 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) { + + public override void Send(LoggerLine line) + { FileHelper.EnsureDirectoryCreated(logsDirectory); string channel = string.IsNullOrEmpty(line.LoggerLevel.Channel) ? "" : $"[{line.LoggerLevel.Channel}] "; diff --git a/ProjectLighthouse/Logging/LoggerLevels.cs b/ProjectLighthouse/Logging/LoggerLevels.cs index 7ddb690c..b033f58b 100644 --- a/ProjectLighthouse/Logging/LoggerLevels.cs +++ b/ProjectLighthouse/Logging/LoggerLevels.cs @@ -1,32 +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"; } - - public class LoggerLevelFilter : LoggerLevel { - public override string Name => "Filter"; - public static readonly LoggerLevelFilter Instance = new(); - } - public class LoggerLevelAspNet : LoggerLevel { - public override string Name => "AspNet"; - - public LoggerLevelAspNet(LogLevel level) { + public class LoggerLevelFilter : LoggerLevel + { + public static readonly LoggerLevelFilter Instance = new(); + public override string Name => "Filter"; + } + + public class LoggerLevelAspNet : LoggerLevel + { + + public LoggerLevelAspNet(LogLevel level) + { this.Channel = level.ToString(); } + public override string Name => "AspNet"; } } \ No newline at end of file diff --git a/ProjectLighthouse/Logging/NullScope.cs b/ProjectLighthouse/Logging/NullScope.cs index 3152fea5..5d790f78 100644 --- a/ProjectLighthouse/Logging/NullScope.cs +++ b/ProjectLighthouse/Logging/NullScope.cs @@ -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); } } diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index a74ebed2..804f9c94 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -14,31 +14,33 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace LBPUnion.ProjectLighthouse { - public static class Program { - public static void Main(string[] args) { +namespace LBPUnion.ProjectLighthouse +{ + public static class Program + { + public static void Main(string[] args) + { // Log startup time Stopwatch stopwatch = new(); stopwatch.Start(); - + // Setup logging - + Logger.StartLogging(); LoggerLine.LogFormat = "[{0}] {1}"; Logger.AddLogger(new ConsoleLogger()); Logger.AddLogger(new LighthouseFileLogger()); - + 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); - if(!dbConnected) Environment.Exit(1); + if (!dbConnected) Environment.Exit(1); using Database database = new(); Logger.Log("Migrating database...", LoggerLevelDatabase.Instance); MigrateDatabase(database); - Logger.Log("Fixing broken timestamps...", LoggerLevelDatabase.Instance); FixTimestamps(database); @@ -49,46 +51,50 @@ namespace LBPUnion.ProjectLighthouse { CreateHostBuilder(args).Build().Run(); } - public static void MigrateDatabase(Database database) { + 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) { + 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 (Slot slot in database.Slots.Where(s => s.FirstUploaded == 0)) slot.FirstUploaded = TimeHelper.UnixTimeMilliseconds(); - foreach(Comment comment in database.Comments.Where(c => c.Timestamp == 0)) { - comment.Timestamp = 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(); - }) - .ConfigureLogging(logging => { - logging.ClearProviders(); - logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); - }); + public static IHostBuilder CreateHostBuilder(string[] args) + => Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults + ( + webBuilder => + { + webBuilder.UseStartup(); + } + ) + .ConfigureLogging + ( + logging => + { + logging.ClearProviders(); + logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); + } + ); } } \ No newline at end of file diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 35309169..3a7ade23 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -8,23 +8,23 @@ - - - - + + + + - all - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + diff --git a/ProjectLighthouse/Serialization/LbpSerializer.cs b/ProjectLighthouse/Serialization/LbpSerializer.cs index e7946c02..1d2cfdaf 100644 --- a/ProjectLighthouse/Serialization/LbpSerializer.cs +++ b/ProjectLighthouse/Serialization/LbpSerializer.cs @@ -2,26 +2,30 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -namespace LBPUnion.ProjectLighthouse.Serialization { +namespace LBPUnion.ProjectLighthouse.Serialization +{ /// - /// 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. /// [SuppressMessage("ReSharper", "UnusedMember.Global")] - public static class LbpSerializer { + public static class LbpSerializer + { public static string BlankElement(string key) => $"<{key}>"; public static string StringElement(KeyValuePair pair) => $"<{pair.Key}>{pair.Value}"; public static string StringElement(string key, object value) => $"<{key}>{value}"; - - public static string TaggedStringElement(KeyValuePair pair, KeyValuePair tagPair) => - $"<{pair.Key} {tagPair.Key}=\"{tagPair.Value}\">{pair.Value}"; - - public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => - $"<{key} {tagKey}=\"{tagValue}\">{value}"; - public static string Elements(params KeyValuePair[] pairs) => - pairs.Aggregate(string.Empty, (current, pair) => current + StringElement(pair)); + public static string TaggedStringElement + (KeyValuePair pair, KeyValuePair tagPair) + => $"<{pair.Key} {tagPair.Key}=\"{tagPair.Value}\">{pair.Value}"; + + public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}"; + + public static string Elements + (params KeyValuePair[] pairs) + => pairs.Aggregate(string.Empty, (current, pair) => current + StringElement(pair)); } } \ No newline at end of file diff --git a/ProjectLighthouse/Serialization/XmlOutputFormatter.cs b/ProjectLighthouse/Serialization/XmlOutputFormatter.cs index da7c25ae..6103f8cd 100644 --- a/ProjectLighthouse/Serialization/XmlOutputFormatter.cs +++ b/ProjectLighthouse/Serialization/XmlOutputFormatter.cs @@ -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"); } diff --git a/ProjectLighthouse/Startup.cs b/ProjectLighthouse/Startup.cs index d83ff302..bd3b2640 100644 --- a/ProjectLighthouse/Startup.cs +++ b/ProjectLighthouse/Startup.cs @@ -10,57 +10,69 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace LBPUnion.ProjectLighthouse { - public class Startup { - public Startup(IConfiguration configuration) { +namespace LBPUnion.ProjectLighthouse +{ + public class Startup + { + public Startup(IConfiguration configuration) + { this.Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) { + 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(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - if(env.IsDevelopment()) { - app.UseDeveloperExceptionPage(); - } + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + 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(); - - context.Request.EnableBuffering(); // Allows us to reset the position of Request.Body for later logging - await next(); // Handle the request so we can get the status code from it - - 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.Use + ( + async (context, next) => + { + Stopwatch requestStopwatch = new(); + requestStopwatch.Start(); + + context.Request.EnableBuffering(); // Allows us to reset the position of Request.Body for later logging + await next(); // Handle the request so we can get the status code from it + + 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(); - app.UseEndpoints(endpoints => { - endpoints.MapControllers(); - }); + app.UseEndpoints + ( + endpoints => + { + endpoints.MapControllers(); + } + ); } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Files/LbpFile.cs b/ProjectLighthouse/Types/Files/LbpFile.cs index 70ad51da..b226276c 100644 --- a/ProjectLighthouse/Types/Files/LbpFile.cs +++ b/ProjectLighthouse/Types/Files/LbpFile.cs @@ -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); - } - - /// - /// The type of file. - /// - public LbpFileType FileType; +namespace LBPUnion.ProjectLighthouse.Types.Files +{ + public class LbpFile + { /// - /// A buffer of the file's data. + /// A buffer of the file's data. /// public readonly byte[] Data; + /// + /// The type of file. + /// + public LbpFileType FileType; + + public LbpFile(byte[] data) + { + this.Data = data; + this.FileType = FileHelper.DetermineFileType(this.Data); + } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Files/LbpFileType.cs b/ProjectLighthouse/Types/Files/LbpFileType.cs index 9c01d4ed..871aac91 100644 --- a/ProjectLighthouse/Types/Files/LbpFileType.cs +++ b/ProjectLighthouse/Types/Files/LbpFileType.cs @@ -1,5 +1,7 @@ -namespace LBPUnion.ProjectLighthouse.Types.Files { - public enum LbpFileType { +namespace LBPUnion.ProjectLighthouse.Types.Files +{ + public enum LbpFileType + { Script, // .ff, FSH Texture, // TEX Level, // LVL diff --git a/ProjectLighthouse/Types/HeartedProfile.cs b/ProjectLighthouse/Types/HeartedProfile.cs index 6d2908f0..bf4ebea5 100644 --- a/ProjectLighthouse/Types/HeartedProfile.cs +++ b/ProjectLighthouse/Types/HeartedProfile.cs @@ -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; } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Levels/HeartedLevel.cs b/ProjectLighthouse/Types/Levels/HeartedLevel.cs index 40c55dea..72b9855b 100644 --- a/ProjectLighthouse/Types/Levels/HeartedLevel.cs +++ b/ProjectLighthouse/Types/Levels/HeartedLevel.cs @@ -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; } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Levels/LevelTags.cs b/ProjectLighthouse/Types/Levels/LevelTags.cs index 3bb2a212..784985e4 100644 --- a/ProjectLighthouse/Types/Levels/LevelTags.cs +++ b/ProjectLighthouse/Types/Levels/LevelTags.cs @@ -1,12 +1,14 @@ using System.Diagnostics.CodeAnalysis; -namespace LBPUnion.ProjectLighthouse.Types.Levels { +namespace LBPUnion.ProjectLighthouse.Types.Levels +{ /// - /// A series of tags that can be applied to a level + /// A series of tags that can be applied to a level /// [SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "UnusedMember.Global")] - public enum LevelTags { + public enum LevelTags + { Brilliant, Beautiful, Funky, diff --git a/ProjectLighthouse/Types/Levels/QueuedLevel.cs b/ProjectLighthouse/Types/Levels/QueuedLevel.cs index 484f0c36..e238627e 100644 --- a/ProjectLighthouse/Types/Levels/QueuedLevel.cs +++ b/ProjectLighthouse/Types/Levels/QueuedLevel.cs @@ -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))] diff --git a/ProjectLighthouse/Types/Levels/Slot.cs b/ProjectLighthouse/Types/Levels/Slot.cs index c35faa28..79b9d2fe 100644 --- a/ProjectLighthouse/Types/Levels/Slot.cs +++ b/ProjectLighthouse/Types/Levels/Slot.cs @@ -5,12 +5,15 @@ using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types.Profiles; -namespace LBPUnion.ProjectLighthouse.Types.Levels { +namespace LBPUnion.ProjectLighthouse.Types.Levels +{ /// - /// A LittleBigPlanet level. + /// A LittleBigPlanet level. /// - [XmlRoot("slot"), XmlType("slot")] - public class Slot { + [XmlRoot("slot")] + [XmlType("slot")] + public class Slot + { [XmlAttribute("type")] [NotMapped] public string Type { get; set; } @@ -19,87 +22,86 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels { [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; } /// - /// The location of the level on the creator's earth + /// The location of the level on the creator's earth /// [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; } - + [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 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) + @@ -120,7 +122,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels { LbpSerializer.StringElement("firstPublished", this.FirstUploaded) + LbpSerializer.StringElement("lastUpdated", this.LastUpdated) + LbpSerializer.StringElement("mmpick", this.MMPick); - + return LbpSerializer.TaggedStringElement("slot", slotData, "type", "user"); } } diff --git a/ProjectLighthouse/Types/LoginData.cs b/ProjectLighthouse/Types/LoginData.cs index 6a51d2b1..5fcde0f1 100644 --- a/ProjectLighthouse/Types/LoginData.cs +++ b/ProjectLighthouse/Types/LoginData.cs @@ -4,29 +4,39 @@ using System.IO; using System.Text; using LBPUnion.ProjectLighthouse.Helpers; -namespace LBPUnion.ProjectLighthouse.Types { +namespace LBPUnion.ProjectLighthouse.Types +{ /// - /// The data sent from POST /LOGIN. + /// The data sent from POST /LOGIN. /// - public class LoginData { + public class LoginData + { + + public static readonly string UsernamePrefix = Encoding.ASCII.GetString + ( + new byte[] + { + 0x04, 0x00, 0x20, + } + ); + public string Username { get; set; } = null!; - public static readonly string UsernamePrefix = Encoding.ASCII.GetString(new byte[] { 0x04, 0x00, 0x20 }); - /// - /// Converts a X-I-5 Ticket into `LoginData`. - /// https://www.psdevwiki.com/ps3/X-I-5-Ticket - /// - public static LoginData? CreateFromString(string str) { + /// Converts a X-I-5 Ticket into `LoginData`. + /// https://www.psdevwiki.com/ps3/X-I-5-Ticket + /// + 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; + if (!str.Contains(UsernamePrefix)) return null; LoginData loginData = new(); - + reader.BaseStream.Position = str.IndexOf(UsernamePrefix, StringComparison.Ordinal) + UsernamePrefix.Length; loginData.Username = BinaryHelper.ReadString(reader).Replace("\0", string.Empty); diff --git a/ProjectLighthouse/Types/LoginResult.cs b/ProjectLighthouse/Types/LoginResult.cs index c0ed0997..bafb2416 100644 --- a/ProjectLighthouse/Types/LoginResult.cs +++ b/ProjectLighthouse/Types/LoginResult.cs @@ -2,23 +2,23 @@ using System.Collections.Generic; using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Serialization; -namespace LBPUnion.ProjectLighthouse.Types { +namespace LBPUnion.ProjectLighthouse.Types +{ /// - /// Response to POST /login + /// Response to POST /login /// - [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("authTicket", this.AuthTicket), - new KeyValuePair("lbpEnvVer", this.LbpEnvVer) - ); - } + public string Serialize() + => LbpSerializer.Elements + (new KeyValuePair("authTicket", this.AuthTicket), new KeyValuePair("lbpEnvVer", this.LbpEnvVer)); } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Match/IMatchData.cs b/ProjectLighthouse/Types/Match/IMatchData.cs index 435b08ef..b785b433 100644 --- a/ProjectLighthouse/Types/Match/IMatchData.cs +++ b/ProjectLighthouse/Types/Match/IMatchData.cs @@ -1,5 +1,5 @@ -namespace LBPUnion.ProjectLighthouse.Types.Match { - public interface IMatchData { - - } +namespace LBPUnion.ProjectLighthouse.Types.Match +{ + public interface IMatchData + {} } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Match/RoomState.cs b/ProjectLighthouse/Types/Match/RoomState.cs index 1cb53079..2cfc28e2 100644 --- a/ProjectLighthouse/Types/Match/RoomState.cs +++ b/ProjectLighthouse/Types/Match/RoomState.cs @@ -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, diff --git a/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs b/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs index fade3952..ff93dd2c 100644 --- a/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs +++ b/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs @@ -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; } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Match/UpdatePlayersInRoom.cs b/ProjectLighthouse/Types/Match/UpdatePlayersInRoom.cs index a689bcc2..a7752ec2 100644 --- a/ProjectLighthouse/Types/Match/UpdatePlayersInRoom.cs +++ b/ProjectLighthouse/Types/Match/UpdatePlayersInRoom.cs @@ -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 Players; public List Reservations; } diff --git a/ProjectLighthouse/Types/News/NewsEntry.cs b/ProjectLighthouse/Types/News/NewsEntry.cs index aecf5b88..2ef65ecb 100644 --- a/ProjectLighthouse/Types/News/NewsEntry.cs +++ b/ProjectLighthouse/Types/News/NewsEntry.cs @@ -1,10 +1,12 @@ using LBPUnion.ProjectLighthouse.Serialization; -namespace LBPUnion.ProjectLighthouse.Types.News { +namespace LBPUnion.ProjectLighthouse.Types.News +{ /// - /// Used on the info moon on LBP1. Broken for unknown reasons + /// Used on the info moon on LBP1. Broken for unknown reasons /// - 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); } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/News/NewsImage.cs b/ProjectLighthouse/Types/News/NewsImage.cs index 4e134ae0..f174afff 100644 --- a/ProjectLighthouse/Types/News/NewsImage.cs +++ b/ProjectLighthouse/Types/News/NewsImage.cs @@ -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)); } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Profiles/ClientsConnected.cs b/ProjectLighthouse/Types/Profiles/ClientsConnected.cs index 2241ca4e..be6c77fe 100644 --- a/ProjectLighthouse/Types/Profiles/ClientsConnected.cs +++ b/ProjectLighthouse/Types/Profiles/ClientsConnected.cs @@ -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) + ); } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Profiles/Comment.cs b/ProjectLighthouse/Types/Profiles/Comment.cs index a10f2d16..f2260fe2 100644 --- a/ProjectLighthouse/Types/Profiles/Comment.cs +++ b/ProjectLighthouse/Types/Profiles/Comment.cs @@ -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()); } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Profiles/LastMatch.cs b/ProjectLighthouse/Types/Profiles/LastMatch.cs index 0513ca78..ec637c14 100644 --- a/ProjectLighthouse/Types/Profiles/LastMatch.cs +++ b/ProjectLighthouse/Types/Profiles/LastMatch.cs @@ -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; } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Profiles/Location.cs b/ProjectLighthouse/Types/Profiles/Location.cs index a4a9b20d..139565e6 100644 --- a/ProjectLighthouse/Types/Profiles/Location.cs +++ b/ProjectLighthouse/Types/Profiles/Location.cs @@ -1,12 +1,15 @@ using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Serialization; -namespace LBPUnion.ProjectLighthouse.Types.Profiles { +namespace LBPUnion.ProjectLighthouse.Types.Profiles +{ /// - /// The location of a slot on a planet. + /// The location of a slot on a planet. /// - [XmlRoot("location"), XmlType("location")] - public class Location { + [XmlRoot("location")] + [XmlType("location")] + public class Location + { [XmlIgnore] public int Id { get; set; } @@ -16,9 +19,6 @@ namespace LBPUnion.ProjectLighthouse.Types.Profiles { [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); } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/ResourceList.cs b/ProjectLighthouse/Types/ResourceList.cs index 7e293cd8..5af4425a 100644 --- a/ProjectLighthouse/Types/ResourceList.cs +++ b/ProjectLighthouse/Types/ResourceList.cs @@ -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; } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Settings/PrivacySettings.cs b/ProjectLighthouse/Types/Settings/PrivacySettings.cs index c381a66d..ac636c5d 100644 --- a/ProjectLighthouse/Types/Settings/PrivacySettings.cs +++ b/ProjectLighthouse/Types/Settings/PrivacySettings.cs @@ -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) ); - } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs index b4de8c54..daaa3e95 100644 --- a/ProjectLighthouse/Types/Settings/ServerSettings.cs +++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs @@ -3,10 +3,12 @@ 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 + { /// - /// The maximum amount of slots allowed on users' earth + /// The maximum amount of slots allowed on users' earth /// public const int EntitledSlots = 50; @@ -15,11 +17,11 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings { 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; } diff --git a/ProjectLighthouse/Types/Token.cs b/ProjectLighthouse/Types/Token.cs index 9232de0c..979459f1 100644 --- a/ProjectLighthouse/Types/Token.cs +++ b/ProjectLighthouse/Types/Token.cs @@ -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; } } diff --git a/ProjectLighthouse/Types/User.cs b/ProjectLighthouse/Types/User.cs index 4f06deed..8d16af5d 100644 --- a/ProjectLighthouse/Types/User.cs +++ b/ProjectLighthouse/Types/User.cs @@ -4,8 +4,13 @@ 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; } @@ -14,21 +19,22 @@ namespace LBPUnion.ProjectLighthouse.Types { public int HeartCount { get; set; } public string YayHash { get; set; } public string BooHash { get; set; } - + /// - /// A user-customizable biography shown on the profile card + /// A user-customizable biography shown on the profile card /// 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; } /// - /// The location of the profile card on the user's earth + /// The location of the profile card on the user's earth /// [ForeignKey("LocationId")] public Location Location { get; set; } @@ -42,56 +48,9 @@ namespace LBPUnion.ProjectLighthouse.Types { public int StaffChallengeBronzeCount { get; set; } public string PlanetHash { get; set; } = ""; - -// [NotMapped] - public readonly ClientsConnected ClientsConnected = new(); - - #region Slots - /// - /// The number of used slots on the earth - /// - [NotMapped] - public int UsedSlots { - get { - using Database database = new(); - return database.Slots.Count(s => s.CreatorId == this.UserId); - } - } - - /// - /// The number of slots remaining on the earth - /// - 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() + @@ -117,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 + + /// + /// The number of used slots on the earth + /// + [NotMapped] + public int UsedSlots { + get { + using Database database = new(); + return database.Slots.Count(s => s.CreatorId == this.UserId); + } + } + + /// + /// The number of slots remaining on the earth + /// + 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 + } } \ No newline at end of file diff --git a/README.md b/README.md index 479361fd..8867d5e9 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,80 @@ # 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 --project ProjectLighthouse`. ## Compatibility across games and platforms -| Game | Console (PS3/Vita) | Emulator (RPCS3) | Next-Gen (PS4/PS5) | +| 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 | diff --git a/docker-compose.yml b/docker-compose.yml index 973902f2..0f507cfe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,6 @@ services: - '3306' # Expose port to localhost:3306 volumes: - lighthouse-db:/var/lib/mysql - + volumes: lighthouse-db: \ No newline at end of file