Fin tutoriel

master
Baptiste MARCEL 2 years ago
parent 47ed6f7af1
commit ebf9bc75b9

@ -5,6 +5,8 @@ VisualStudioVersion = 17.3.32929.385
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorProject", "BlazorProject\BlazorProject.csproj", "{826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorProject", "BlazorProject\BlazorProject.csproj", "{826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Minecraft.Crafting.Api", "Minecraft.Crafting.Api\Minecraft.Crafting.Api.csproj", "{54CA5D3A-4F3B-4D06-95E6-0D55346E9AC9}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -15,6 +17,10 @@ Global
{826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}.Release|Any CPU.Build.0 = Release|Any CPU {826FD9F1-4474-41B8-AEFB-8CDF2A5CD4FB}.Release|Any CPU.Build.0 = Release|Any CPU
{54CA5D3A-4F3B-4D06-95E6-0D55346E9AC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54CA5D3A-4F3B-4D06-95E6-0D55346E9AC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54CA5D3A-4F3B-4D06-95E6-0D55346E9AC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54CA5D3A-4F3B-4D06-95E6-0D55346E9AC9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

@ -0,0 +1,6 @@
@typeparam TItem
<div class="card text-center">
@CardHeader(Item)
@CardBody(Item)
@CardFooter
</div>

@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Components;
namespace BlazorProject.Components
{
public partial class Card<TItem>
{
[Parameter]
public RenderFragment<TItem> CardBody { get; set; }
[Parameter]
public RenderFragment CardFooter { get; set; }
[Parameter]
public RenderFragment<TItem> CardHeader { get; set; }
[Parameter]
public TItem Item { get; set; }
}
}

@ -0,0 +1,50 @@
<CascadingValue Value="@this">
<div class="container">
<div class="row">
<div class="col-6">
<div>Available items:</div>
<div>
<div class="css-grid">
@foreach (var item in Items)
{
<CraftingItem Item="item" NoDrop="true" />
}
</div>
</div>
</div>
<div class="col-6">
<div>Recipe</div>
<div>
<div class="css-recipe">
<CraftingItem Index="0" />
<CraftingItem Index="1" />
<CraftingItem Index="2" />
<CraftingItem Index="3" />
<CraftingItem Index="4" />
<CraftingItem Index="5" />
<CraftingItem Index="6" />
<CraftingItem Index="7" />
<CraftingItem Index="8" />
</div>
</div>
<div>Result</div>
<div>
<CraftingItem Item="RecipeResult" />
</div>
</div>
<div class="col-12">
<div>Actions</div>
<div class="actions" id="actions">
</div>
</div>
</div>
</div>
</CascadingValue>

@ -0,0 +1,80 @@
using BlazorProject.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace BlazorProject.Components
{
public partial class Crafting
{
private Item _recipeResult;
public Crafting()
{
Actions = new ObservableCollection<CraftingAction>();
Actions.CollectionChanged += OnActionsCollectionChanged;
this.RecipeItems = new List<Item> { null, null, null, null, null, null, null, null, null };
}
public ObservableCollection<CraftingAction> Actions { get; set; }
public Item CurrentDragItem { get; set; }
[Parameter]
public List<Item> Items { get; set; }
public List<Item> RecipeItems { get; set; }
public Item RecipeResult
{
get => this._recipeResult;
set
{
if (this._recipeResult == value)
{
return;
}
this._recipeResult = value;
this.StateHasChanged();
}
}
[Parameter]
public List<CraftingRecipe> Recipes { get; set; }
/// <summary>
/// Gets or sets the java script runtime.
/// </summary>
[Inject]
internal IJSRuntime JavaScriptRuntime { get; set; }
public void CheckRecipe()
{
RecipeResult = null;
// Get the current model
var currentModel = string.Join("|", this.RecipeItems.Select(s => s != null ? s.Name : string.Empty));
this.Actions.Add(new CraftingAction { Action = $"Items : {currentModel}" });
foreach (var craftingRecipe in Recipes)
{
// Get the recipe model
var recipeModel = string.Join("|", craftingRecipe.Have.SelectMany(s => s));
this.Actions.Add(new CraftingAction { Action = $"Recipe model : {recipeModel}" });
if (currentModel == recipeModel)
{
RecipeResult = craftingRecipe.Give;
}
}
}
private void OnActionsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
JavaScriptRuntime.InvokeVoidAsync("Crafting.AddActions", e.NewItems);
}
}
}

@ -0,0 +1,19 @@
.css-grid {
grid-template-columns: repeat(4,minmax(0,1fr));
gap: 10px;
display: grid;
width: 286px;
}
.css-recipe {
grid-template-columns: repeat(3,minmax(0,1fr));
gap: 10px;
display: grid;
width: 212px;
}
.actions {
border: 1px solid black;
height: 250px;
overflow: scroll;
}

@ -0,0 +1,16 @@
window.Crafting =
{
AddActions: function (data) {
data.forEach(element => {
var div = document.createElement('div');
div.innerHTML = 'Action: ' + element.action + ' - Index: ' + element.index;
if (element.item) {
div.innerHTML += ' - Item Name: ' + element.item.name;
}
document.getElementById('actions').appendChild(div);
});
}
}

@ -0,0 +1,11 @@
using BlazorProject.Models;
namespace BlazorProject.Components
{
public class CraftingAction
{
public string Action { get; set; }
public int Index { get; set; }
public Item Item { get; set; }
}
}

@ -0,0 +1,13 @@
<div class="item"
ondragover="event.preventDefault();"
draggable="true"
@ondragstart="@OnDragStart"
@ondrop="@OnDrop"
@ondragenter="@OnDragEnter"
@ondragleave="@OnDragLeave">
@if (Item != null)
{
@Item.DisplayName
}
</div>

@ -0,0 +1,64 @@
using Blazorise;
using BlazorProject.Models;
using Microsoft.AspNetCore.Components;
namespace BlazorProject.Components
{
public partial class CraftingItem
{
[Parameter]
public int Index { get; set; }
[Parameter]
public Item Item { get; set; }
[Parameter]
public bool NoDrop { get; set; }
[CascadingParameter]
public Crafting Parent { get; set; }
internal void OnDragEnter()
{
if (NoDrop)
{
return;
}
Parent.Actions.Add(new CraftingAction { Action = "Drag Enter", Item = this.Item, Index = this.Index });
}
internal void OnDragLeave()
{
if (NoDrop)
{
return;
}
Parent.Actions.Add(new CraftingAction { Action = "Drag Leave", Item = this.Item, Index = this.Index });
}
internal void OnDrop()
{
if (NoDrop)
{
return;
}
this.Item = Parent.CurrentDragItem;
Parent.RecipeItems[this.Index] = this.Item;
Parent.Actions.Add(new CraftingAction { Action = "Drop", Item = this.Item, Index = this.Index });
// Check recipe
Parent.CheckRecipe();
}
private void OnDragStart()
{
Parent.CurrentDragItem = this.Item;
Parent.Actions.Add(new CraftingAction { Action = "Drag Start", Item = this.Item, Index = this.Index });
}
}
}

@ -0,0 +1,6 @@
.item {
width: 64px;
height: 64px;
border: 1px solid;
overflow: hidden;
}

@ -0,0 +1,10 @@
using BlazorProject.Models;
namespace BlazorProject.Components
{
public class CraftingRecipe
{
public Item Give { get; set; }
public List<List<string>> Have { get; set; }
}
}

@ -0,0 +1,12 @@
@typeparam TItem
<div>
@if ((Items?.Count ?? 0) != 0)
{
@foreach (var item in Items)
{
@ShowTemplate(item)
;
}
}
</div>

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Components;
namespace BlazorProject.Components
{
public partial class ShowItems<TItem>
{
[Parameter]
public List<TItem> Items { get; set; }
[Parameter]
public RenderFragment<TItem> ShowTemplate { get; set; }
}
}

@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
/// <summary>
/// The culture controller.
/// </summary>
[Route("[controller]/[action]")]
public class CultureController : Controller
{
/// <summary>
/// Sets the culture.
/// </summary>
/// <param name="culture">The culture.</param>
/// <param name="redirectUri">The redirect URI.</param>
/// <returns>
/// The action result.
/// </returns>
public IActionResult SetCulture(string culture, string redirectUri)
{
if (culture != null)
{
// Define a cookie with the selected culture
this.HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture)));
}
return this.LocalRedirect(redirectUri);
}
}

@ -15,7 +15,8 @@ namespace BlazorProject.Factories
EnchantCategories = item.EnchantCategories, EnchantCategories = item.EnchantCategories,
MaxDurability = item.MaxDurability, MaxDurability = item.MaxDurability,
StackSize = item.StackSize, StackSize = item.StackSize,
ImageContent = imageContent ImageContent = imageContent,
ImageBase64 = string.IsNullOrWhiteSpace(item.ImageBase64) ? Convert.ToBase64String(imageContent) : item.ImageBase64
}; };
} }
@ -30,7 +31,8 @@ namespace BlazorProject.Factories
EnchantCategories = model.EnchantCategories, EnchantCategories = model.EnchantCategories,
MaxDurability = model.MaxDurability, MaxDurability = model.MaxDurability,
StackSize = model.StackSize, StackSize = model.StackSize,
CreatedDate = DateTime.Now CreatedDate = DateTime.Now,
ImageBase64 = Convert.ToBase64String(model.ImageContent)
}; };
} }
@ -43,6 +45,7 @@ namespace BlazorProject.Factories
item.MaxDurability = model.MaxDurability; item.MaxDurability = model.MaxDurability;
item.StackSize = model.StackSize; item.StackSize = model.StackSize;
item.UpdatedDate = DateTime.Now; item.UpdatedDate = DateTime.Now;
item.ImageBase64 = Convert.ToBase64String(model.ImageContent);
} }
} }
} }

@ -0,0 +1,9 @@
namespace BlazorProject.Models
{
public class Cake
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Cost { get; set; }
}
}

@ -11,5 +11,6 @@
public List<string> RepairWith { get; set; } public List<string> RepairWith { get; set; }
public DateTime CreatedDate { get; set; } public DateTime CreatedDate { get; set; }
public DateTime? UpdatedDate { get; set; } public DateTime? UpdatedDate { get; set; }
public string ImageBase64 { get; set; }
} }
} }

@ -33,5 +33,7 @@ namespace BlazorProject.Models
[Required(ErrorMessage = "L'image de l'item est obligatoire !")] [Required(ErrorMessage = "L'image de l'item est obligatoire !")]
public byte[] ImageContent { get; set; } public byte[] ImageContent { get; set; }
public string ImageBase64 { get; set; }
} }
} }

@ -0,0 +1,5 @@
@page "/logs"
<h3>CreateLog</h3>
<button @onclick="CreateLogs">Create logs</button>

@ -0,0 +1,21 @@
namespace BlazorProject.Pages
{
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Logging;
public partial class CreateLog
{
[Inject]
public ILogger<CreateLog> Logger { get; set; }
private void CreateLogs()
{
var logLevels = Enum.GetValues(typeof(LogLevel)).Cast<LogLevel>();
foreach (var logLevel in logLevels.Where(l => l != LogLevel.None))
{
Logger.Log(logLevel, $"Log message for the level: {logLevel}");
}
}
}
}

@ -53,19 +53,14 @@
} }
</div> </div>
</p> </p>
<p> <p>
<label> <label>
Current Item image: Current Item image:
@if (File.Exists($"{WebHostEnvironment.WebRootPath}/images/{itemModel.Name}.png")) <img src="data:image/png;base64, @(itemModel.ImageBase64)" class="img-thumbnail" title="@itemModel.DisplayName" alt="@itemModel.DisplayName" style="min-width: 50px; max-width: 150px" />
{
<img src="images/@(itemModel.Name).png" class="img-thumbnail" title="@itemModel.DisplayName" alt="@itemModel.DisplayName" style="max-width: 150px" />
}
else
{
<img src="images/default.png" class="img-thumbnail" title="@itemModel.DisplayName" alt="@itemModel.DisplayName" style="max-width: 150px" />
}
</label> </label>
</p> </p>
<p> <p>
<label> <label>
Item image: Item image:

@ -1,9 +1,21 @@
@page "/" @page "/"
@using System.Globalization
@using BlazorProject.Components;
@using BlazorProject.Models;
<PageTitle>Index</PageTitle> <PageTitle>Index</PageTitle>
<h1>Hello, world!</h1> <h1>Hello, world!</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<div>
<Crafting Items="Items" Recipes="Recipes" />
</div>
Welcome to your new app. Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" /> <SurveyPrompt Title="How is Blazor working for you?" />

@ -0,0 +1,32 @@
using BlazorProject.Components;
using BlazorProject.Models;
using BlazorProject.Services;
using Microsoft.AspNetCore.Components;
namespace BlazorProject.Pages
{
public partial class Index
{
[Inject]
public IDataService DataService { get; set; }
public List<Item> Items { get; set; } = new List<Item>();
private List<CraftingRecipe> Recipes { get; set; } = new List<CraftingRecipe>();
protected override async Task OnAfterRenderAsync(bool firstRender)
{
base.OnAfterRenderAsync(firstRender);
if (!firstRender)
{
return;
}
Items = await DataService.List(0, await DataService.Count());
Recipes = await DataService.GetRecipes();
StateHasChanged();
}
}
}

@ -19,9 +19,9 @@
<DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="#" /> <DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="#" />
<DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="Image"> <DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="Image">
<DisplayTemplate> <DisplayTemplate>
@if (File.Exists($"{WebHostEnvironment.WebRootPath}/images/{context.Name}.png")) @if (!string.IsNullOrWhiteSpace(context.ImageBase64))
{ {
<img src="images/@(context.Name).png" class="img-thumbnail" title="@context.DisplayName" alt="@context.DisplayName" style="max-width: 150px" /> <img src="data:image/png;base64, @(context.ImageBase64)" class="img-thumbnail" title="@context.DisplayName" alt="@context.DisplayName" style="min-width: 50px; max-width: 150px" />
} }
else else
{ {

@ -30,6 +30,7 @@
<script src="_framework/blazor.server.js"></script> <script src="_framework/blazor.server.js"></script>
<script src="_content/Blazored.Modal/blazored.modal.js"></script> <script src="_content/Blazored.Modal/blazored.modal.js"></script>
<script src="Components/Crafting.razor.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
<link href="_content/Blazorise/blazorise.css" rel="stylesheet" /> <link href="_content/Blazorise/blazorise.css" rel="stylesheet" />

@ -7,6 +7,9 @@ using BlazorProject.Data;
using BlazorProject.Services; using BlazorProject.Services;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Options;
using System.Globalization;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -23,10 +26,29 @@ builder.Services
builder.Services.AddBlazoredLocalStorage(); builder.Services.AddBlazoredLocalStorage();
builder.Services.AddScoped<IDataService, DataLocalService>(); builder.Services.AddScoped<IDataService, DataApiService>();
builder.Services.AddBlazoredModal(); builder.Services.AddBlazoredModal();
// Add the controller of the app
builder.Services.AddControllers();
// Add the localization to the app and specify the resources path
builder.Services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
// Configure the localtization
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
// Set the default culture of the web site
options.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"));
// Declare the supported culture
options.SupportedCultures = new List<CultureInfo> { new CultureInfo("en-US"), new CultureInfo("fr-FR") };
options.SupportedUICultures = new List<CultureInfo> { new CultureInfo("en-US"), new CultureInfo("fr-FR") };
});
builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging"));
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
@ -43,6 +65,21 @@ app.UseStaticFiles();
app.UseRouting(); app.UseRouting();
// Get the current localization options
var options = ((IApplicationBuilder)app).ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
if (options?.Value != null)
{
// use the default localization
app.UseRequestLocalization(options.Value);
}
// Add the controller to the endpoint
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.MapBlazorHub(); app.MapBlazorHub();
app.MapFallbackToPage("/_Host"); app.MapFallbackToPage("/_Host");

@ -0,0 +1,59 @@
using BlazorProject.Components;
using BlazorProject.Factories;
using BlazorProject.Models;
namespace BlazorProject.Services
{
public class DataApiService : IDataService
{
private readonly HttpClient _http;
public DataApiService(
HttpClient http)
{
_http = http;
}
public async Task Add(ItemModel model)
{
// Get the item
var item = ItemFactory.Create(model);
// Save the data
await _http.PostAsJsonAsync("https://localhost:7234/api/Crafting/", item);
}
public async Task<int> Count()
{
return await _http.GetFromJsonAsync<int>("https://localhost:7234/api/Crafting/count");
}
public async Task<List<Item>> List(int currentPage, int pageSize)
{
return await _http.GetFromJsonAsync<List<Item>>($"https://localhost:7234/api/Crafting/?currentPage={currentPage}&pageSize={pageSize}");
}
public async Task<Item> GetById(int id)
{
return await _http.GetFromJsonAsync<Item>($"https://localhost:7234/api/Crafting/{id}");
}
public async Task Update(int id, ItemModel model)
{
// Get the item
var item = ItemFactory.Create(model);
await _http.PutAsJsonAsync($"https://localhost:7234/api/Crafting/{id}", item);
}
public async Task Delete(int id)
{
await _http.DeleteAsync($"https://localhost:7234/api/Crafting/{id}");
}
public async Task<List<CraftingRecipe>> GetRecipes()
{
return await _http.GetFromJsonAsync<List<CraftingRecipe>>("https://localhost:7234/api/Crafting/recipe");
}
}
}

@ -1,4 +1,5 @@
using Blazored.LocalStorage; using Blazored.LocalStorage;
using BlazorProject.Components;
using BlazorProject.Factories; using BlazorProject.Factories;
using BlazorProject.Models; using BlazorProject.Models;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -162,5 +163,24 @@ namespace BlazorProject.Services
// Save the data // Save the data
await _localStorage.SetItemAsync("data", currentData); await _localStorage.SetItemAsync("data", currentData);
} }
public Task<List<CraftingRecipe>> GetRecipes()
{
var items = new List<CraftingRecipe>
{
new CraftingRecipe
{
Give = new Item { DisplayName = "Diamond", Name = "diamond" },
Have = new List<List<string>>
{
new List<string> { "dirt", "dirt", "dirt" },
new List<string> { "dirt", null, "dirt" },
new List<string> { "dirt", "dirt", "dirt" }
}
}
};
return Task.FromResult(items);
}
} }
} }

@ -1,4 +1,5 @@
using BlazorProject.Models; using BlazorProject.Components;
using BlazorProject.Models;
namespace BlazorProject.Services namespace BlazorProject.Services
{ {
@ -15,5 +16,7 @@ namespace BlazorProject.Services
Task Update(int id, ItemModel model); Task Update(int id, ItemModel model);
Task Delete(int id); Task Delete(int id);
Task<List<CraftingRecipe>> GetRecipes();
} }
} }

@ -0,0 +1,43 @@
@using System.Globalization
@inject NavigationManager NavigationManager
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr-FR")
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentUICulture == value)
{
return;
}
var culture = value.Name.ToLower(CultureInfo.InvariantCulture);
var uri = new Uri(this.NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var query = $"?culture={Uri.EscapeDataString(culture)}&" + $"redirectUri={Uri.EscapeDataString(uri)}";
// Redirect the user to the culture controller to set the cookie
this.NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
}
}
}

@ -10,6 +10,10 @@
<main> <main>
<div class="top-row px-4"> <div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
<div class="px-4">
<CultureSelector />
</div>
</div> </div>
<article class="content px-4"> <article class="content px-4">

@ -1,9 +1,9 @@
{ {
"DetailedErrors": true,
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning" "Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
} }
} }
} }

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

@ -0,0 +1,449 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CraftingController.cs" company="UCA Clermont-Ferrand">
// Copyright (c) UCA Clermont-Ferrand All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Minecraft.Crafting.Api.Controllers
{
using Microsoft.AspNetCore.Mvc;
using Minecraft.Crafting.Api.Models;
using System.Text.Json;
using System.Text.Json.Serialization;
/// <summary>
/// The crafting controller.
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class CraftingController : ControllerBase
{
/// <summary>
/// The json serializer options.
/// </summary>
private readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
};
/// <summary>
/// Adds the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>The async task.</returns>
[HttpPost]
[Route("")]
public Task Add(Item item)
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
data.Add(item);
System.IO.File.WriteAllText("Data/items.json", JsonSerializer.Serialize(data, _jsonSerializerOptions));
return Task.CompletedTask;
}
/// <summary>
/// Get all items.
/// </summary>
/// <returns>All items.</returns>
[HttpGet]
[Route("all")]
public Task<List<Item>> All()
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
return Task.FromResult(data.ToList());
}
/// <summary>
/// Count the number of items.
/// </summary>
/// <returns>The number of items.</returns>
[HttpGet]
[Route("count")]
public Task<int> Count()
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
return Task.FromResult(data.Count);
}
/// <summary>
/// Deletes the specified identifier.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>The async task.</returns>
[HttpDelete]
[Route("{id}")]
public Task Delete(int id)
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
var item = data.FirstOrDefault(w => w.Id == id);
if (item == null)
{
throw new Exception($"Unable to found the item with ID: {id}");
}
data.Remove(item);
System.IO.File.WriteAllText("Data/items.json", JsonSerializer.Serialize(data, _jsonSerializerOptions));
return Task.CompletedTask;
}
/// <summary>
/// Gets the item by identifier.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>The item.</returns>
[HttpGet]
[Route("{id}")]
public Task<Item> GetById(int id)
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
var item = data.FirstOrDefault(w => w.Id == id);
if (item == null)
{
throw new Exception($"Unable to found the item with ID: {id}");
}
return Task.FromResult(item);
}
/// <summary>
/// Gets the item by name.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>
/// The item.
/// </returns>
[HttpGet]
[Route("by-name/{name}")]
public Task<Item> GetByName(string name)
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
var item = data.FirstOrDefault(w => w.Name.ToLowerInvariant() == name.ToLowerInvariant());
if (item == null)
{
throw new Exception($"Unable to found the item with name: {name}");
}
return Task.FromResult(item);
}
/// <summary>
/// Gets the recipes.
/// </summary>
/// <returns>The recipes.</returns>
[HttpGet]
[Route("recipe")]
public Task<List<Recipe>> GetRecipe()
{
if (!System.IO.File.Exists("Data/convert-recipes.json"))
{
ResetRecipes();
}
var data = JsonSerializer.Deserialize<List<Recipe>>(System.IO.File.ReadAllText("Data/convert-recipes.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the recipes.");
}
return Task.FromResult(data);
}
/// <summary>
/// Get the items with pagination.
/// </summary>
/// <param name="currentPage">The current page.</param>
/// <param name="pageSize">Size of the page.</param>
/// <returns>The items.</returns>
[HttpGet]
[Route("")]
public Task<List<Item>> List(int currentPage, int pageSize)
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
return Task.FromResult(data.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList());
}
/// <summary>
/// Resets the items.
/// </summary>
/// <returns>The async task.</returns>
[HttpGet]
[Route("reset-items")]
public Task ResetItems()
{
if (!System.IO.File.Exists("Data/items.json"))
{
System.IO.File.Delete("Data/items.json");
}
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items-original.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the items.");
}
var defaultImage = Convert.ToBase64String(System.IO.File.ReadAllBytes("Images/default.png"));
var imageTranslation = new Dictionary<string, string>
{
{ "stone_slab", "smooth_stone_slab_side" },
{ "sticky_piston", "piston_top_sticky" },
{ "mob_spawner", "spawner" },
{ "chest", "chest_minecart" },
{ "stone_stairs", "stairs" },
};
foreach (var item in data)
{
var imageFilepath = defaultImage;
if (System.IO.File.Exists($"Images/{item.Name}.png"))
{
imageFilepath = Convert.ToBase64String(System.IO.File.ReadAllBytes($"Images/{item.Name}.png"));
}
if (imageFilepath == defaultImage && System.IO.File.Exists($"Images/{item.Name}_top.png"))
{
imageFilepath = Convert.ToBase64String(System.IO.File.ReadAllBytes($"Images/{item.Name}_top.png"));
}
if (imageFilepath == defaultImage && System.IO.File.Exists($"Images/{item.Name}_front.png"))
{
imageFilepath = Convert.ToBase64String(System.IO.File.ReadAllBytes($"Images/{item.Name}_front.png"));
}
if (imageFilepath == defaultImage && System.IO.File.Exists($"Images/white_{item.Name}.png"))
{
imageFilepath = Convert.ToBase64String(System.IO.File.ReadAllBytes($"Images/white_{item.Name}.png"));
}
if (imageFilepath == defaultImage && System.IO.File.Exists($"Images/oak_{item.Name}.png"))
{
imageFilepath = Convert.ToBase64String(System.IO.File.ReadAllBytes($"Images/oak_{item.Name}.png"));
}
if (imageFilepath == defaultImage && System.IO.File.Exists($"Images/{item.DisplayName.ToLower().Replace(" ", "_")}.png"))
{
imageFilepath = Convert.ToBase64String(System.IO.File.ReadAllBytes($"Images/{item.DisplayName.ToLower().Replace(" ", "_")}.png"));
}
if (imageFilepath == defaultImage && imageTranslation.ContainsKey(item.Name))
{
imageFilepath = Convert.ToBase64String(System.IO.File.ReadAllBytes($"Images/{imageTranslation[item.Name]}.png"));
}
item.ImageBase64 = imageFilepath;
}
System.IO.File.WriteAllText("Data/items.json", JsonSerializer.Serialize(data, _jsonSerializerOptions));
return Task.FromResult(data);
}
/// <summary>
/// Resets the recipes.
/// </summary>
/// <returns>The async task.</returns>
[HttpGet]
[Route("reset-recipes")]
public Task ResetRecipes()
{
if (!System.IO.File.Exists("Data/convert-recipes.json"))
{
System.IO.File.Delete("Data/convert-recipes.json");
}
ConvertRecipes();
return Task.CompletedTask;
}
/// <summary>
/// Updates the specified identifier.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="item">The item.</param>
/// <returns>The async task.</returns>
[HttpPut]
[Route("{id}")]
public Task Update(int id, Item item)
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
var itemOriginal = data?.FirstOrDefault(w => w.Id == id);
if (itemOriginal == null)
{
throw new Exception($"Unable to found the item with ID: {id}");
}
itemOriginal.Id = item.Id;
itemOriginal.Name = item.Name;
itemOriginal.CreatedDate = item.CreatedDate;
itemOriginal.DisplayName = item.DisplayName;
itemOriginal.EnchantCategories = item.EnchantCategories;
itemOriginal.MaxDurability = item.MaxDurability;
itemOriginal.RepairWith = item.RepairWith;
itemOriginal.StackSize = item.StackSize;
itemOriginal.UpdatedDate = item.UpdatedDate;
System.IO.File.WriteAllText("Data/items.json", JsonSerializer.Serialize(data, _jsonSerializerOptions));
return Task.CompletedTask;
}
/// <summary>
/// Gets the name of the item.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="inShape">The in shape.</param>
/// <param name="line">The line.</param>
/// <param name="row">The row.</param>
/// <returns>The name of the item.</returns>
private static string GetItemName(List<Item> items, InShape[][] inShape, int line, int row)
{
if (inShape.Length < line + 1)
{
return null;
}
if (inShape[line].Length < row + 1)
{
return null;
}
var id = inShape[line][row].Integer ?? inShape[line][row].IngredientClass?.Id;
if (id == null)
{
return null;
}
return GetItemName(items, id.Value);
}
/// <summary>
/// Gets the name of the item.
/// </summary>
/// <param name="items">The items.</param>
/// <param name="id">The identifier.</param>
/// <returns>The name of the item.</returns>
private static string GetItemName(List<Item> items, long id)
{
var item = items.FirstOrDefault(w => w.Id == id);
return item?.Name;
}
/// <summary>
/// Converts the recipes.
/// </summary>
private void ConvertRecipes()
{
var data = JsonSerializer.Deserialize<List<Item>>(System.IO.File.ReadAllText("Data/items.json"), _jsonSerializerOptions);
if (data == null)
{
return;
}
var recipes = Recipes.FromJson(System.IO.File.ReadAllText("Data/recipes.json"));
var items = new List<Recipe>();
foreach (var recipe in recipes.SelectMany(s => s.Value))
{
if (recipe.InShape == null)
{
continue;
}
var giveItem = data.FirstOrDefault(w => w.Id == recipe.Result.Id);
if (giveItem == null)
{
continue;
}
items.Add(new Recipe
{
Give = giveItem,
Have = new List<List<string>>
{
new()
{
GetItemName(data, recipe.InShape, 0, 0),
GetItemName(data, recipe.InShape, 0, 1),
GetItemName(data, recipe.InShape, 0, 2)
},
new()
{
GetItemName(data, recipe.InShape, 1, 0),
GetItemName(data, recipe.InShape, 1, 1),
GetItemName(data, recipe.InShape, 1, 2)
},
new()
{
GetItemName(data, recipe.InShape, 2, 0),
GetItemName(data, recipe.InShape, 2, 1),
GetItemName(data, recipe.InShape, 2, 2)
}
}
});
}
System.IO.File.WriteAllText("Data/convert-recipes.json", JsonSerializer.Serialize(items, _jsonSerializerOptions));
}
}
}

@ -0,0 +1,143 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="InventoryController.cs" company="UCA Clermont-Ferrand">
// Copyright (c) UCA Clermont-Ferrand All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Minecraft.Crafting.Api.Controllers
{
using Microsoft.AspNetCore.Mvc;
using Minecraft.Crafting.Api.Models;
using System.Text.Json;
using System.Text.Json.Serialization;
/// <summary>
/// The inventory controller.
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class InventoryController : ControllerBase
{
/// <summary>
/// The json serializer options.
/// </summary>
private readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
};
/// <summary>
/// Adds to inventory.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>The async task.</returns>
[HttpPost]
[Route("")]
public Task AddToInventory(InventoryModel item)
{
var data = JsonSerializer.Deserialize<List<InventoryModel>>(System.IO.File.ReadAllText("Data/inventory.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the inventory.");
}
data.Add(item);
System.IO.File.WriteAllText("Data/inventory.json", JsonSerializer.Serialize(data, _jsonSerializerOptions));
return Task.CompletedTask;
}
/// <summary>
/// Deletes from inventory.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>The async task.</returns>
[HttpDelete]
[Route("")]
public Task DeleteFromInventory(InventoryModel item)
{
if (!System.IO.File.Exists("Data/inventory.json"))
{
throw new Exception($"Unable to found the item with name: {item.ItemName}");
}
var data = JsonSerializer.Deserialize<List<InventoryModel>>(System.IO.File.ReadAllText("Data/inventory.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the inventory.");
}
var inventoryItem = data.FirstOrDefault(w => w.ItemName == item.ItemName && w.Position == item.Position);
if (inventoryItem == null)
{
throw new Exception($"Unable to found the item with name: {item.ItemName} at position: {item.Position}");
}
data.Remove(inventoryItem);
System.IO.File.WriteAllText("Data/inventory.json", JsonSerializer.Serialize(data, _jsonSerializerOptions));
return Task.CompletedTask;
}
/// <summary>
/// Gets the inventory.
/// </summary>
/// <returns>The inventory.</returns>
[HttpGet]
[Route("")]
public Task<List<InventoryModel>> GetInventory()
{
if (!System.IO.File.Exists("Data/inventory.json"))
{
return Task.FromResult(new List<InventoryModel>());
}
var data = JsonSerializer.Deserialize<List<InventoryModel>>(System.IO.File.ReadAllText("Data/inventory.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the inventory.");
}
return Task.FromResult(data);
}
/// <summary>
/// Updates the inventory.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>The async task.</returns>
[HttpPut]
[Route("")]
public Task UpdateInventory(InventoryModel item)
{
var data = JsonSerializer.Deserialize<List<InventoryModel>>(System.IO.File.ReadAllText("Data/inventory.json"), _jsonSerializerOptions);
if (data == null)
{
throw new Exception("Unable to get the inventory.");
}
var inventoryItem = data.FirstOrDefault(w => w.ItemName == item.ItemName && w.Position == item.Position);
if (inventoryItem == null)
{
throw new Exception($"Unable to found the item with name: {item.ItemName} at position: {item.Position}");
}
inventoryItem.ItemName = item.ItemName;
inventoryItem.Position = item.Position;
System.IO.File.WriteAllText("Data/inventory.json", JsonSerializer.Serialize(data, _jsonSerializerOptions));
return Task.CompletedTask;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,20 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["src/Minecraft.Crafting.Api/Minecraft.Crafting.Api.csproj", "Minecraft.Crafting.Api/"]
RUN dotnet restore "Minecraft.Crafting.Api/Minecraft.Crafting.Api.csproj"
COPY src/. .
WORKDIR "/src/Minecraft.Crafting.Api"
RUN dotnet build "Minecraft.Crafting.Api.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Minecraft.Crafting.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Minecraft.Crafting.Api.dll"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save