diff --git a/Src/NationsConverter/NationsConverter.csproj b/Src/NationsConverter/NationsConverter.csproj index 20f9b5b..f248227 100644 --- a/Src/NationsConverter/NationsConverter.csproj +++ b/Src/NationsConverter/NationsConverter.csproj @@ -1,6 +1,7 @@  + 2.0.0-alpha.1 net9.0 enable enable diff --git a/Src/NationsConverter/Stages/MediaTrackerStage.cs b/Src/NationsConverter/Stages/MediaTrackerStage.cs index f83929b..36d88cb 100644 --- a/Src/NationsConverter/Stages/MediaTrackerStage.cs +++ b/Src/NationsConverter/Stages/MediaTrackerStage.cs @@ -3,7 +3,7 @@ namespace NationsConverter.Stages; -internal sealed class MediaTrackerStage +internal sealed class MediaTrackerStage : EnvironmentStageBase { private readonly CGameCtnChallenge mapIn; private readonly CGameCtnChallenge mapOut; @@ -12,14 +12,14 @@ internal sealed class MediaTrackerStage private readonly Int3 blockSize; private readonly Int3 centerOffset; - public MediaTrackerStage(CGameCtnChallenge mapIn, CGameCtnChallenge mapOut, NationsConverterConfig config) + public MediaTrackerStage(CGameCtnChallenge mapIn, CGameCtnChallenge mapOut, NationsConverterConfig config) : base(mapIn) { this.mapIn = mapIn; this.mapOut = mapOut; this.config = config; blockSize = mapIn.Collection.GetValueOrDefault().GetBlockSize(); - centerOffset = new Int3((mapOut.Size.X - mapIn.Size.X) / 2, 0, (mapOut.Size.Z - mapIn.Size.Z) / 2) ; + centerOffset = new Int3((mapOut.Size.X - mapIn.Size.X) / 2, 0, (mapOut.Size.Z - mapIn.Size.Z) / 2); } public void Convert() @@ -182,7 +182,7 @@ public void Convert() Start = cameraGame.Start, End = cameraGame.End, }; - newCameraGame.CreateChunk().Version = 2; + newCameraGame.CreateChunk().Version = 4; newTrack.Blocks.Add(newCameraGame); break; @@ -214,9 +214,9 @@ public void Convert() var coordEnumerable = trigger.Coords?.Select(coord => coord with { X = coord.X * blockSize.X / 32, - Y = coord.Y * blockSize.Y / 8 + 9, + Y = coord.Y * blockSize.Y / 8 + 8, Z = coord.Z * blockSize.Z / 32, - }); + } + centerOffset); var coords = new List(); foreach (var coord in coordEnumerable ?? []) diff --git a/Src/NationsConverterCLI/Config/Default/Manual/Crystal/Stadium.yml b/Src/NationsConverterCLI/Config/Default/Manual/Crystal/Stadium.yml index 5bba0b7..1150c8d 100644 --- a/Src/NationsConverterCLI/Config/Default/Manual/Crystal/Stadium.yml +++ b/Src/NationsConverterCLI/Config/Default/Manual/Crystal/Stadium.yml @@ -122,7 +122,9 @@ Blocks: StadiumRoadDirtToRoadGrass: Items: - Name: RoadDirt/RoadLow/StadiumRoadDirt/Ground_3_0.Item.Gbx + Modernized: true - Name: RoadDirt/RoadLow/StadiumRoadDirtFenceStraight/Ground_0_0.Item.Gbx + Modernized: true StadiumRoadDirtCheckpoint: NoItem: true NoTerrainModifier: true @@ -944,11 +946,13 @@ Blocks: Modernized: true Conversion: Name: StadiumRoadDirtHigh + Modernized: true Variant: 3 Items: - Name: Misc/Waypoint/Checkpoint.Item.Gbx OffsetY: 8 - Name: RoadDirt/RoadHigh/StadiumRoadDirtHighFenceStraight/Ground_0_0.Item.Gbx + Modernized: true StadiumRoadDirtHighGTCurve2: Modernized: true StadiumRoadDirtHighGTCurve3: diff --git a/Src/NationsConverterCLI/NationsConverterCLI.csproj b/Src/NationsConverterCLI/NationsConverterCLI.csproj index a4c3ba8..adece03 100644 --- a/Src/NationsConverterCLI/NationsConverterCLI.csproj +++ b/Src/NationsConverterCLI/NationsConverterCLI.csproj @@ -1,6 +1,7 @@  + 2.0.0-alpha.1 Exe net9.0 enable diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/ImgComparison.razor b/Src/NationsConverterWeb/NationsConverterWeb/Components/ImgComparison.razor index 0f4d362..16fac48 100644 --- a/Src/NationsConverterWeb/NationsConverterWeb/Components/ImgComparison.razor +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/ImgComparison.razor @@ -1,27 +1,39 @@ -
-
- - +@rendermode InteractiveServer +
+
+ + -
-
+
+
+ fill="none" + viewBox="0 0 24 24" + stroke-width="1" + stroke="currentColor" + class="w-6 h-6"> + stroke-linejoin="round" + d="M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" />
- +
@code { + [Parameter] + public string? BeforeImage { get; set; } + + [Parameter] + public string? AfterImage { get; set; } + + private string? sliderValue; + public void OnInput(string value) + { + sliderValue = value; + } } diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/NavMenu.razor b/Src/NationsConverterWeb/NationsConverterWeb/Components/NavMenu.razor index 59b9d12..3e97dd7 100644 --- a/Src/NationsConverterWeb/NationsConverterWeb/Components/NavMenu.razor +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/NavMenu.razor @@ -11,7 +11,7 @@
@if (Released) { - + } diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/About.razor b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/About.razor new file mode 100644 index 0000000..d37833a --- /dev/null +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/About.razor @@ -0,0 +1,14 @@ +@page "/about" +@attribute [AllowAnonymous] + +About - Nations Converter 2 + + +
+
+
+

About this project

+

One day, we will write something here...

+
+
+
diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/About.razor.css b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/About.razor.css new file mode 100644 index 0000000..809c89a --- /dev/null +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/About.razor.css @@ -0,0 +1,84 @@ +.download-latest { + padding: 20px; + font-size: 120%; +} + + .download-latest div { + max-width: 1200px; + margin: 0 auto; + } + +.latest-version { + text-align: center; + font-size: 150%; +} + +.download-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 15px; +} + +.download-button-set { + display: flex; + flex-direction: column; + gap: 8px; +} + + .download-button-set a { + padding: 5px 10px; + } + + .download-button-set a:first-child { + font-weight: bold; + } + + .download-button-set div { + font-size: 80%; + } + +.button-download-platform { + display: flex; + align-items: center; + width: 180px; + border-radius: 10px; +} + + .button-download-platform img { + padding-right: 5px; + border-right: 2px solid #FFF5; + } + + .button-download-platform span { + flex: 1; + text-align: center; + } + +.edition-row { + display: flex; + gap: 5px; + flex-grow: 1; + width: 100%; +} + +.button-download-assets { + display: flex; + padding: 5px 10px; + width: 100%; + align-items: center; + justify-content: center; +} + + .button-download-assets span { + flex: 1; + text-align: center; + } + +.download-assets { + display: flex; + flex-direction: column; + gap: 5px; + width: 400px; + font-size: 90%; + font-weight: bold; +} diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Dashboard.razor b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Dashboard.razor index 82527ed..67b9eb7 100644 --- a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Dashboard.razor +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Dashboard.razor @@ -2,6 +2,7 @@ @attribute [Authorize(Roles = "Admin,Developer,Modeler")] @inject IDbContextFactory DbFactory @inject IJSRuntime JS +@inject IWebHostEnvironment Env @inject ILogger Logger @rendermode InteractiveServer @@ -101,6 +102,7 @@ { + Bulk fix } @@ -213,12 +215,12 @@ currentDiscordUser = discordUsers.FirstOrDefault(x => x.Id == snowflake); - /*blocks = db.Blocks - .Where(x => x.Name.Contains(searchValue)) - .Where(x => x.EnvironmentId.Contains(Environment ?? "")) - .Include(x => x.AssignedTo) - .ThenInclude(x => x!.DiscordUser) - .AsNoTracking() + /*blocks = db.Blocks + .Where(x => x.Name.Contains(searchValue)) + .Where(x => x.EnvironmentId.Contains(Environment ?? "")) + .Include(x => x.AssignedTo) + .ThenInclude(x => x!.DiscordUser) + .AsNoTracking() .Select(x => new BlockDto { Id = x.Id, @@ -291,6 +293,72 @@ await JS.InvokeVoidAsync("downloadFileFromStream", "UserData.zip", streamRef); } + private async Task PublishCurrentZipAssetsAsync() + { + await using var db = DbFactory.CreateDbContext(); + + var uploads = await db.ItemUploads + .Include(x => x.BlockItem) + .ThenInclude(x => x.Block) + .GroupBy(x => x.BlockItem) + .Select(x => x.OrderByDescending(x => x.UploadedAt).First()) + .ToListAsync(); + + var zipStreamDict = new Dictionary(); + var zipDict = new Dictionary(); + + foreach (var env in new string[] { "Desert", "Rally", "Snow" }) + { + var zipMs = new MemoryStream(); + var zip = new ZipArchive(zipMs, ZipArchiveMode.Create, leaveOpen: true); + zipStreamDict[env] = zipMs; + zipDict[env] = zip; + } + + foreach (var upload in uploads) + { + if (!zipDict.TryGetValue(upload.BlockItem.Block.EnvironmentId, out var zip)) + { + continue; + } + + var filePath = Path.Combine( + "Items", + "NC2", + upload.BlockItem.Block.CategoryId, + upload.BlockItem.Block.SubCategoryId, + "MM_Collision", + upload.BlockItem.Block.EnvironmentId, + upload.BlockItem.Block.PageName, + upload.BlockItem.Block.Name, + upload.BlockItem.FileName); + + var entry = zip.CreateEntry(filePath, CompressionLevel.SmallestSize); + + entry.LastWriteTime = upload.LastModifiedAt; + + using var entryStream = entry.Open(); + await using var uploadStream = new MemoryStream(upload.Data); + await uploadStream.CopyToAsync(entryStream); + } + + foreach (var (env, zip) in zipDict) + { + zip.Dispose(); + } + + foreach (var (env, zipMs) in zipStreamDict) + { + zipMs.Position = 0; + + var assets = Path.Combine(Env.WebRootPath, "assets"); + Directory.CreateDirectory(assets); + await using var fs = new FileStream(Path.Combine(assets, $"{env}.zip"), FileMode.Create, FileAccess.Write, FileShare.None, 4096, useAsync: true); + + await zipMs.CopyToAsync(fs); + } + } + private async Task DownloadClaimedInitItemsAsync() { if (currentDiscordUser is null) diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor index 5a44539..2e15268 100644 --- a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor @@ -1,7 +1,7 @@ @page "/downloads" @attribute [AllowAnonymous] -Nations Converter 2 - Downloads +Downloads - Nations Converter 2
@@ -9,11 +9,12 @@

Download the CLI tool

CLI is shipped with common Stadium assets by default (Crystal Classic and Modernized). For other environments, download additional assets.

+

To install additional assets, move the downloaded asset ZIP file to the UserData folder of the converter. Do not extract anything from it.

-

2.0.0-alpha01

+

2.0.0-alpha.01

Tool
Item assets
@@ -21,7 +22,7 @@
@@ -33,17 +34,17 @@
- Island - Bay - Coast + Island + Bay + Coast
- Stadium (Solid) + Stadium (Solid)
@@ -57,37 +58,40 @@
-

Tool build assets have been taken from the latest GitHub release, which is automatically generated.

+

Tool build assets have been taken from the latest GitHub release, which is automatically generated from open-source code.

Item assets are hosted separately and deployed manually, as they don't contain any code.

-

Other tool builds

-
- - - - - - - - - - - - - - - - - - - - - - - - - -
VersionRelease dateDownload
1.0.02023-12-31Download
0.9.02023-12-30Download
0.8.02023-12-29Download
-
+ @if (!hideOtherToolBuilds) + { +

Other tool builds

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
VersionRelease dateDownload
1.0.02023-12-31Download
0.9.02023-12-30Download
0.8.02023-12-29Download
+
+ }
@@ -95,4 +99,6 @@ @code { [Parameter] public bool Released { get; set; } + + private bool hideOtherToolBuilds = true; } diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor.css b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor.css index 809c89a..9dc9ac5 100644 --- a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor.css +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Downloads.razor.css @@ -74,6 +74,10 @@ text-align: center; } +.button-download-assets.disabled { + background-color: #666; +} + .download-assets { display: flex; flex-direction: column; diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor index 5a47864..0f6e01d 100644 --- a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor @@ -35,11 +35,11 @@ else
-
+

Join the Discord server

Discuss anything, report issues, suggest features, share maps, or apply for modeller!

- +
@@ -77,7 +77,7 @@ else (+ TM2) (+ TM2) - + Desert @@ -178,35 +178,35 @@ else

How does it look like?

- +

Stadium (category: Crystal, Modernized)

Blocks we made in 2020 were getting a little old. We modernized the Stadium conversion to the 2024 standard.

- +

Desert (category: Solid, Modless)

The first non-Stadium environment that we ported to Nations Converter.

- +

Rally (category: Solid, Modless)

Less of a swamp now. Reflective water, remade houses, usage of item trees.

- +

Snow (category: Solid, Modless)

-

The most contrasted and overhauled environment in Nations Converter 2.

+

Contrasted yet well-blended. Proper winter vibes right here.

- +

Stadium (category: Crystal, Classic)

We brought the same Nations Converter back to with minor improvements, if you're used to it.

@@ -237,17 +237,17 @@ else

Balanced

Mod that looks acceptable when you don't have it downloaded. To be done.

Stock

-

Keep the true looks of TM2020. Save a lot of time you'd spend copying the blocks one by one.

+

Keep the true looks of TM2020. Save a lot of time you'd spend copying the blocks one by one. To be done.

Enhanced

-

Represents most of the older blocks in the TM2020 style. Includes custom assets to reach this quality.

-

Stock

-

Attempt its best to copy the map layout with official assets only. Perfect for concepts to expand on. No custom assets are embedded to the map.

+

Represents most of the older blocks in the TM2020 style. Includes custom assets to reach this quality. To be done.

+

Raw

+

Attempt its best to copy the map layout with official assets only. Perfect for concepts to expand on. No custom assets are embedded to the map. To be done.

Believe it or not, the tool is open source

- GitHub + GitHub
@@ -259,7 +259,7 @@ else

Mesh modeling team (looking for more volunteers!)

-

harry.alexm, Paddy Productions, nod, Zai, eyebo

+

harry.alexm, Paddy Productions, nod, Zai, eyebo, Rokas RX

Mod work

@@ -280,7 +280,7 @@ else @code { [CascadingParameter] public Task? AuthenticationStateTask { get; set; } - public bool Released { get; set; } = false; + public bool Released { get; set; } public bool WebAppReleased { get; set; } diff --git a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor.css b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor.css index 96676d7..110b93a 100644 --- a/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor.css +++ b/Src/NationsConverterWeb/NationsConverterWeb/Components/Pages/Index.razor.css @@ -17,7 +17,7 @@ div.comparisons { div.showcase { display: flex; - gap: 10px; + gap: 20px; } div.showcase div.text { @@ -83,19 +83,28 @@ div.showcase { gap: 20px; } -#button-discord { - display: block; - border: 2px solid #457; - border-radius: 5px; - padding: 10px; - width: 250px; - text-align: center; - background-color: #346; - color: white; - text-decoration: none; - font-weight: bold; +.button-discord { + display: flex; + height: 80px; + background-color: #5865F2 +} + + .button-discord:hover { + background-color: #6E7BEF; + } + +.discord-server { + gap: 20px; + display: flex; + flex-direction: column; + flex: 1; + justify-content: center; +} + +h3 { + margin-top: 15px; } - #button-discord:hover { - background-color: #457; - } \ No newline at end of file +h4 { + margin-top: 10px; +} \ No newline at end of file