diff --git a/Minecraft-Realms-Emulator/Controllers/WorldsController.cs b/Minecraft-Realms-Emulator/Controllers/WorldsController.cs index 0e80380..4e88f64 100644 --- a/Minecraft-Realms-Emulator/Controllers/WorldsController.cs +++ b/Minecraft-Realms-Emulator/Controllers/WorldsController.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; using Minecraft_Realms_Emulator.Attributes; using Minecraft_Realms_Emulator.Data; using Minecraft_Realms_Emulator.Entities; using Minecraft_Realms_Emulator.Requests; using Minecraft_Realms_Emulator.Responses; using Newtonsoft.Json; +using Semver; namespace Minecraft_Realms_Emulator.Controllers { @@ -28,6 +30,7 @@ namespace Minecraft_Realms_Emulator.Controllers string playerUUID = cookie.Split(";")[0].Split(":")[2]; string playerName = cookie.Split(";")[1].Split("=")[1]; + string gameVersion = cookie.Split(";")[2].Split("=")[1]; var ownedWorlds = await _context.Worlds.Where(w => w.OwnerUUID == playerUUID).Include(w => w.Subscription).ToListAsync(); var memberWorlds = await _context.Players.Where(p => p.Uuid == playerUUID && p.Accepted).Include(p => p.World.Subscription).Select(p => p.World).ToListAsync(); @@ -49,7 +52,8 @@ namespace Minecraft_Realms_Emulator.Controllers MinigameName = null, MinigameImage = null, ActiveSlot = 1, - Member = false + Member = false, + ActiveVersion = gameVersion }; ownedWorlds.Add(world); @@ -60,6 +64,9 @@ namespace Minecraft_Realms_Emulator.Controllers foreach (var world in ownedWorlds) { + int versionsCompared = SemVersion.Parse(gameVersion, SemVersionStyles.Strict).ComparePrecedenceTo(SemVersion.Parse(world.ActiveVersion, SemVersionStyles.Strict)); + string isCompatible = versionsCompared == 0 ? "COMPATIBLE" : versionsCompared < 0 ? "NEEDS_DOWNGRADE" : "NEEDS_UPGRADE"; + WorldResponse response = new() { Id = world.Id, @@ -75,7 +82,9 @@ namespace Minecraft_Realms_Emulator.Controllers MinigameImage = world.MinigameImage, ActiveSlot = world.ActiveSlot, Member = world.Member, - Players = world.Players + Players = world.Players, + ActiveVersion = world.ActiveVersion, + Compatibility = isCompatible }; if (world.Subscription != null) @@ -90,6 +99,9 @@ namespace Minecraft_Realms_Emulator.Controllers foreach (var world in memberWorlds) { + int versionsCompared = SemVersion.Parse(gameVersion, SemVersionStyles.Strict).ComparePrecedenceTo(SemVersion.Parse(world.ActiveVersion, SemVersionStyles.Strict)); + string isCompatible = versionsCompared == 0 ? "COMPATIBLE" : versionsCompared < 0 ? "NEEDS_DOWNGRADE" : "NEEDS_UPGRADE"; + WorldResponse response = new() { Id = world.Id, @@ -108,7 +120,9 @@ namespace Minecraft_Realms_Emulator.Controllers Players = world.Players, DaysLeft = 0, Expired = ((DateTimeOffset)world.Subscription.StartDate.AddDays(30) - DateTime.Today).Days < 0, - ExpiredTrial = false + ExpiredTrial = false, + ActiveVersion = world.ActiveVersion, + Compatibility = isCompatible }; allWorlds.Add(response); @@ -125,10 +139,16 @@ namespace Minecraft_Realms_Emulator.Controllers [HttpGet("{id}")] public async Task> GetWorldById(int id) { + string cookie = Request.Headers.Cookie; + string gameVersion = cookie.Split(";")[2].Split("=")[1]; + var world = await _context.Worlds.Include(w => w.Players).Include(w => w.Subscription).FirstOrDefaultAsync(w => w.Id == id); if (world?.Subscription == null) return NotFound("World not found"); + int versionsCompared = SemVersion.Parse(gameVersion, SemVersionStyles.Strict).ComparePrecedenceTo(SemVersion.Parse(world.ActiveVersion, SemVersionStyles.Strict)); + string isCompatible = versionsCompared == 0 ? "COMPATIBLE" : versionsCompared < 0 ? "NEEDS_DOWNGRADE" : "NEEDS_UPGRADE"; + WorldResponse response = new() { Id = world.Id, @@ -143,11 +163,14 @@ namespace Minecraft_Realms_Emulator.Controllers MinigameName = world.MinigameName, MinigameImage = world.MinigameImage, ActiveSlot = world.ActiveSlot, + Slots = world.Slots, Member = world.Member, Players = world.Players, DaysLeft = ((DateTimeOffset)world.Subscription.StartDate.AddDays(30) - DateTime.Today).Days, Expired = ((DateTimeOffset)world.Subscription.StartDate.AddDays(30) - DateTime.Today).Days < 0, - ExpiredTrial = false + ExpiredTrial = false, + ActiveVersion = world.ActiveVersion, + Compatibility = isCompatible }; return response; diff --git a/Minecraft-Realms-Emulator/Entities/World.cs b/Minecraft-Realms-Emulator/Entities/World.cs index cbee5ca..c14b5b6 100644 --- a/Minecraft-Realms-Emulator/Entities/World.cs +++ b/Minecraft-Realms-Emulator/Entities/World.cs @@ -20,5 +20,6 @@ namespace Minecraft_Realms_Emulator.Entities public int ActiveSlot { get; set; } = 1; public JsonDocument[] Slots { get; set; } = []; public bool Member { get; set; } = false; + public string ActiveVersion { get; set; } = null!; } } \ No newline at end of file diff --git a/Minecraft-Realms-Emulator/Migrations/20240421111457_Worlds_Version.Designer.cs b/Minecraft-Realms-Emulator/Migrations/20240421111457_Worlds_Version.Designer.cs new file mode 100644 index 0000000..fab8e68 --- /dev/null +++ b/Minecraft-Realms-Emulator/Migrations/20240421111457_Worlds_Version.Designer.cs @@ -0,0 +1,317 @@ +// +using System; +using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Minecraft_Realms_Emulator.Data; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Minecraft_Realms_Emulator.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20240421111457_Worlds_Version")] + partial class Worlds_Version + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Backup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BackupId") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastModifiedDate") + .HasColumnType("bigint"); + + b.Property("Metadata") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("WorldId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WorldId"); + + b.ToTable("Backups"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Configuration", b => + { + b.Property("Key") + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("jsonb"); + + b.HasKey("Key"); + + b.ToTable("Configuration"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Connection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Address") + .IsRequired() + .HasColumnType("text"); + + b.Property("PendingUpdate") + .HasColumnType("boolean"); + + b.Property("WorldId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WorldId"); + + b.ToTable("Connections"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Invite", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("InvitationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("RecipeintUUID") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorldId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WorldId"); + + b.ToTable("Invites"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Accepted") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Online") + .HasColumnType("boolean"); + + b.Property("Operator") + .HasColumnType("boolean"); + + b.Property("Permission") + .IsRequired() + .HasColumnType("text"); + + b.Property("Uuid") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorldId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WorldId"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Subscription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SubscriptionType") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorldId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WorldId") + .IsUnique(); + + b.ToTable("Subscriptions"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.World", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ActiveSlot") + .HasColumnType("integer"); + + b.Property("ActiveVersion") + .IsRequired() + .HasColumnType("text"); + + b.Property("MaxPlayers") + .HasColumnType("integer"); + + b.Property("Member") + .HasColumnType("boolean"); + + b.Property("MinigameId") + .HasColumnType("integer"); + + b.Property("MinigameImage") + .HasColumnType("text"); + + b.Property("MinigameName") + .HasColumnType("text"); + + b.Property("Motd") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Owner") + .HasColumnType("text"); + + b.Property("OwnerUUID") + .HasColumnType("text"); + + b.Property("Slots") + .IsRequired() + .HasColumnType("jsonb[]"); + + b.Property("State") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorldType") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Worlds"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Backup", b => + { + b.HasOne("Minecraft_Realms_Emulator.Entities.World", "World") + .WithMany() + .HasForeignKey("WorldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("World"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Connection", b => + { + b.HasOne("Minecraft_Realms_Emulator.Entities.World", "World") + .WithMany() + .HasForeignKey("WorldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("World"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Invite", b => + { + b.HasOne("Minecraft_Realms_Emulator.Entities.World", "World") + .WithMany() + .HasForeignKey("WorldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("World"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Player", b => + { + b.HasOne("Minecraft_Realms_Emulator.Entities.World", "World") + .WithMany("Players") + .HasForeignKey("WorldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("World"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.Subscription", b => + { + b.HasOne("Minecraft_Realms_Emulator.Entities.World", "World") + .WithOne("Subscription") + .HasForeignKey("Minecraft_Realms_Emulator.Entities.Subscription", "WorldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("World"); + }); + + modelBuilder.Entity("Minecraft_Realms_Emulator.Entities.World", b => + { + b.Navigation("Players"); + + b.Navigation("Subscription"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Minecraft-Realms-Emulator/Migrations/20240421111457_Worlds_Version.cs b/Minecraft-Realms-Emulator/Migrations/20240421111457_Worlds_Version.cs new file mode 100644 index 0000000..0b22471 --- /dev/null +++ b/Minecraft-Realms-Emulator/Migrations/20240421111457_Worlds_Version.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Minecraft_Realms_Emulator.Migrations +{ + /// + public partial class Worlds_Version : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "ActiveVersion", + table: "Worlds", + type: "text", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ActiveVersion", + table: "Worlds"); + } + } +} diff --git a/Minecraft-Realms-Emulator/Migrations/DataContextModelSnapshot.cs b/Minecraft-Realms-Emulator/Migrations/DataContextModelSnapshot.cs index 12d1c8f..4369893 100644 --- a/Minecraft-Realms-Emulator/Migrations/DataContextModelSnapshot.cs +++ b/Minecraft-Realms-Emulator/Migrations/DataContextModelSnapshot.cs @@ -18,7 +18,7 @@ namespace Minecraft_Realms_Emulator.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.1") + .HasAnnotation("ProductVersion", "8.0.4") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -199,6 +199,10 @@ namespace Minecraft_Realms_Emulator.Migrations b.Property("ActiveSlot") .HasColumnType("integer"); + b.Property("ActiveVersion") + .IsRequired() + .HasColumnType("text"); + b.Property("MaxPlayers") .HasColumnType("integer"); diff --git a/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj b/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj index 82c31c9..64d3f98 100644 --- a/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj +++ b/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj @@ -17,6 +17,7 @@ + diff --git a/Minecraft-Realms-Emulator/Responses/WorldResponse.cs b/Minecraft-Realms-Emulator/Responses/WorldResponse.cs index 233f340..964dbf3 100644 --- a/Minecraft-Realms-Emulator/Responses/WorldResponse.cs +++ b/Minecraft-Realms-Emulator/Responses/WorldResponse.cs @@ -6,5 +6,6 @@ public int DaysLeft { get; set; } = 30; public bool Expired { get; set; } = false; public bool ExpiredTrial { get; set; } = false; + public string Compatibility { get; set; } = null!; } } \ No newline at end of file