internal void HandleCache(TinyToken cachedFontRoot) { if (!matches(cachedFontRoot)) { return; } foreach (var cacheEntry in cachedFontRoot.Values <TinyObject>("Cache")) { var path = cacheEntry.Value <string>("Path"); var hash = cacheEntry.Value <string>("Hash"); var fullPath = Path.Combine(mapsetDirectory, path); if (!File.Exists(fullPath) || HashHelper.GetFileMd5(fullPath) != hash) { continue; } textureCache.Add(cacheEntry.Value <string>("Text"), new FontTexture( path, cacheEntry.Value <float>("OffsetX"), cacheEntry.Value <float>("OffsetY"), cacheEntry.Value <int>("BaseWidth"), cacheEntry.Value <int>("BaseHeight"), cacheEntry.Value <int>("Width"), cacheEntry.Value <int>("Height") )); } }
private void writeArray(TextWriter writer, TinyArray array, TinyToken parent, int indentLevel) { var parentIsArray = parent != null && parent.Type == TinyTokenType.Array; var first = true; foreach (var token in array) { if (!first || !parentIsArray) { writeIndent(writer, indentLevel); } if (token.IsEmpty) { writer.WriteLine("- "); } else if (token.IsInline) { writer.Write("- "); write(writer, token, array, 0); } else { writer.Write("- "); write(writer, token, array, indentLevel + 1); } first = false; } }
public FontGenerator LoadFont(string directory, FontDescription description, params FontEffect[] effects) { var fontDirectory = Path.GetFullPath(Path.Combine(context.MapsetPath, directory)); if (fontDirectories.Contains(fontDirectory)) { throw new InvalidOperationException($"This effect already generated a font inside \"{fontDirectory}\""); } fontDirectories.Add(fontDirectory); var fontGenerator = new FontGenerator(directory, description, effects, context.ProjectPath, context.MapsetPath); fontGenerators.Add(fontGenerator); var cachePath = fontCacheDirectory; if (Directory.Exists(cachePath)) { var path = Path.Combine(cachePath, HashHelper.GetMd5(fontGenerator.Directory) + ".yaml"); if (File.Exists(path)) { var cachedFontRoot = Util.Misc.WithRetries(() => TinyToken.Read(path), canThrow: false); if (cachedFontRoot != null) { fontGenerator.HandleCache(cachedFontRoot); } } } return(fontGenerator); }
public TinyToken Parse(IEnumerable <Token <YamlTokenType> > tokens) { TinyToken result = null; var context = new ParseContext <YamlTokenType>(tokens, new AnyParser(r => result = r)); while (context.CurrentToken != null) { switch (context.CurrentToken.Type) { case YamlTokenType.Indent: context.Indent(context.CurrentToken.Value.Length / 2); context.ConsumeToken(); continue; case YamlTokenType.EndLine: context.NewLine(); context.ConsumeToken(); continue; } //Debug.Print($" - {context.Parser.GetType().Name} ({context.ParserCount})"); context.Parser.Parse(context); } context.End(); return(result); }
private bool matches(TinyToken cachedFontRoot) { if (cachedFontRoot.Value <string>("FontPath") == description.FontPath && cachedFontRoot.Value <int>("FontSize") == description.FontSize && MathUtil.FloatEquals(cachedFontRoot.Value <float>("ColorR"), description.Color.R, 0.00001f) && MathUtil.FloatEquals(cachedFontRoot.Value <float>("ColorG"), description.Color.G, 0.00001f) && MathUtil.FloatEquals(cachedFontRoot.Value <float>("ColorB"), description.Color.B, 0.00001f) && MathUtil.FloatEquals(cachedFontRoot.Value <float>("ColorA"), description.Color.A, 0.00001f) && MathUtil.FloatEquals(cachedFontRoot.Value <float>("PaddingX"), description.Padding.X, 0.00001f) && MathUtil.FloatEquals(cachedFontRoot.Value <float>("PaddingY"), description.Padding.Y, 0.00001f) && cachedFontRoot.Value <FontStyle>("FontStyle") == description.FontStyle && cachedFontRoot.Value <bool>("TrimTransparency") == description.TrimTransparency && cachedFontRoot.Value <bool>("EffectsOnly") == description.EffectsOnly && cachedFontRoot.Value <bool>("Debug") == description.Debug) { var effectsRoot = cachedFontRoot.Value <TinyArray>("Effects"); if (effectsRoot.Count != effects.Length) { return(false); } for (var i = 0; i < effects.Length; i++) { if (!effects[i].Matches(effectsRoot[i].Value <TinyToken>())) { return(false); } } return(true); } return(false); }
public bool Matches(TinyToken cachedEffectRoot) => cachedEffectRoot.Value <string>("Type") == GetType().FullName&& cachedEffectRoot.Value <int>("Thickness") == Thickness && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorR"), Color.R, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorG"), Color.G, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorB"), Color.B, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorA"), Color.A, 0.00001f);
public bool Matches(TinyToken cachedEffectRoot) => cachedEffectRoot.Value <string>("Type") == GetType().FullName&& cachedEffectRoot.Value <int>("Radius") == Radius && MathUtil.DoubleEquals(cachedEffectRoot.Value <double>("Power"), Power, 0.00001) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorR"), Color.R, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorG"), Color.G, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorB"), Color.B, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorA"), Color.A, 0.00001f);
public bool Matches(TinyToken cachedEffectRoot) => cachedEffectRoot.Value <string>("Type") == GetType().FullName&& MathUtil.FloatEquals(cachedEffectRoot.Value <float>("OffsetX"), Offset.X, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("OffsetY"), Offset.Y, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("SizeX"), Size.X, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("SizeY"), Size.Y, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorR"), Color.R, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorG"), Color.G, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorB"), Color.B, 0.00001f) && MathUtil.FloatEquals(cachedEffectRoot.Value <float>("ColorA"), Color.A, 0.00001f) && cachedEffectRoot.Value <WrapMode>("WrapMode") == WrapMode;
public TinyToken Parse(IEnumerable <Token <JsonTokenType> > tokens) { TinyToken result = null; var context = new ParseContext <JsonTokenType>(tokens, new AnyParser(r => result = r)); while (context.CurrentToken != null) { //Debug.Print($" - {context.Parser.GetType().Name} ({context.ParserCount}) {context.CurrentToken}"); context.Parser.Parse(context); } context.End(); return(result); }
private void write(TextWriter writer, TinyToken token, TinyToken parent, int indentLevel) { switch (token.Type) { case TinyTokenType.Object: writeObject(writer, (TinyObject)token, parent, indentLevel); break; case TinyTokenType.Array: writeArray(writer, (TinyArray)token, parent, indentLevel); break; default: writeValue(writer, (TinyValue)token, parent, indentLevel); break; } }
internal void HandleCache(TinyToken cachedFontRoot) { if (!matches(cachedFontRoot)) { return; } foreach (var cacheEntry in cachedFontRoot.Values <TinyObject>("Cache")) { var path = cacheEntry.Value <string>("Path"); var hash = cacheEntry.Value <string>("Hash"); var fullPath = Path.Combine(mapsetDirectory, path); if (!File.Exists(fullPath) || HashHelper.GetFileMd5(fullPath) != hash) { continue; } var text = cacheEntry.Value <string>("Text"); if (text.Contains('\ufffd')) { Trace.WriteLine($"Ignoring invalid font texture \"{text}\" ({path})"); continue; } if (textureCache.ContainsKey(text)) { throw new InvalidDataException($"The font texture for \"{text}\" ({path}) has been cached multiple times"); } textureCache.Add(text, new FontTexture( path, cacheEntry.Value <float>("OffsetX"), cacheEntry.Value <float>("OffsetY"), cacheEntry.Value <int>("BaseWidth"), cacheEntry.Value <int>("BaseHeight"), cacheEntry.Value <int>("Width"), cacheEntry.Value <int>("Height") )); } }
private void writeObject(TextWriter writer, TinyObject obj, TinyToken parent, int indentLevel) { var parentIsArray = parent != null && parent.Type == TinyTokenType.Array; var first = true; foreach (var property in obj) { if (!first || !parentIsArray) { writeIndent(writer, indentLevel); } var key = property.Key; if (key.Contains(" ") || key.Contains(":") || key.StartsWith("-")) { key = "\"" + YamlUtil.EscapeString(key) + "\""; } var value = property.Value; if (value.IsEmpty) { writer.WriteLine(key + ":"); } else if (value.IsInline) { writer.Write(key + ": "); write(writer, value, obj, 0); } else { writer.WriteLine(key + ":"); write(writer, value, obj, indentLevel + 1); } first = false; } }
private void checkLatestVersion() { NetHelper.Request($"https://api.github.com/repos/{Program.Repository}/releases?per_page=10&page=1", "cache/net/releases", 15 * 60, (response, exception) => { if (IsDisposed) { return; } if (exception != null) { handleLastestVersionException(exception); return; } try { var hasLatest = false; var latestVersion = Program.Version; var description = ""; var downloadUrl = (string)null; var releases = TinyToken.ReadString <JsonFormat>(response); foreach (var release in releases.Values <TinyObject>()) { var isDraft = release.Value <bool>("draft"); var isPrerelease = release.Value <bool>("prerelease"); if (isDraft || isPrerelease) { continue; } var name = release.Value <string>("name"); var version = new Version(name); if (!hasLatest) { hasLatest = true; latestVersion = version; foreach (var asset in release.Values <TinyObject>("assets")) { var downloadName = asset.Value <string>("name"); if (downloadName.EndsWith(".zip")) { downloadUrl = asset.Value <string>("browser_download_url"); break; } } } if (Program.Version < version || Program.Version >= latestVersion) { var publishedAt = release.Value <string>("published_at"); var publishDate = DateTime.ParseExact(publishedAt, @"yyyy-MM-dd\THH:mm:ss\Z", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); var authorName = release.Value <string>("author", "login"); var body = release.Value <string>("body"); if (body.Contains("---")) { body = body.Substring(0, body.IndexOf("---")); } body = body.Replace("\r\n", "\n").Trim(' ', '\n'); body = $"v{version} - {authorName}, {publishDate.ToTimeAgo()}\n{body}\n\n"; var newDescription = description + body; if (description.Length > 0 && newDescription.Count(c => c == '\n') > 35) { break; } description = newDescription; } else { break; } } if (Program.Version < latestVersion) { updateButton.Text = $"Version {latestVersion} available!"; updateButton.Tooltip = $"What's new:\n\n{description.TrimEnd('\n')}"; updateButton.OnClick += (sender, e) => { if (downloadUrl != null && latestVersion >= new Version(1, 4)) { Manager.Add(new UpdateMenu(downloadUrl)); } else { Updater.OpenLastestReleasePage(); } }; updateButton.StyleName = ""; updateButton.Disabled = false; } else { versionLabel.Tooltip = $"Recent changes:\n\n{description.TrimEnd('\n')}"; updateButton.Displayed = false; } bottomLayout.Pack(600); } catch (Exception e) { handleLastestVersionException(e); } }); }
public override void Write(TextWriter writer, TinyToken value) => write(writer, value, null, 0);
private void writeValue(TextWriter writer, TinyValue valueToken, TinyToken parent, int indentLevel) { if (indentLevel != 0) { throw new InvalidOperationException(); } var type = valueToken.Type; var value = valueToken.Value <object>(); switch (type) { case TinyTokenType.Null: writer.WriteLine(); break; case TinyTokenType.String: writer.WriteLine("\"" + YamlUtil.EscapeString((string)value) + "\""); break; case TinyTokenType.Integer: writer.WriteLine(value?.ToString()); break; case TinyTokenType.Float: if (value is float floatFloat) { writer.WriteLine(floatFloat.ToString(CultureInfo.InvariantCulture)); } else if (value is double floatDouble) { writer.WriteLine(floatDouble.ToString(CultureInfo.InvariantCulture)); } else if (value is decimal floatDecimal) { writer.WriteLine(floatDecimal.ToString(CultureInfo.InvariantCulture)); } else if (value is string floatString) { writer.WriteLine(floatString); } else { throw new InvalidDataException(value?.ToString()); } break; case TinyTokenType.Boolean: writer.WriteLine(((bool)value) ? BooleanTrue : BooleanFalse); break; case TinyTokenType.Array: case TinyTokenType.Object: case TinyTokenType.Invalid: // Should never happen :) throw new InvalidDataException(type.ToString()); default: throw new NotImplementedException(type.ToString()); } }
private void loadText(string path) { var targetDirectory = Path.Combine(Path.GetDirectoryName(path), DataFolder); using (var directoryReader = new SafeDirectoryReader(targetDirectory)) { var indexPath = directoryReader.GetPath("index.yaml"); var indexRoot = TinyToken.Read(indexPath); var indexVersion = indexRoot.Value <int>("FormatVersion"); if (indexVersion > Version) { throw new InvalidOperationException("This project was saved with a more recent version, you need to update to open it"); } var userPath = directoryReader.GetPath("user.yaml"); if (File.Exists(userPath)) { var userRoot = TinyToken.Read(userPath); var userVersion = userRoot.Value <int>("FormatVersion"); if (userVersion > Version) { throw new InvalidOperationException("This project's user settings were saved with a more recent version, you need to update to open it"); } var savedBy = userRoot.Value <string>("Editor"); Debug.Print($"Project saved by {savedBy}"); OwnsOsb = userRoot.Value <bool>("OwnsOsb"); } MapsetPath = indexRoot.Value <string>("MapsetPath"); SelectBeatmap(indexRoot.Value <long>("BeatmapId"), indexRoot.Value <string>("BeatmapName")); ImportedAssemblies = indexRoot.Values <string>("Assemblies"); // Load effects var layerInserters = new Dictionary <string, Action>(); foreach (var effectPath in Directory.EnumerateFiles(directoryReader.Path, "effect.*.yaml", SearchOption.TopDirectoryOnly)) { var guidMatch = effectGuidRegex.Match(effectPath); if (!guidMatch.Success || guidMatch.Groups.Count < 2) { throw new InvalidDataException($"Could not parse effect Guid from '{effectPath}'"); } var effectRoot = TinyToken.Read(effectPath); var effectVersion = effectRoot.Value <int>("FormatVersion"); if (effectVersion > Version) { throw new InvalidOperationException("This project contains an effect that was saved with a more recent version, you need to update to open it"); } var effect = AddEffect(effectRoot.Value <string>("Script")); effect.Guid = Guid.Parse(guidMatch.Groups[1].Value); effect.Name = effectRoot.Value <string>("Name"); var configRoot = effectRoot.Value <TinyObject>("Config"); var fieldIndex = 0; foreach (var fieldProperty in configRoot) { var fieldRoot = fieldProperty.Value; var fieldTypeName = fieldRoot.Value <string>("Type"); var fieldContent = fieldRoot.Value <string>("Value"); var fieldValue = ObjectSerializer.FromString(fieldTypeName, fieldContent); var allowedValues = fieldRoot .Value <TinyObject>("AllowedValues")? .Select(p => new NamedValue { Name = p.Key, Value = ObjectSerializer.FromString(fieldTypeName, p.Value.Value <string>()), }) .ToArray(); effect.Config.UpdateField(fieldProperty.Key, fieldRoot.Value <string>("DisplayName") ?? fieldProperty.Key, fieldIndex++, fieldValue?.GetType(), fieldValue, allowedValues); } var layersRoot = effectRoot.Value <TinyObject>("Layers"); foreach (var layerProperty in layersRoot) { var layerEffect = effect; var layerGuid = layerProperty.Key; var layerRoot = layerProperty.Value; layerInserters.Add(layerGuid, () => layerEffect.AddPlaceholder(new EditorStoryboardLayer(layerRoot.Value <string>("Name"), layerEffect) { Guid = Guid.Parse(layerGuid), OsbLayer = layerRoot.Value <OsbLayer>("OsbLayer"), DiffSpecific = layerRoot.Value <bool>("DiffSpecific"), Visible = layerRoot.Value <bool>("Visible"), })); } } // Insert layers defined in the index var layersOrder = indexRoot.Values <string>("Layers"); if (layersOrder != null) { foreach (var layerGuid in layersOrder.Distinct()) { if (layerInserters.TryGetValue(layerGuid, out var insertLayer)) { insertLayer(); } } } // Insert all remaining layers foreach (var key in layersOrder == null ? layerInserters.Keys : layerInserters.Keys.Except(layersOrder)) { var insertLayer = layerInserters[key]; insertLayer(); } } }
public override void Write(TextWriter writer, TinyToken value) => throw new NotImplementedException();