From 7c8e92241cc445765a84055bfd8fe1a8c964e470 Mon Sep 17 00:00:00 2001 From: "terentev.a.a" Date: Wed, 4 Dec 2024 10:43:52 +0300 Subject: [PATCH 1/2] Enhance SkinService with second layer support Added support for handling second-layer skin textures in the SkinService. This involves cropping and drawing new parts for the secondary head, body, leg, and arm layers. Additionally, redundant stream handling has been streamlined to improve performance. --- src/Gml.Launcher/Core/Services/SkinService.cs | 138 +++++++++--------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/src/Gml.Launcher/Core/Services/SkinService.cs b/src/Gml.Launcher/Core/Services/SkinService.cs index a799184..a49258c 100644 --- a/src/Gml.Launcher/Core/Services/SkinService.cs +++ b/src/Gml.Launcher/Core/Services/SkinService.cs @@ -42,81 +42,75 @@ public static byte[] GetCloak(string cloakPath, int size) return memoryStream.ToArray(); } - public static byte[] GetFront(Stream skinStream, int size) - { - using var inputImage = Image.Load(skinStream); - - var scaleFactor = inputImage.Width / 64; - - var croppedHead = inputImage.Clone(ctx => - ctx.Crop(new Rectangle(8 * scaleFactor, 8 * scaleFactor, 8 * scaleFactor, 8 * scaleFactor))); - - var croppedBody = inputImage.Clone(ctx => - ctx.Crop(new Rectangle(20 * scaleFactor, 20 * scaleFactor, 8 * scaleFactor, 12 * scaleFactor))); - - var croppedLeg = inputImage.Clone(ctx => - ctx.Crop(new Rectangle(4 * scaleFactor, 20 * scaleFactor, 4 * scaleFactor, 12 * scaleFactor))); - - var croppedArm = inputImage.Clone(ctx => - ctx.Crop(new Rectangle(44 * scaleFactor, 20 * scaleFactor, 4 * scaleFactor, 12 * scaleFactor))); - - var newWidth = croppedArm.Width * 2 + croppedBody.Width; - var newHeight = croppedHead.Height + croppedBody.Height + croppedArm.Height; - - var combinedImage = new Image(newWidth, newHeight); - - combinedImage.Mutate(context => - { - var headPosition = new Rectangle(croppedArm.Width, 0, croppedHead.Width, croppedHead.Height); - var bodyPosition = new Rectangle(headPosition.X, croppedHead.Height, croppedBody.Width, croppedBody.Height); - - var leftArmPosition = new Rectangle(0, bodyPosition.Y, croppedArm.Width, croppedArm.Height); - var rightArmPosition = new Rectangle(leftArmPosition.Width + bodyPosition.Width, leftArmPosition.Y, - leftArmPosition.Width, leftArmPosition.Height); - - var leftLegPosition = new Rectangle(leftArmPosition.Width, headPosition.Height + bodyPosition.Height, - croppedLeg.Width, croppedLeg.Height); - var rightLegPosition = new Rectangle(leftArmPosition.Width + leftLegPosition.Width, - headPosition.Height + bodyPosition.Height, leftLegPosition.Width, leftLegPosition.Height); - - context.DrawImage(croppedHead, new Point(headPosition.X, headPosition.Y), 1f); - context.DrawImage(croppedBody, new Point(bodyPosition.X, bodyPosition.Y), 1f); - context.DrawImage(croppedArm, new Point(leftArmPosition.X, leftArmPosition.Y), 1f); - context.DrawImage(croppedArm, new Point(rightArmPosition.X, rightArmPosition.Y), 1f); - context.DrawImage(croppedLeg, new Point(leftLegPosition.X, leftLegPosition.Y), 1f); - context.DrawImage(croppedLeg, new Point(rightLegPosition.X, rightLegPosition.Y), 1f); - - // context.DrawImage(croppedArm, new Point(0, 8 * scaleFactor), 1f); - // context.DrawImage(croppedLeg, new Point(200, 200), 1f); - }); - - using var memoryStream = new MemoryStream(); - if (inputImage.Metadata.DecodedImageFormat != null) - combinedImage.Save(memoryStream, inputImage.Metadata.DecodedImageFormat); - else - combinedImage.Save(memoryStream, new PngEncoder()); - - // var image = ResizeImage(size, inputImage, combinedImage); - - if (size != combinedImage.Width) - { - var scaleSize = GetScaleSize(size, combinedImage.Width); - - if (scaleSize != 0) - combinedImage = combinedImage.Clone(ctx => ctx.Resize(combinedImage.Width * scaleSize, - combinedImage.Height * scaleSize, KnownResamplers.Box)); - } - - using var resizeMemoryStream = new MemoryStream(); - - if (inputImage.Metadata.DecodedImageFormat != null) - combinedImage.Save(resizeMemoryStream, inputImage.Metadata.DecodedImageFormat); - else - combinedImage.Save(resizeMemoryStream, new PngEncoder()); + public static byte[] GetFront(Stream skinStream, int size) { + using var inputImage = Image.Load(skinStream); + + var scaleFactor = inputImage.Width / 64; + + var croppedHead = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(8 * scaleFactor, 8 * scaleFactor, 8 * scaleFactor, 8 * scaleFactor))); + var croppedBody = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(20 * scaleFactor, 20 * scaleFactor, 8 * scaleFactor, 12 * scaleFactor))); + var croppedLeg = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(4 * scaleFactor, 20 * scaleFactor, 4 * scaleFactor, 12 * scaleFactor))); + var croppedArm = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(44 * scaleFactor, 20 * scaleFactor, 4 * scaleFactor, 12 * scaleFactor))); + + var secondLayerHead = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(40 * scaleFactor, 8 * scaleFactor, 8 * scaleFactor, 8 * scaleFactor))); + var secondLayerBody = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(20 * scaleFactor, 36 * scaleFactor, 8 * scaleFactor, 12 * scaleFactor))); + var secondLayerLeg = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(4 * scaleFactor, 52 * scaleFactor, 4 * scaleFactor, 12 * scaleFactor))); + var secondLayerArm = inputImage.Clone(ctx => + ctx.Crop(new Rectangle(44 * scaleFactor, 52 * scaleFactor, 4 * scaleFactor, 12 * scaleFactor))); + + var newWidth = croppedArm.Width * 2 + croppedBody.Width; + var newHeight = croppedHead.Height + croppedBody.Height + croppedArm.Height; + + var combinedImage = new Image(newWidth, newHeight); + + combinedImage.Mutate(context => { + var headPosition = new Rectangle(croppedArm.Width, 0, croppedHead.Width, croppedHead.Height); + var bodyPosition = new Rectangle(headPosition.X, croppedHead.Height, croppedBody.Width, croppedBody.Height); + + var leftArmPosition = new Rectangle(0, bodyPosition.Y, croppedArm.Width, croppedArm.Height); + var rightArmPosition = new Rectangle(leftArmPosition.Width + bodyPosition.Width, leftArmPosition.Y, + leftArmPosition.Width, leftArmPosition.Height); + + var leftLegPosition = new Rectangle(leftArmPosition.Width, headPosition.Height + bodyPosition.Height, + croppedLeg.Width, croppedLeg.Height); + var rightLegPosition = new Rectangle(leftArmPosition.Width + leftLegPosition.Width, + headPosition.Height + bodyPosition.Height, leftLegPosition.Width, leftLegPosition.Height); + + context.DrawImage(croppedHead, new Point(headPosition.X, headPosition.Y), 1f); + context.DrawImage(croppedBody, new Point(bodyPosition.X, bodyPosition.Y), 1f); + context.DrawImage(croppedArm, new Point(leftArmPosition.X, leftArmPosition.Y), 1f); + context.DrawImage(croppedArm, new Point(rightArmPosition.X, rightArmPosition.Y), 1f); + context.DrawImage(croppedLeg, new Point(leftLegPosition.X, leftLegPosition.Y), 1f); + context.DrawImage(croppedLeg, new Point(rightLegPosition.X, rightLegPosition.Y), 1f); + + context.DrawImage(secondLayerHead, new Point(headPosition.X, headPosition.Y), 1f); + context.DrawImage(secondLayerBody, new Point(bodyPosition.X, bodyPosition.Y), 1f); + context.DrawImage(secondLayerArm, new Point(leftArmPosition.X, leftArmPosition.Y), 1f); + context.DrawImage(secondLayerArm, new Point(rightArmPosition.X, rightArmPosition.Y), 1f); + context.DrawImage(secondLayerLeg, new Point(leftLegPosition.X, leftLegPosition.Y), 1f); + context.DrawImage(secondLayerLeg, new Point(rightLegPosition.X, rightLegPosition.Y), 1f); + }); + + if (size != combinedImage.Width) { + var scaleSize = GetScaleSize(size, combinedImage.Width); + if (scaleSize != 0) + combinedImage = combinedImage.Clone(ctx => ctx.Resize(combinedImage.Width * scaleSize, + combinedImage.Height * scaleSize, KnownResamplers.Box)); + } - return resizeMemoryStream.ToArray(); + using var memoryStream = new MemoryStream(); + combinedImage.Save(memoryStream, new PngEncoder()); + return memoryStream.ToArray(); } + public static byte[] GetBack(string skinPath, int size, bool includeCloak = false) { using var inputImage = Image.Load(skinPath); From bb7c722e12836241faded90aba474ef45b1583a1 Mon Sep 17 00:00:00 2001 From: "terentev.a.a" Date: Wed, 4 Dec 2024 10:43:59 +0300 Subject: [PATCH 2/2] Add debug-specific configuration to Program.cs Introduced conditional compilation to execute additional logging and error handling specific to the debug build. This includes initializing Sentry, setting a default exception handler, and using `BuildAvaloniaApp` without parameters in the debug scenario, improving debugging efficiency and error traceability. --- src/Gml.Launcher/Program.cs | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Gml.Launcher/Program.cs b/src/Gml.Launcher/Program.cs index 43da76f..efa8770 100644 --- a/src/Gml.Launcher/Program.cs +++ b/src/Gml.Launcher/Program.cs @@ -14,6 +14,24 @@ namespace Gml.Launcher; internal class Program { [STAThread] +#if DEBUG + public static void Main(string[] args) + { + try + { + Debug.WriteLine($"[Gml][{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Application started"); + InitializeSentry(); + RxApp.DefaultExceptionHandler = Observer.Create(GlobalExceptionHandler); + BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + } + catch (Exception exception) + { + SentrySdk.CaptureException(exception); + Console.WriteLine(exception); + } + } +#else public static void Main(string[] args) { try @@ -30,12 +48,25 @@ public static void Main(string[] args) Console.WriteLine(exception); } } +#endif private static void GlobalExceptionHandler(Exception exception) { SentrySdk.CaptureException(exception); } +#if DEBUG + public static AppBuilder BuildAvaloniaApp() + { + Debug.WriteLine($"[Gml][{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Configuring launcher"); + return AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .RegisterServices([]) + .LogToTrace() + .UseReactiveUI(); + } +#else public static AppBuilder BuildAvaloniaApp(string[] args) { Debug.WriteLine($"[Gml][{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] Configuring launcher"); @@ -46,8 +77,7 @@ public static AppBuilder BuildAvaloniaApp(string[] args) .LogToTrace() .UseReactiveUI(); } - - +#endif private static void InitializeSentry() {