From 6734d64e992a93f2201411a78c54b644c938fa1c Mon Sep 17 00:00:00 2001 From: Stone_Red <56473591+Stone-Red-Code@users.noreply.github.com> Date: Sun, 4 Feb 2024 20:25:30 +0100 Subject: [PATCH] Make room system generic --- .gitignore | 6 +++-- src/TextLore/Database/GamesDatabaseContext.cs | 2 +- .../Games/Roguelike/Logic/LevelGenerator.cs | 15 ++++++++---- src/TextLore/Games/Roguelike/Models/Level.cs | 21 +++++++++++++++-- .../Games/Roguelike/Models/RoomDefinition.cs | 22 ++++++++++++------ .../Games/Roguelike/Models/RoomTag.cs | 9 +++++++ .../Games/Roguelike/RoguelikePage.razor.cs | 2 +- src/TextLore/Program.cs | 20 +++++++--------- src/TextLore/games.sqlite | Bin 12288 -> 12288 bytes 9 files changed, 68 insertions(+), 29 deletions(-) create mode 100644 src/TextLore/Games/Roguelike/Models/RoomTag.cs diff --git a/.gitignore b/.gitignore index 426d76d..7b32c7f 100644 --- a/.gitignore +++ b/.gitignore @@ -302,8 +302,6 @@ node_modules/ *.dsp # Visual Studio 6 technical files -*.ncb -*.aps # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts @@ -396,3 +394,7 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml + +# SQLite +/src/TextLore/games.sqlite-shm +/src/TextLore/games.sqlite-wal diff --git a/src/TextLore/Database/GamesDatabaseContext.cs b/src/TextLore/Database/GamesDatabaseContext.cs index 350e663..4affdb1 100644 --- a/src/TextLore/Database/GamesDatabaseContext.cs +++ b/src/TextLore/Database/GamesDatabaseContext.cs @@ -4,5 +4,5 @@ namespace TextLore.Database; public class GamesDatabaseContext(DbContextOptions options) : DbContext(options) { - public DbSet RoguelikeRooms { get; set; } + public DbSet Rooms { get; set; } } \ No newline at end of file diff --git a/src/TextLore/Games/Roguelike/Logic/LevelGenerator.cs b/src/TextLore/Games/Roguelike/Logic/LevelGenerator.cs index b58910b..3d790f2 100644 --- a/src/TextLore/Games/Roguelike/Logic/LevelGenerator.cs +++ b/src/TextLore/Games/Roguelike/Logic/LevelGenerator.cs @@ -19,12 +19,12 @@ public class LevelGenerator(DeterministicRandom seed, IQueryable Level level = new Level(size, seed); Queue generationQueue = new Queue(); - RoomDefinition startRoomDefinition = await GetRandomRoomDefinition() ?? throw new InvalidOperationException("No rooms found in the database."); + RoomDefinition startRoomDefinition = await GetRandomRoomDefinition(level) ?? throw new InvalidOperationException("No rooms found in the database."); Position startRoomPosition = new Position(seed.Next(0, size.Width), seed.Next(0, size.Height)); Room startRoom = new Room(startRoomPosition, startRoomDefinition); - level.AddRoom(startRoom); + _ = level.AddRoom(startRoom); generationQueue.Enqueue(startRoom); while (generationQueue.Count > 0) @@ -43,11 +43,11 @@ public class LevelGenerator(DeterministicRandom seed, IQueryable if (level.IsPositionInBounds(newPosition) && level.GetRoom(newPosition) is null) { - RoomDefinition? newRoomDefinition = await GetRandomRoomDefinition(); + RoomDefinition? newRoomDefinition = await GetRandomRoomDefinition(level); Room newRoom = new Room(newPosition, newRoomDefinition ?? throw new InvalidOperationException("No rooms found in the database.")); - level.AddRoom(newRoom); + _ = level.AddRoom(newRoom); generationQueue.Enqueue(newRoom); } } @@ -74,7 +74,7 @@ public class LevelGenerator(DeterministicRandom seed, IQueryable return level; } - private async Task GetRandomRoomDefinition() + private async Task GetRandomRoomDefinition(Level level) { RoomDefinition? room = null; int randomRoomIndex = seed.Next(); @@ -87,6 +87,11 @@ public class LevelGenerator(DeterministicRandom seed, IQueryable { room = await rooms.FirstOrDefaultAsync(x => x.Id == randomRoomIndex); + if (room?.Tag == RoomTag.Unique && level.RoomExists(room)) + { + room = null; + } + if (room is not null) { break; diff --git a/src/TextLore/Games/Roguelike/Models/Level.cs b/src/TextLore/Games/Roguelike/Models/Level.cs index fe94250..dcd4b7b 100644 --- a/src/TextLore/Games/Roguelike/Models/Level.cs +++ b/src/TextLore/Games/Roguelike/Models/Level.cs @@ -22,14 +22,26 @@ public class Level(Size size, DeterministicRandom seed) return rooms; } - public void AddRoom(Room room) + public bool AddRoom(Room room) { if (!IsRoomInBounds(room)) { - throw new InvalidOperationException("Room is out of bounds."); + return false; + } + + if (room.Definition.Tag == RoomTag.Unique && RoomExists(room.Definition)) + { + return false; + } + + if (room.Definition.Tag == RoomTag.Start && rooms.Values.Any(r => r.Definition.Tag == RoomTag.Start)) + { + return false; } rooms[room.Position] = room; + + return true; } public bool IsPositionInBounds(Position point) @@ -47,6 +59,11 @@ public class Level(Size size, DeterministicRandom seed) return rooms.ContainsKey(point); } + public bool RoomExists(RoomDefinition definition) + { + return rooms.Values.Any(r => r.Definition.Id == definition.Id); + } + public void ClearRoom(Position point) { _ = rooms.Remove(point); diff --git a/src/TextLore/Games/Roguelike/Models/RoomDefinition.cs b/src/TextLore/Games/Roguelike/Models/RoomDefinition.cs index 20144ed..8d2b2c8 100644 --- a/src/TextLore/Games/Roguelike/Models/RoomDefinition.cs +++ b/src/TextLore/Games/Roguelike/Models/RoomDefinition.cs @@ -1,14 +1,22 @@ -using System.ComponentModel.DataAnnotations; +using Microsoft.EntityFrameworkCore; + using System.ComponentModel.DataAnnotations.Schema; namespace TextLore.Games.Roguelike.Models; -public class RoomDefinition(string name) +[PrimaryKey(nameof(Id), nameof(Tag), nameof(Game))] +public class RoomDefinition(int id, RoomTag tag, string game) { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; private set; } + [Column(Order = 0)] + public int Id { get; } = id; - [Required] - public string Name { get; set; } = name; + [Column(Order = 1)] + public RoomTag Tag { get; } = tag; + + [Column(Order = 2)] + public string Game { get; } = game; + + public required string Name { get; set; } + + public string Script { get; set; } = string.Empty; } \ No newline at end of file diff --git a/src/TextLore/Games/Roguelike/Models/RoomTag.cs b/src/TextLore/Games/Roguelike/Models/RoomTag.cs new file mode 100644 index 0000000..374daba --- /dev/null +++ b/src/TextLore/Games/Roguelike/Models/RoomTag.cs @@ -0,0 +1,9 @@ +namespace TextLore.Games.Roguelike.Models; + +public enum RoomTag +{ + None = 0, + Start = 1, + End = 2, + Unique = 3 +} \ No newline at end of file diff --git a/src/TextLore/Games/Roguelike/RoguelikePage.razor.cs b/src/TextLore/Games/Roguelike/RoguelikePage.razor.cs index b168fe2..cc99f3b 100644 --- a/src/TextLore/Games/Roguelike/RoguelikePage.razor.cs +++ b/src/TextLore/Games/Roguelike/RoguelikePage.razor.cs @@ -37,7 +37,7 @@ public partial class RoguelikePage { if (firstRender) { - await console.Execute(new GenerateLevelCommand(DatabaseContext.RoguelikeRooms, NavigationManager, OnLevelGenerated), Seed); + await console.Execute(new GenerateLevelCommand(DatabaseContext.Rooms, NavigationManager, OnLevelGenerated), Seed); } } } \ No newline at end of file diff --git a/src/TextLore/Program.cs b/src/TextLore/Program.cs index 2f04cea..f06b9d3 100644 --- a/src/TextLore/Program.cs +++ b/src/TextLore/Program.cs @@ -28,17 +28,15 @@ GamesDatabaseContext databaseContext = serviceScope.ServiceProvider.GetRequiredS if (await databaseContext.Database.EnsureCreatedAsync()) { - databaseContext.RoguelikeRooms.AddRange( - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 1"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 2"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 3"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 4"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 5"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 6"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 7"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 8"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 9"), - new TextLore.Games.Roguelike.Models.RoomDefinition("Room 10") + databaseContext.Rooms.AddRange( + new TextLore.Games.Roguelike.Models.RoomDefinition(1, TextLore.Games.Roguelike.Models.RoomTag.Start, "rogelike") { Name = "Start Room" }, + new TextLore.Games.Roguelike.Models.RoomDefinition(1, TextLore.Games.Roguelike.Models.RoomTag.Unique, "rogelike") { Name = "Unique Room" }, + new TextLore.Games.Roguelike.Models.RoomDefinition(2, TextLore.Games.Roguelike.Models.RoomTag.Unique, "rogelike") { Name = "Normal Room 1" }, + new TextLore.Games.Roguelike.Models.RoomDefinition(3, TextLore.Games.Roguelike.Models.RoomTag.Unique, "rogelike") { Name = "Normal Room 2" }, + new TextLore.Games.Roguelike.Models.RoomDefinition(4, TextLore.Games.Roguelike.Models.RoomTag.Unique, "rogelike") { Name = "Normal Room 3" }, + new TextLore.Games.Roguelike.Models.RoomDefinition(5, TextLore.Games.Roguelike.Models.RoomTag.Unique, "rogelike") { Name = "Normal Room 4" }, + new TextLore.Games.Roguelike.Models.RoomDefinition(6, TextLore.Games.Roguelike.Models.RoomTag.Unique, "rogelike") { Name = "Normal Room 5" }, + new TextLore.Games.Roguelike.Models.RoomDefinition(1, TextLore.Games.Roguelike.Models.RoomTag.End, "rogelike") { Name = "End Room" } ); _ = await databaseContext.SaveChangesAsync(); diff --git a/src/TextLore/games.sqlite b/src/TextLore/games.sqlite index 531ee3ae5301db306075e22180e62f973aa3584c..18e31e13550b2aac2279f1eedd9ff31ee6ae6713 100644 GIT binary patch delta 383 zcmZojXh@il%FX|Sfr)Q61K(`^-5U$F`M8>78QH}(H5r>rC;Rfp)a&qaDFA^|NMgE@ zf~Q}ItGjEEf}ekgf?ueQ4@}ZMF*j97A;dKTD2yiMhg&K*xhS)s1iL4l2}v%mf-@M^N4}}6aOQiIoJ5*_*sF*Fv3k?;$;PD I<%H=306e*7X#fBK delta 336 zcmZojXh@il%FV#Qz{K~Ff!~?$<7PpDM!uK;CN^^m|5yH3{P+2<@So)0$G@3>1^-%)r7#eVLGBZem*_NCfFs213JB(@0$p&MZak9dgrkpG=rU@rAjA_it1Y;U; tGQyaKAO|t>zhM9(FxV`vaGHN&gP@2IBeN!BP=0!8YEEW$D##JVTmYmiShD~C