#region Copyright & License Information /* * Copyright 2007-2021 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System.Linq; using System.Threading.Tasks; using OpenRA.FileFormats; using OpenRA.Graphics; using OpenRA.Primitives; using OpenRA.Support; namespace OpenRA { public class PlayerDatabase : IGlobalModData { public readonly string Profile = "https://forum.openra.net/openra/info/"; public readonly int IconSize = 24; // 512x512 is large enough for 49 unique 72x72 badges // or 100 unique 42x42 badges // or 441 unique 24x24 badges // or some combination of the above if the DPI changes ingame [FieldLoader.Ignore] SheetBuilder sheetBuilder; [FieldLoader.Ignore] Cache<(PlayerBadge, int), Sprite> iconCache; Sprite LoadSprite(string url, int density) { var spriteSize = IconSize * density; var sprite = sheetBuilder.Allocate(new Size(spriteSize, spriteSize), 1f / density); Task.Run(async () => { try { var client = HttpClientFactory.Create(); var httpResponseMessage = await client.GetAsync(url); var result = await httpResponseMessage.Content.ReadAsStreamAsync(); var icon = new Png(result); if (icon.Width == spriteSize && icon.Height == spriteSize) { Game.RunAfterTick(() => { Util.FastCopyIntoSprite(sprite, icon); sprite.Sheet.CommitBufferedData(); }); } } catch { } }); return sprite; } Sheet CreateSheet() { var sheet = new Sheet(SheetType.BGRA, new Size(512, 512)); // We must manually force the buffer creation to avoid a crash // that is indirectly triggered by rendering from a Sheet that // has not yet been written to. sheet.CreateBuffer(); sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear; return sheet; } public PlayerBadge LoadBadge(MiniYaml yaml) { if (sheetBuilder == null) { sheetBuilder = new SheetBuilder(SheetType.BGRA, CreateSheet); iconCache = new Cache<(PlayerBadge Badge, int Density), Sprite>(p => { if (p.Density > 2 && !string.IsNullOrEmpty(p.Badge.Icon3x)) return LoadSprite(p.Badge.Icon3x, 3); if (p.Density > 1 && !string.IsNullOrEmpty(p.Badge.Icon2x)) return LoadSprite(p.Badge.Icon2x, 2); return LoadSprite(p.Badge.Icon, 1); }); } var labelNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Label"); var icon24Node = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon24"); var icon48Node = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon48"); var icon72Node = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon72"); if (labelNode == null) return null; return new PlayerBadge( labelNode.Value.Value, icon24Node?.Value.Value, icon48Node?.Value.Value, icon72Node?.Value.Value); } public Sprite GetIcon(PlayerBadge badge) { var ws = Game.Renderer.WindowScale; var density = ws > 2 ? 3 : ws > 1 ? 2 : 1; return iconCache[(badge, density)]; } } }