Skip to content

Commit bc6ab95

Browse files
committed
Upgrade packages, add Genshincards renderer, refactor
Upgraded package versions in `Directory.Packages.props`, including `Aspire.Hosting.AppHost` and `Microsoft.EntityFrameworkCore.Design`. Added `SkiaSharp.HarfBuzz` dependency. Introduced `GenshincardsDeckImageCreator` for rendering decks with SkiaSharp, supporting role cards, action cards, and multi-deck layouts. Added `GenshincardsDeckImageOptions` for configuration. Refactored `UpdateEmojisSlashCommand.cs` to improve emoji existence checks and simplify upload logic. Simplified `ImageCacheServiceExtension.cs` methods and improved variable naming. Enhanced `SkAssetsUtils.cs` with utility methods for loading fonts and typefaces. Added `ElementColors.cs`, `SkillElementExtension.cs`, and `SkillElements.cs` for managing skill element colors and icons. Updated `Dockerfile` to include new project references. General cleanup and refactoring to improve readability, maintainability, and consistency.
1 parent c57939d commit bc6ab95

15 files changed

Lines changed: 873 additions & 58 deletions

Directory.Packages.props

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
55
<ItemGroup>
6-
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.4.1" />
7-
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="9.4.1" />
8-
<PackageVersion Include="Aspire.Hosting.Redis" Version="9.4.1" />
9-
<PackageVersion Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.4.0" />
10-
<PackageVersion Include="Aspire.StackExchange.Redis.DistributedCaching" Version="9.4.0" />
11-
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.8" />
12-
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="9.8.0" />
13-
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.8.0" />
14-
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.4.1" />
6+
<PackageVersion Include="Aspire.Hosting.AppHost" Version="9.4.2" />
7+
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="9.4.2" />
8+
<PackageVersion Include="Aspire.Hosting.Redis" Version="9.4.2" />
9+
<PackageVersion Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.4.2" />
10+
<PackageVersion Include="Aspire.StackExchange.Redis.DistributedCaching" Version="9.4.2" />
11+
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.9" />
12+
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="9.9.0" />
13+
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="9.9.0" />
14+
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="9.4.2" />
1515
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
1616
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
1717
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
@@ -20,11 +20,12 @@
2020
<PackageVersion Include="OpenTelemetry.Instrumentation.Runtime" Version="1.12.0" />
2121
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.11" />
2222
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
23-
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.8" />
24-
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.8" />
25-
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.8" />
23+
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.9" />
24+
<PackageVersion Include="Microsoft.Extensions.Http" Version="9.0.9" />
25+
<PackageVersion Include="Microsoft.AspNetCore.WebUtilities" Version="9.0.9" />
2626
<PackageVersion Include="NetCord.Hosting.Services" Version="1.0.0-alpha.410" />
2727
<PackageVersion Include="SkiaSharp" Version="3.119.0" />
28+
<PackageVersion Include="SkiaSharp.HarfBuzz" Version="3.119.0" />
2829
<PackageVersion Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.0" />
2930
</ItemGroup>
3031
</Project>

src/GitcgNetCord.MainApp/Commands/Slash/UpdateEmojisSlashCommand.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using GitcgNetCord.MainApp.Commands.Preconditions;
22
using GitcgSkia;
3-
using GitcgSkia.Extensions;
43
using HoyolabHttpClient;
54
using NetCord;
65
using NetCord.Rest;
@@ -74,13 +73,12 @@ async Task CreateApplicationEmoteByUrlAsync(
7473
)
7574
{
7675
// Skip if the emote already exists
77-
if (_emojis.ContainsKey(emojiName))
78-
return;
76+
bool emojiExists = _emojis.ContainsKey(emojiName)
77+
|| newEmotes.Any(x => x.Name == emojiName);
78+
if (emojiExists) return;
7979

8080
if (url == "https://act-webstatic.hoyoverse.com/hk4e/e20200928calculate/")
81-
{
8281
url += "item_icon/67c7f719/8b295c3fed21771dcced6055cdf2f2ce.png";
83-
}
8482

8583
using var icon = await imageCacheService.LoadHttpImageAsync(url);
8684

@@ -96,15 +94,18 @@ async Task EncodeThenUploadAsync(
9694
quality: 100
9795
);
9896

99-
var emoji = await context.Client.Rest.CreateApplicationEmojiAsync(
100-
applicationId: applicationId,
101-
new ApplicationEmojiProperties(
102-
name: emojiName,
103-
image: new ImageProperties()
104-
.WithData(encoded.ToArray())
105-
)
97+
var image = new ImageProperties(
98+
format: ImageFormat.WebP,
99+
data: encoded.ToArray()
106100
);
107101

102+
var emoji = await context.Client.Rest
103+
.CreateApplicationEmojiAsync(
104+
applicationId,
105+
new ApplicationEmojiProperties(
106+
name: emojiName, image: image)
107+
);
108+
108109
newEmotes.Add(emoji);
109110
}
110111
}

src/GitcgNetCord.MainApp/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ WORKDIR /src
1515
COPY ["Directory.Packages.props", "."]
1616
COPY ["src/GitcgNetCord.MainApp/GitcgNetCord.MainApp.csproj", "src/GitcgNetCord.MainApp/"]
1717
COPY ["src/GitcgPainter/GitcgPainter.csproj", "src/GitcgPainter/"]
18+
COPY ["src/GitcgSharp.Shared/GitcgSharp.Shared.csproj", "src/GitcgSharp.Shared/"]
1819
COPY ["src/HoyolabHttpClient/HoyolabHttpClient.csproj", "src/HoyolabHttpClient/"]
20+
COPY ["src/GitcgSkia/GitcgSkia.csproj", "src/GitcgSkia/"]
1921
COPY ["src/ServiceDefaults/ServiceDefaults.csproj", "src/ServiceDefaults/"]
2022
COPY ["src/SharedUtils/SharedUtils.csproj", "src/SharedUtils/"]
2123
RUN dotnet restore "./src/GitcgNetCord.MainApp/GitcgNetCord.MainApp.csproj"

src/GitcgNetCord.MainApp/Models/DeckImageCreatorCollection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using GitcgPainter.ImageCreators.Deck.Genshincards;
21
using GitcgPainter.ImageCreators.Deck.Simplest;
32
using GitcgSkia.ImageCreators.Deck.GameBackground;
3+
using GitcgSkia.ImageCreators.Deck.Genshincards;
44

55
namespace GitcgNetCord.MainApp.Models;
66

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using SkiaSharp;
2+
3+
namespace GitcgSkia.Extensions;
4+
5+
public static class ElementColors
6+
{
7+
public static SKColor Cyro { get; } = SKColor.Parse("#7af2f2");
8+
9+
public static SKColor Hydro { get; } = SKColor.Parse("#00c0ff");
10+
11+
public static SKColor Pyro { get; } = SKColor.Parse("#ff6640");
12+
13+
public static SKColor Electro { get; } = SKColor.Parse("#cc80ff");
14+
15+
public static SKColor Anemo { get; } = SKColor.Parse("#33d7a0");
16+
17+
public static SKColor Geo { get; } = SKColor.Parse("#ffb00d");
18+
19+
public static SKColor Dendro { get; } = SKColor.Parse("#9be53d");
20+
21+
public static SKColor Unaligned { get; } = SKColor.Parse("#545454");
22+
23+
public static SKColor Aligned { get; } = SKColor.Parse("#ffffff");
24+
25+
public static SKColor Energy { get; } = SKColor.Parse("#ffffdf");
26+
27+
public static SKColor ArcaneLegend { get; } = SKColor.Parse("#cc6ce7");
28+
}

src/GitcgSkia/Extensions/ImageCacheServiceExtension.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ public static ValueTask<SKBitmap>
1818
Role role
1919
)
2020
{
21-
return imageCacheService.LoadHttpImageAsync(
22-
uri: role.Basic.IconSmall
23-
);
21+
var uri = role.Basic.IconSmall;
22+
23+
return imageCacheService.LoadHttpImageAsync(uri);
2424
}
2525

2626
public static ValueTask<SKBitmap> LoadIconAsync(
2727
this ImageCacheService imageCacheService,
2828
Basic basic
2929
)
3030
{
31-
return imageCacheService.LoadHttpImageAsync(
32-
uri: basic.Icon
33-
);
31+
var uri = basic.Icon;
32+
33+
return imageCacheService.LoadHttpImageAsync(uri);
3434
}
3535

3636
public static ValueTask<SKBitmap>
@@ -39,7 +39,9 @@ public static ValueTask<SKBitmap>
3939
ICardBasic card
4040
)
4141
{
42-
return imageCacheService.LoadIconAsync(card.Basic);
42+
var basic = card.Basic;
43+
44+
return imageCacheService.LoadIconAsync(basic);
4345
}
4446

4547
public static async ValueTask<SKBitmap>
@@ -55,17 +57,17 @@ ICardBasic card
5557

5658
if (cachedBorderedIcon != null) return cachedBorderedIcon;
5759

58-
SKBitmap cachedBorder;
59-
if (IsArcaneCard(card: card))
60-
cachedBorder = await imageCacheService.LoadArcaneBorderAsync();
60+
SKBitmap border;
61+
if (IsArcaneCard(card))
62+
border = await imageCacheService.LoadArcaneBorderAsync();
6163
else
62-
cachedBorder = await SkAssetsUtils.LoadCardBorderAsync();
64+
border = await SkAssetsUtils.LoadCardBorderAsync();
6365

64-
using (cachedBorder)
66+
using (border)
6567
{
66-
var cachedIcon = await imageCacheService.LoadIconAsync(card: card);
68+
var Icon = await imageCacheService.LoadIconAsync(card);
6769

68-
var borderedIcon = BorderIcon(icon: cachedIcon, border: cachedBorder);
70+
var borderedIcon = BorderIcon(icon: Icon, border: border);
6971

7072
cachedBorderedIcon = await imageCacheService
7173
.CacheImageAsync(key: cacheKey, image: borderedIcon);
@@ -98,7 +100,7 @@ await imageCacheService.CacheImageAsync(
98100
key: Utils.ArcaneBorderCacheKey,
99101
image: arcaneBorderResized
100102
);
101-
cachedArcaneBorder = arcaneBorder;
103+
cachedArcaneBorder = arcaneBorderResized;
102104

103105
return cachedArcaneBorder;
104106
}

src/GitcgSkia/Extensions/ServiceCollectionExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
using GitcgSkia.ImageCreators.Deck;
2-
using GitcgSkia.ImageCreators.Deck.GameBackground;
1+
using GitcgSkia.ImageCreators.Deck.GameBackground;
2+
using GitcgSkia.ImageCreators.Deck.Genshincards;
33
using Microsoft.Extensions.DependencyInjection;
44

55
namespace GitcgSkia.Extensions;
@@ -16,7 +16,7 @@ this IServiceCollection services
1616
// .AddTransient<DeckImageCreatorCollection>()
1717
// .AddTransient<SimplestDeckImageCreator>()
1818
.AddTransient<GameBackgroundDeckImageCreator>()
19-
// .AddTransient<GenshincardsDeckImageCreator>()
19+
.AddTransient<GenshincardsDeckImageCreator>()
2020
;
2121

2222
return services;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using HoyolabHttpClient.Models;
2+
using SkiaSharp;
3+
using ExtensionSkillElements = HoyolabHttpClient.Extensions.SkillElements;
4+
5+
namespace GitcgSkia.Extensions;
6+
7+
public static class SkillElementExtension
8+
{
9+
public static SKColor GetColor(this SkillElement? skillElement)
10+
{
11+
skillElement ??= ExtensionSkillElements.Aligned;
12+
13+
return SkillElements.Colors[skillElement.Value];
14+
}
15+
16+
public static ValueTask<SKBitmap> LoadElementIconAsync(
17+
this SkillElement? skillElement
18+
)
19+
{
20+
skillElement ??= ExtensionSkillElements.Aligned;
21+
22+
return skillElement.Value.LoadElementIconAsync();
23+
}
24+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using SkiaSharp;
2+
3+
using ExtensionSkillElements = HoyolabHttpClient.Extensions.SkillElements;
4+
5+
namespace GitcgSkia.Extensions;
6+
7+
public static class SkillElements
8+
{
9+
public static IDictionary<string, SKColor> Colors { get; }
10+
11+
static SkillElements()
12+
{
13+
Colors = new Dictionary<string, SKColor>
14+
{
15+
[ExtensionSkillElements.Cyro.Value] = ElementColors.Cyro,
16+
[ExtensionSkillElements.Hydro.Value] = ElementColors.Hydro,
17+
[ExtensionSkillElements.Pyro.Value] = ElementColors.Pyro,
18+
[ExtensionSkillElements.Electro.Value] = ElementColors.Electro,
19+
[ExtensionSkillElements.Anemo.Value] = ElementColors.Anemo,
20+
[ExtensionSkillElements.Geo.Value] = ElementColors.Geo,
21+
[ExtensionSkillElements.Dendro.Value] = ElementColors.Dendro,
22+
[ExtensionSkillElements.Unaligned.Value] = ElementColors.Unaligned,
23+
[ExtensionSkillElements.Aligned.Value] = ElementColors.Aligned,
24+
[ExtensionSkillElements.Energy.Value] = ElementColors.Energy,
25+
[ExtensionSkillElements.ArcaneLegend.Value] = ElementColors.ArcaneLegend
26+
};
27+
}
28+
29+
public static ValueTask<SKBitmap> LoadElementIconAsync(this string value)
30+
{
31+
if (value == ExtensionSkillElements.Cyro.Value)
32+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.CryoPath);
33+
if (value == ExtensionSkillElements.Hydro.Value)
34+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.HydroPath);
35+
if (value == ExtensionSkillElements.Pyro.Value)
36+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.PyroPath);
37+
if (value == ExtensionSkillElements.Electro.Value)
38+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.ElectroPath);
39+
if (value == ExtensionSkillElements.Anemo.Value)
40+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.AnemoPath);
41+
if (value == ExtensionSkillElements.Geo.Value)
42+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.GeoPath);
43+
if (value == ExtensionSkillElements.Dendro.Value)
44+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.DendroPath);
45+
46+
if (value == ExtensionSkillElements.Unaligned.Value)
47+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.TcgActionPointCommonBlackPath);
48+
if (value == ExtensionSkillElements.Aligned.Value)
49+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.TcgActionPointCommonWhitePath);
50+
51+
if (value == ExtensionSkillElements.Energy.Value)
52+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.TcgCharacterRechargePointPath);
53+
54+
if (value == ExtensionSkillElements.ArcaneLegend.Value)
55+
return SkAssetsUtils.LoadImageFromManifestResourceAsync(SkAssetsUtils.CostSecretPath);
56+
57+
throw new ArgumentException("Invalid value", nameof(value));
58+
}
59+
}

src/GitcgSkia/GitcgSkia.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<EmbeddedResource Include="assets\**"/>
10+
<EmbeddedResource Include="assets\**" />
1111
</ItemGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="SkiaSharp"/>
15-
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid"/>
14+
<PackageReference Include="SkiaSharp" />
15+
<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" />
1616
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" />
1717
</ItemGroup>
1818

1919
<ItemGroup>
2020
<ProjectReference Include="..\GitcgSharp.Shared\GitcgSharp.Shared.csproj" />
21-
<ProjectReference Include="..\HoyolabHttpClient\HoyolabHttpClient.csproj"/>
21+
<ProjectReference Include="..\HoyolabHttpClient\HoyolabHttpClient.csproj" />
2222
</ItemGroup>
2323

2424
</Project>

0 commit comments

Comments
 (0)