Refactor namespaces to follow new naming convention and add item model classes

This commit is contained in:
Jose Henrique 2025-02-02 12:39:59 -03:00
parent 4e5addd1d5
commit 0a257199f7
27 changed files with 463 additions and 94 deletions

@ -1,8 +1,8 @@
using Microsoft.AspNetCore.Mvc;
using pet_companion_api.Models;
using pet_companion_api.Services;
using Pet.Companion.Models;
using Pet.Companion.Services;
namespace pet_companion_api.Controllers
namespace Pet.Companion.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]

42
DATABASE.md Normal file

@ -0,0 +1,42 @@
# Database Setup and Migration Guide
## Prerequisites
- .NET 8.0 SDK
- Entity Framework Core tools
## Install EF Core Tools
```sh
dotnet tool install --global dotnet-ef
```
### Creating and Updating Database
1. Create initial migration:
dotnet ef migrations add InitialCreate
2. Apply migrations to create/update database:
dotnet ef database update
### Common Commands
1. Create new migration:
dotnet ef migrations add <MigrationName>
2. Remove last migration:
dotnet ef migrations remove
3. Apply migrations to create/update database:
dotnet ef database update
4. Revert last migration:
dotnet ef database update <MigrationName>
5. List all migrations:
dotnet ef migrations list
6. Script migration:
dotnet ef migrations script
7. Remove all migrations:
dotnet ef migrations remove
8. Drop database:
dotnet ef database drop

@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using pet_companion_api.Models;
using Pet.Companion.Models;
namespace pet_companion_api.Data
namespace Pet.Companion.Data
{
public class ApplicationDbContext : DbContext
{

20
Items.csv Normal file

@ -0,0 +1,20 @@
Item Name, Type, Rarity, Description
Basic Kibble,Consumable,Common,Adds +20 food resources
Superfood Smoothie,Consumable,Uncommon,Adds +30 food resources; Restores 5 Intelligence
Energy Drink,Consumable,Rare,Reduces Cooldown by 5 min
Golden Apple,Consumable,Legendary,Adds +20 Intelligence (Permanent); Adds +100 food resources
Healing Potion,Consumable,Uncommon,Adds +20 to Health; Adds +20 food resources
Charisma Cookie,Consumable,Rare,Adds +2 Charisma (Permanent)
XP Booster,Consumable,Rare,Award +10 XP
Sleeping Draught,Consumable,Common,Reduces Cooldown for resting by 10 min
Mystery Meat,Consumable,Uncommon,Randomly ±2 to one stat (Permanent)
Elixir of Vitality,Consumable,Legendary,Fully restores all stats and health; Adds +1 Level
Leather Hat,Equipment,Common,Helmet: +5 Max Health
Wizard Hat,Equipment,Rare,Helmet: +15 Max Intelligence
Knight's Armor,Equipment,Rare,Chest: +15 Max Strength
Golden Boots,Equipment,Uncommon,Legging: +10 Max Charisma
Laser Pointer,Equipment,Common,Weapon: +5 Max Strength
Celestial Crown,Equipment,Legendary,Helmet: +20 max to all stats
Dragon Scale Shield,Equipment,Legendary,Weapon: +50 Max Health
Feathers,Material,Common, Crafting material (coming soon)
Phoenix Feather,Material,Legendary, Crafting material (coming soon)
1 Item Name Type Rarity Description
2 Basic Kibble Consumable Common Adds +20 food resources
3 Superfood Smoothie Consumable Uncommon Adds +30 food resources; Restores 5 Intelligence
4 Energy Drink Consumable Rare Reduces Cooldown by 5 min
5 Golden Apple Consumable Legendary Adds +20 Intelligence (Permanent); Adds +100 food resources
6 Healing Potion Consumable Uncommon Adds +20 to Health; Adds +20 food resources
7 Charisma Cookie Consumable Rare Adds +2 Charisma (Permanent)
8 XP Booster Consumable Rare Award +10 XP
9 Sleeping Draught Consumable Common Reduces Cooldown for resting by 10 min
10 Mystery Meat Consumable Uncommon Randomly ±2 to one stat (Permanent)
11 Elixir of Vitality Consumable Legendary Fully restores all stats and health; Adds +1 Level
12 Leather Hat Equipment Common Helmet: +5 Max Health
13 Wizard Hat Equipment Rare Helmet: +15 Max Intelligence
14 Knight's Armor Equipment Rare Chest: +15 Max Strength
15 Golden Boots Equipment Uncommon Legging: +10 Max Charisma
16 Laser Pointer Equipment Common Weapon: +5 Max Strength
17 Celestial Crown Equipment Legendary Helmet: +20 max to all stats
18 Dragon Scale Shield Equipment Legendary Weapon: +50 Max Health
19 Feathers Material Common Crafting material (coming soon)
20 Phoenix Feather Material Legendary Crafting material (coming soon)

@ -4,11 +4,11 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using pet_companion_api.Data;
using Pet.Companion.Data;
#nullable disable
namespace pet_companion_api.Migrations
namespace Pet.Companion.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20250201173643_Initial")]
@ -20,7 +20,7 @@ namespace pet_companion_api.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.1");
modelBuilder.Entity("pet_companion_api.Models.Pet", b =>
modelBuilder.Entity("Pet.Companion.Models.Pet", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
@ -59,7 +59,7 @@ namespace pet_companion_api.Migrations
b.ToTable("Pets");
});
modelBuilder.Entity("pet_companion_api.Models.PetStats", b =>
modelBuilder.Entity("Pet.Companion.Models.PetStats", b =>
{
b.Property<string>("PetId")
.HasColumnType("TEXT");
@ -87,7 +87,7 @@ namespace pet_companion_api.Migrations
b.ToTable("PetStats");
});
modelBuilder.Entity("pet_companion_api.Models.Resources", b =>
modelBuilder.Entity("Pet.Companion.Models.Resources", b =>
{
b.Property<string>("PetId")
.HasColumnType("TEXT");
@ -109,25 +109,25 @@ namespace pet_companion_api.Migrations
b.ToTable("Resources");
});
modelBuilder.Entity("pet_companion_api.Models.PetStats", b =>
modelBuilder.Entity("Pet.Companion.Models.PetStats", b =>
{
b.HasOne("pet_companion_api.Models.Pet", null)
b.HasOne("Pet.Companion.Models.Pet", null)
.WithOne("Stats")
.HasForeignKey("pet_companion_api.Models.PetStats", "PetId")
.HasForeignKey("Pet.Companion.Models.PetStats", "PetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("pet_companion_api.Models.Resources", b =>
modelBuilder.Entity("Pet.Companion.Models.Resources", b =>
{
b.HasOne("pet_companion_api.Models.Pet", null)
b.HasOne("Pet.Companion.Models.Pet", null)
.WithOne("Resources")
.HasForeignKey("pet_companion_api.Models.Resources", "PetId")
.HasForeignKey("Pet.Companion.Models.Resources", "PetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("pet_companion_api.Models.Pet", b =>
modelBuilder.Entity("Pet.Companion.Models.Pet", b =>
{
b.Navigation("Resources")
.IsRequired();

@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace pet_companion_api.Migrations
namespace Pet.Companion.Migrations
{
/// <inheritdoc />
public partial class Initial : Migration

@ -3,11 +3,11 @@ using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using pet_companion_api.Data;
using Pet.Companion.Data;
#nullable disable
namespace pet_companion_api.Migrations
namespace Pet.Companion.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
@ -17,7 +17,7 @@ namespace pet_companion_api.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.1");
modelBuilder.Entity("pet_companion_api.Models.Pet", b =>
modelBuilder.Entity("Pet.Companion.Models.Pet", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
@ -56,7 +56,7 @@ namespace pet_companion_api.Migrations
b.ToTable("Pets");
});
modelBuilder.Entity("pet_companion_api.Models.PetStats", b =>
modelBuilder.Entity("Pet.Companion.Models.PetStats", b =>
{
b.Property<string>("PetId")
.HasColumnType("TEXT");
@ -84,7 +84,7 @@ namespace pet_companion_api.Migrations
b.ToTable("PetStats");
});
modelBuilder.Entity("pet_companion_api.Models.Resources", b =>
modelBuilder.Entity("Pet.Companion.Models.Resources", b =>
{
b.Property<string>("PetId")
.HasColumnType("TEXT");
@ -106,25 +106,25 @@ namespace pet_companion_api.Migrations
b.ToTable("Resources");
});
modelBuilder.Entity("pet_companion_api.Models.PetStats", b =>
modelBuilder.Entity("Pet.Companion.Models.PetStats", b =>
{
b.HasOne("pet_companion_api.Models.Pet", null)
b.HasOne("Pet.Companion.Models.Pet", null)
.WithOne("Stats")
.HasForeignKey("pet_companion_api.Models.PetStats", "PetId")
.HasForeignKey("Pet.Companion.Models.PetStats", "PetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("pet_companion_api.Models.Resources", b =>
modelBuilder.Entity("Pet.Companion.Models.Resources", b =>
{
b.HasOne("pet_companion_api.Models.Pet", null)
b.HasOne("Pet.Companion.Models.Pet", null)
.WithOne("Resources")
.HasForeignKey("pet_companion_api.Models.Resources", "PetId")
.HasForeignKey("Pet.Companion.Models.Resources", "PetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("pet_companion_api.Models.Pet", b =>
modelBuilder.Entity("Pet.Companion.Models.Pet", b =>
{
b.Navigation("Resources")
.IsRequired();

25
Models/Enums/ItemEnums.cs Normal file

@ -0,0 +1,25 @@
namespace Pet.Companion.Models.Enums
{
public enum ItemType
{
Consumable,
Equipment,
Material
}
public enum ItemRarity
{
Common,
Uncommon,
Rare,
Legendary
}
public enum EquipmentSlot
{
Helmet,
Chest,
Leggings,
Weapon
}
}

79
Models/GameItems.cs Normal file

@ -0,0 +1,79 @@
using Pet.Companion.Models.Enums;
namespace Pet.Companion.Models
{
public class MaterialItem : Item
{
public MaterialItem()
{
Type = ItemType.Material;
}
public override void Use(ref Pet pet)
{
// Materials cannot be used directly
}
}
public class StatBoostEquipment : EquipableItem
{
public Dictionary<string, int> StatBoosts { get; set; } = new();
public override void Equip(ref Pet pet)
{
base.Equip(ref pet);
if (IsEquipped)
{
foreach (var boost in StatBoosts)
{
switch (boost.Key.ToLower())
{
case "health":
pet.MaxHealth += boost.Value;
break;
case "intelligence":
pet.Stats.MaxIntelligence += boost.Value;
break;
case "strength":
pet.Stats.MaxStrength += boost.Value;
break;
case "charisma":
pet.Stats.MaxCharisma += boost.Value;
break;
}
}
}
}
public override void Unequip(ref Pet pet)
{
if (IsEquipped)
{
foreach (var boost in StatBoosts)
{
switch (boost.Key.ToLower())
{
case "health":
pet.MaxHealth -= boost.Value;
break;
case "intelligence":
pet.Stats.MaxIntelligence -= boost.Value;
break;
case "strength":
pet.Stats.MaxStrength -= boost.Value;
break;
case "charisma":
pet.Stats.MaxCharisma -= boost.Value;
break;
}
}
}
base.Unequip(ref pet);
}
public override void Use(ref Pet pet)
{
Equip(ref pet);
}
}
}

28
Models/Inventory.cs Normal file

@ -0,0 +1,28 @@
namespace Pet.Companion.Models
{
public class Inventory
{
public List<Item> Items { get; set; } = new();
public int Capacity { get; set; }
public bool AddItem(Item item)
{
if (Items.Count < Capacity)
{
Items.Add(item);
return true;
}
return false;
}
public bool RemoveItem(Item item)
{
return Items.Remove(item);
}
public void TrashItem(Item item)
{
RemoveItem(item);
}
}
}

50
Models/Item.cs Normal file

@ -0,0 +1,50 @@
using Pet.Companion.Models.Enums;
namespace Pet.Companion.Models
{
public abstract class Item
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ItemType Type { get; set; }
public ItemRarity Rarity { get; set; }
public abstract void Use(ref Pet pet);
}
public abstract class EquipableItem : Item
{
public EquipmentSlot Slot { get; set; }
public bool IsEquipped { get; set; }
public virtual void Equip(ref Pet pet)
{
if (!IsEquipped)
{
pet.Equipment[Slot]?.Unequip(ref pet);
pet.Equipment[Slot] = this;
IsEquipped = true;
}
}
public virtual void Unequip(ref Pet pet)
{
if (IsEquipped)
{
pet.Equipment[Slot] = null;
IsEquipped = false;
}
}
}
public class ConsumableItem : Item
{
public Action<Pet> Effect { get; set; }
public override void Use(ref Pet pet)
{
Effect?.Invoke(pet);
}
}
}

@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
using Pet.Companion.Models.Enums;
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public class Pet
{
@ -10,7 +11,11 @@ namespace pet_companion_api.Models
public PetClass Class { get; set; }
public PetStats Stats { get; set; }
public Resources Resources { get; set; }
public Inventory Inventory { get; set; }
public int Level { get; set; }
public int Experience { get; set; }
public int Health { get; set; }
public int MaxHealth { get; set; }
public string UserId { get; set; }
public bool IsDead { get; set; }
@ -20,6 +25,16 @@ namespace pet_companion_api.Models
public PetBasicAction PetBasicAction { get; set; }
public DateTime BasicActionCooldown { get; set; }
public Dictionary<EquipmentSlot, EquipableItem> Equipment { get; set; } = new();
public Pet()
{
foreach (EquipmentSlot slot in Enum.GetValues(typeof(EquipmentSlot)))
{
Equipment[slot] = null;
}
}
public void IncrementIntelligence(int amount)
{
var newValue = Stats.Intelligence + amount;

@ -1,4 +1,4 @@
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public enum PetBasicAction
{

@ -1,4 +1,4 @@
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public enum PetClass
{

@ -1,5 +1,5 @@
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public class PetClassInfo
{

@ -1,4 +1,4 @@
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public class PetCreationRequest
{

@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public class PetStats
{

@ -1,4 +1,4 @@
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public class PetUpdateActionRequest
{

@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace pet_companion_api.Models
namespace Pet.Companion.Models
{
public class Resources
{

@ -1,10 +1,10 @@
using Microsoft.EntityFrameworkCore;
using pet_companion_api.Data;
using pet_companion_api.Repositories;
using pet_companion_api.Services;
using Pet.Companion.Data;
using Pet.Companion.Repositories;
using Pet.Companion.Services;
using System.Text.Json.Serialization;
namespace pet_companion_api
namespace Pet.Companion
{
public class Program
{

@ -1,42 +1,29 @@
# Database Setup and Migration Guide
# Pet Companion
## Prerequisites
- .NET 8.0 SDK
- Entity Framework Core tools
## Todo:
- [ ] Inventory system
- [ ] Skill tree system
- [ ] Explore system
- [ ] Battle system
- [ ] Quest system
- [ ] User login/register system
- [ ] User profile/settings system
- [ ] Front-End: 3D pet model
- [ ] Front-End: 3D pet animations
- [ ] Front-End: 3D pet interactions
- [ ] Front-End: 3D pet environment (depending on the class)
## Install EF Core Tools
```sh
dotnet tool install --global dotnet-ef
```
## Inventory system
- [ ] Inventory UI
- [ ] Inventory database
- [ ] Inventory item database (items, consumables, equipment)
- [ ] Inventory item interactions (use, equip, unequip, drop)
- [ ] Inventory item stacking
- [ ] Inventory item sorting (UI)
### Creating and Updating Database
1. Create initial migration:
dotnet ef migrations add InitialCreate
2. Apply migrations to create/update database:
dotnet ef database update
### Common Commands
1. Create new migration:
dotnet ef migrations add <MigrationName>
2. Remove last migration:
dotnet ef migrations remove
3. Apply migrations to create/update database:
dotnet ef database update
4. Revert last migration:
dotnet ef database update <MigrationName>
5. List all migrations:
dotnet ef migrations list
6. Script migration:
dotnet ef migrations script
7. Remove all migrations:
dotnet ef migrations remove
8. Drop database:
dotnet ef database drop
## Skill tree system
- [ ] Skill tree UI
- [ ] Skill tree database
- [ ] Skill tree interactions (learn, unlearn, upgrade)
- [ ] Skill tree requirements (level, skill points, other skills)
- [ ] Skill tree effects (TBD)

@ -0,0 +1,121 @@
using System.Text.RegularExpressions;
using Pet.Companion.Models;
using Pet.Companion.Models.Enums;
namespace Pet.Companion.Repositories
{
public class ItemRepository
{
private readonly Dictionary<string, Item> _itemTemplates = new();
public ItemRepository()
{
LoadItemsFromCsv();
}
private void LoadItemsFromCsv()
{
var lines = File.ReadAllLines("Items.csv").Skip(1); // Skip header
foreach (var line in lines)
{
var parts = line.Split(',');
var name = parts[0];
var type = Enum.Parse<ItemType>(parts[1]);
var rarity = Enum.Parse<ItemRarity>(parts[2]);
var description = parts[3];
Item item = type switch
{
ItemType.Consumable => CreateConsumableItem(name, description, rarity),
ItemType.Equipment => CreateEquipmentItem(name, description, rarity),
ItemType.Material => CreateMaterialItem(name, description, rarity),
_ => throw new ArgumentException($"Unknown item type: {type}")
};
_itemTemplates.Add(name, item);
}
}
private Item CreateConsumableItem(string name, string description, ItemRarity rarity)
{
var item = new ConsumableItem
{
Id = Guid.NewGuid().ToString(),
Name = name,
Description = description,
Type = ItemType.Consumable,
Rarity = rarity
};
// Parse effects from description
if (description.Contains("food resources"))
{
var foodAmount = int.Parse(Regex.Match(description, @"\+(\d+) food").Groups[1].Value);
item.Effect = (pet) => pet.Resources.Food += foodAmount;
}
else if (description.Contains("Intelligence"))
{
var amount = int.Parse(Regex.Match(description, @"\+(\d+)").Groups[1].Value);
item.Effect = (pet) => pet.IncrementIntelligence(amount);
}
// Add more effect parsing as needed
return item;
}
private Item CreateEquipmentItem(string name, string description, ItemRarity rarity)
{
var equipment = new StatBoostEquipment
{
Id = Guid.NewGuid().ToString(),
Name = name,
Description = description,
Type = ItemType.Equipment,
Rarity = rarity
};
// Parse slot and stats from description
var slotMatch = Regex.Match(description, @"(Helmet|Chest|Legging|Weapon):");
if (slotMatch.Success)
{
equipment.Slot = Enum.Parse<EquipmentSlot>(slotMatch.Groups[1].Value);
}
var statMatch = Regex.Match(description, @"\+(\d+) Max (\w+)");
if (statMatch.Success)
{
var amount = int.Parse(statMatch.Groups[1].Value);
var stat = statMatch.Groups[2].Value;
equipment.StatBoosts.Add(stat, amount);
}
return equipment;
}
private Item CreateMaterialItem(string name, string description, ItemRarity rarity)
{
return new MaterialItem
{
Id = Guid.NewGuid().ToString(),
Name = name,
Description = description,
Type = ItemType.Material,
Rarity = rarity
};
}
public Item CreateItem(string itemName)
{
if (_itemTemplates.TryGetValue(itemName, out var template))
{
// Create a new instance with a new ID but same properties
var json = System.Text.Json.JsonSerializer.Serialize(template);
var newItem = System.Text.Json.JsonSerializer.Deserialize<Item>(json);
newItem.Id = Guid.NewGuid().ToString();
return newItem;
}
throw new KeyNotFoundException($"Item template not found: {itemName}");
}
}
}

@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using pet_companion_api.Data;
using pet_companion_api.Models;
using Pet.Companion.Data;
using Pet.Companion.Models;
namespace pet_companion_api.Repositories
namespace Pet.Companion.Repositories
{
public class PetClassRepository
{

@ -1,8 +1,8 @@
using Microsoft.EntityFrameworkCore;
using pet_companion_api.Data;
using pet_companion_api.Models;
using Pet.Companion.Data;
using Pet.Companion.Models;
namespace pet_companion_api.Repositories
namespace Pet.Companion.Repositories
{
public class PetRepository
{

@ -1,7 +1,7 @@
using pet_companion_api.Models;
using pet_companion_api.Repositories;
using Pet.Companion.Models;
using Pet.Companion.Repositories;
namespace pet_companion_api.Services
namespace Pet.Companion.Services
{
public class PetClassService
{

@ -1,7 +1,7 @@
using pet_companion_api.Models;
using pet_companion_api.Repositories;
using Pet.Companion.Models;
using Pet.Companion.Repositories;
namespace pet_companion_api.Services
namespace Pet.Companion.Services
{
public class PetService
{
@ -64,10 +64,12 @@ namespace pet_companion_api.Services
case PetBasicAction.FEED:
pet.Resources.Food -= 1;
pet.IncrementStrength(1);
pet.Health = Math.Min(pet.Health + 5, 100);
break;
case PetBasicAction.SLEEP:
pet.IncrementIntelligence(1);
pet.IncrementStrength(1);
pet.Health = Math.Min(pet.Health + 15, Pet.MaxHealth);
break;
case PetBasicAction.PLAY:
pet.Resources.Junk -= 1;

@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>pet_companion_api</RootNamespace>
<RootNamespace>Pet.Companion</RootNamespace>
<UserSecretsId>fb7dfb2a-4bb7-4cd0-bc10-293410089f4b</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>