using System; using System.Collections.Generic; using System.Linq; // The third-party attributions the shipped game must show the player. One list, owned here: the credits screen only // renders it, and CreditsTests holds it against the licence files in Assets. Unity-free so the headless build checks it. public class Credit { public string Name; public string Licence; // What the licence requires shown: copyright holders, and any change notice. public string Notice; // The licence file in the repo that carries the full text and that this entry answers for. public string LicenceFile; } public static class Credits { public const string TwemojiFile = "Assets/Fonts/Emoji/LICENSE.txt"; public const string PlaydeadFile = "Assets/Plugins/Playdead/LICENSE.txt"; public const string NounProjectFile = "Assets/Resources/Sprites/Attribution.txt"; public const string LiberationFile = "Assets/TextMesh Pro/Fonts/LiberationSans - OFL.txt"; public const string UniRxFile = "Assets/Plugins/UniRx/ReadMe.txt"; public const string AmbientCgFile = "Assets/Materials/PBR/SOURCES.md"; public const string KdTreeFile = "Assets/Scripts/ServerShared/NIH/KDTree/KDTree.cs"; public const string SimplexNoiseFile = "Assets/Plugins/GPU Noise/SimplexNoise2D.cginc"; // The first line of the attribution file; the icon credits are the lines after it. public const string NounProjectHeading = "Noun Project"; // Where the player build loads the Noun Project credit lines from (Resources path, no extension). public const string NounProjectResource = "Sprites/Attribution"; // The full list. The Noun Project icon credits are the lines of its attribution file, whose text the caller supplies // (Unity reads it as a Resources TextAsset; tests read it from disk), so the file stays the one copy of those names. public static IReadOnlyList All(string nounProjectAttribution) { var credits = new List { new Credit { Name = "Twemoji", Licence = "CC BY 4.0", Notice = "Copyright (c) 2022-present Jason Sofonia & Justine De Caires; copyright (c) 2014-2021 Twitter. " + "Graphics licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). " + "Converted to a colour font; the artwork itself is not edited.", LicenceFile = TwemojiFile }, new Credit { Name = "Playdead temporal anti-aliasing", Licence = "MIT", Notice = "Copyright (c) 2015 Playdead", LicenceFile = PlaydeadFile }, new Credit { Name = "Liberation Sans", Licence = "SIL Open Font License 1.1", Notice = "Digitized data copyright (c) 2010 Google Corporation with Reserved Font Arimo, Tinos and Cousine. " + "Copyright (c) 2012 Red Hat, Inc. with Reserved Font Name Liberation.", LicenceFile = LiberationFile }, new Credit { Name = "UniRx", Licence = "MIT", Notice = "Created by Yoshifumi Kawai (neuecc)", LicenceFile = UniRxFile }, new Credit { Name = "KDTree", Licence = "MIT", Notice = "Copyright (c) 2018 Vili VolĨini / viliwonka", LicenceFile = KdTreeFile }, new Credit { Name = "webgl-noise simplex noise", Licence = "MIT", Notice = "Copyright (C) 2011 Ashima Arts. Author: Ian McEwan, Ashima Arts " + "(https://github.com/ashima/webgl-noise). Translated to Unity shaders and modified by Keijiro Takahashi " + "(https://github.com/keijiro/NoiseShader).", LicenceFile = SimplexNoiseFile }, new Credit { Name = "ambientCG PBR materials", Licence = "CC0 1.0 Universal", Notice = "Texture sets from ambientCG (https://ambientcg.com), public domain", LicenceFile = AmbientCgFile }, new Credit { Name = "Noun Project icons", Licence = "Noun Project attribution licence", Notice = string.Join("\n", NounProjectLines(nounProjectAttribution)), LicenceFile = NounProjectFile } }; Validate(credits); return credits; } // The icon credit lines of the attribution file: everything after its "Noun Project" heading, one line per icon (the // file's "Other" sub-heading and its lines follow in the same list). A file that does not open with the heading is // refused rather than having its first line dropped. public static IEnumerable NounProjectLines(string attribution) { var lines = (attribution ?? "").Split('\n').Select(line => line.Trim()).Where(line => line.Length > 0).ToArray(); if (lines.Length < 2 || lines[0] != NounProjectHeading) throw new InvalidOperationException($"{NounProjectFile} must open with the heading '{NounProjectHeading}' followed by icon credits"); return lines.Skip(1); } // Throws on an entry a player-facing screen could not honestly show. public static void Validate(IReadOnlyList credits) { foreach (var credit in credits) if (string.IsNullOrWhiteSpace(credit.Name) || string.IsNullOrWhiteSpace(credit.Licence) || string.IsNullOrWhiteSpace(credit.Notice) || string.IsNullOrWhiteSpace(credit.LicenceFile)) throw new InvalidOperationException($"Credit '{credit.Name}' is missing its name, licence, notice or licence file"); var duplicate = credits.GroupBy(credit => credit.LicenceFile).FirstOrDefault(group => group.Count() > 1); if (duplicate != null) throw new InvalidOperationException($"Licence file {duplicate.Key} is credited twice"); } }