Skip to content

Commit

Permalink
Fix igms2fd to work with the new changes
Browse files Browse the repository at this point in the history
  • Loading branch information
Dobby233Liu authored May 20, 2023
1 parent 4c8133b commit 008425a
Showing 1 changed file with 190 additions and 190 deletions.
380 changes: 190 additions & 190 deletions UndertaleModTool/Scripts/Community Scripts/ImportGMS2FontData.csx
Original file line number Diff line number Diff line change
@@ -1,190 +1,190 @@
// ImportGMS2FontData by Dobby233Liu

using System;
using System.IO;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UndertaleModLib;
using UndertaleModLib.Util;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

EnsureDataLoaded();

ScriptMessage(@"ImportGMS2FontData by Dobby233Liu
This script can import GM font asset data to your mod
(Designed for the data IDE v2022.6.0.23 generates)
Select the .yy file of the GM font asset you want to import"
);

string importFile = PromptLoadFile("yy", "GameMaker Studio 2 files (.yy)|*.yy|All files|*");
if (importFile == null)
{
ScriptError("Import cancelled.");
return;
}

JObject fontData = null;
using (StreamReader file = File.OpenText(importFile))
{
using (JsonTextReader reader = new JsonTextReader(file))
{
fontData = JObject.Load(reader);
}
}

string fontPath = Path.GetDirectoryName(importFile);
string yyFilename = Path.GetFileNameWithoutExtension(importFile);
string fontName = (string)fontData["name"] ?? yyFilename;
string fontTexturePath = Path.Combine(fontPath, yyFilename + ".png");
// Failsafe to use font name
if (!File.Exists(fontTexturePath))
fontTexturePath = Path.Combine(fontPath, fontName + ".png");
// If we still can't find the texture
if (!File.Exists(fontTexturePath))
throw new ScriptException(
$@"Could not find a texture file for the selected font.
Try renaming the correct texture file to
{yyFilename}.png
and putting it in the same directory as the .yy file."
);

/*
If true, the script will attempt to add the new font (if any) and the new font glyph texture that it created to a texture group
This was an attempt to get fonts that this script creates appear in a specific 2022.3 game, but was proved unnecessary, as the problem was caused by something else
*/
bool attemptToFixFontNotAppearing = false; // Data.GM2022_3;
// Default to putting the font into the default texgroup
UndertaleTextureGroupInfo fontTexGroup = Data.TextureGroupInfo.ByName("Default");

UndertaleFont font = Data.Fonts.ByName(fontName);
if (font == null)
{
font = new UndertaleFont()
{
Name = Data.Strings.MakeString(fontName)
};
Data.Fonts.Add(font);

if (attemptToFixFontNotAppearing)
{
if (fontTexGroup == null)
throw new ScriptException("The default texture group doesn't exist??? (this shouldn't happen)");
fontTexGroup.Fonts.Add(new UndertaleResourceById<UndertaleFont, UndertaleChunkFONT>() { Resource = font });
}
}
else if (attemptToFixFontNotAppearing)
{
// Try to find the texgroup that the font belongs to
// Scariest LINQ query I've ever written (yet)
fontTexGroup = Data.TextureGroupInfo
.Where(t => t.Fonts.Any(f => f.Resource == font))
.DefaultIfEmpty(fontTexGroup)
.FirstOrDefault();
if (fontTexGroup == null)
throw new ScriptException("Existing font doesn't belong to any texture group AND the default texture group doesn't exist??? (this shouldn't happen)");
// Failsafe - put it in Default if it's not in there
if (!fontTexGroup.Fonts.Any(f => f.Resource == font))
fontTexGroup.Fonts.Add(new UndertaleResourceById<UndertaleFont, UndertaleChunkFONT>() { Resource = font });
}

// Prepare font texture
Bitmap textureBitmap = new Bitmap(fontTexturePath);
// Make the DPI exactly 96 for this bitmap
textureBitmap.SetResolution(96.0F, 96.0F);

UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
// ??? Why?
texture.Name = new UndertaleString("Texture " + Data.EmbeddedTextures.Count);
texture.TextureData.TextureBlob = File.ReadAllBytes(fontTexturePath);
Data.EmbeddedTextures.Add(texture);
if (attemptToFixFontNotAppearing)
fontTexGroup.TexturePages.Add(new UndertaleResourceById<UndertaleEmbeddedTexture, UndertaleChunkTXTR>() { Resource = texture });

UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
// ??? Same as above
texturePageItem.Name = new UndertaleString("PageItem " + Data.TexturePageItems.Count);
texturePageItem.TexturePage = texture;
texturePageItem.SourceX = 0;
texturePageItem.SourceY = 0;
texturePageItem.SourceWidth = (ushort)textureBitmap.Width;
texturePageItem.SourceHeight = (ushort)textureBitmap.Height;
texturePageItem.TargetX = 0;
texturePageItem.TargetY = 0;
texturePageItem.TargetWidth = (ushort)textureBitmap.Width;
texturePageItem.TargetHeight = (ushort)textureBitmap.Height;
texturePageItem.BoundingWidth = (ushort)textureBitmap.Width;
texturePageItem.BoundingHeight = (ushort)textureBitmap.Height;
Data.TexturePageItems.Add(texturePageItem);

font.DisplayName = Data.Strings.MakeString((string)fontData["fontName"]);
font.Texture = texturePageItem;
font.Bold = (bool)fontData["bold"];
font.Italic = (bool)fontData["italic"];
// FIXME: Potentially causes float precision to be lost
font.EmSize = (uint)fontData["size"];
// Save font size as a float in GMS2.3+ (shouldn't UML always save EmSize as a float for GMS2.3+ games??)
font.EmSizeIsFloat = Data.IsVersionAtLeast(2, 3);
font.Charset = (byte)fontData["charset"];
font.AntiAliasing = (byte)fontData["AntiAlias"];
// FIXME: ??? All YY files I've saw don't contain this
font.ScaleX = 1;
font.ScaleY = 1;
// Ascender is GM2022.2+
if (fontData.ContainsKey("ascender"))
font.Ascender = (uint)fontData["ascender"];
if (fontData.ContainsKey("ascenderOffset"))
font.AscenderOffset = (int)fontData["ascenderOffset"];

// FIXME: Too complicated?
List<int> charRangesUppersAndLowers = new();
foreach (JObject range in fontData["ranges"].Values<JObject>())
{
charRangesUppersAndLowers.Add((int)range["upper"]);
charRangesUppersAndLowers.Add((int)range["lower"]);
}
charRangesUppersAndLowers.Sort();
// FIXME: Check the range by ourselves if ranges don't have it probably
font.RangeStart = (ushort)charRangesUppersAndLowers.DefaultIfEmpty(0).FirstOrDefault();
font.RangeEnd = (uint)charRangesUppersAndLowers.DefaultIfEmpty(0xFFFF).LastOrDefault();

List<UndertaleFont.Glyph> glyphs = new();
// From what I've seen, the keys of the objects in glyphs is just the character property of the object itself but in string form
foreach (KeyValuePair<string, JToken> glyphKVEntry in (JObject)fontData["glyphs"])
{
var glyphData = (JObject)glyphKVEntry.Value;
glyphs.Add(new UndertaleFont.Glyph()
{
Character = (ushort)glyphData["character"],
SourceX = (ushort)glyphData["x"],
SourceY = (ushort)glyphData["y"],
SourceWidth = (ushort)glyphData["w"],
SourceHeight = (ushort)glyphData["h"],
Shift = (short)glyphData["shift"],
Offset = (short)glyphData["offset"],
});
}
// Sort glyphs like UndertaleFontEditor to be safe
glyphs.Sort((x, y) => x.Character.CompareTo(y.Character));
font.Glyphs.Clear();
foreach (var glyph in glyphs)
font.Glyphs.Add(glyph);

// TODO: Does this always exist?
glyphs = font.Glyphs.ToList();
foreach (JObject kerningPair in fontData["kerningPairs"]?.Values<JObject>())
{
// Why do I need to do this. Thanks YoYo
var first = (ushort)kerningPair["first"];
var glyph = glyphs.Find(x => x.Character == first);
glyph.Kerning.Add(new UndertaleFont.Glyph.GlyphKerning()
{
Other = (short)kerningPair["second"],
Amount = (short)kerningPair["amount"],
});
}

ScriptMessage("Import complete.");
// ImportGMS2FontData by Dobby233Liu

using System;
using System.IO;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UndertaleModLib;
using UndertaleModLib.Util;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

EnsureDataLoaded();

ScriptMessage(@"ImportGMS2FontData by Dobby233Liu
This script can import GM font asset data to your mod
(Designed for the data IDE v2022.6.0.23 generates)
Select the .yy file of the GM font asset you want to import"
);

string importFile = PromptLoadFile("yy", "GameMaker Studio 2 files (.yy)|*.yy|All files|*");
if (importFile == null)
{
ScriptError("Import cancelled.");
return;
}

JObject fontData = null;
using (StreamReader file = File.OpenText(importFile))
{
using (JsonTextReader reader = new JsonTextReader(file))
{
fontData = JObject.Load(reader);
}
}

string fontPath = Path.GetDirectoryName(importFile);
string yyFilename = Path.GetFileNameWithoutExtension(importFile);
string fontName = (string)fontData["name"] ?? yyFilename;
string fontTexturePath = Path.Combine(fontPath, yyFilename + ".png");
// Failsafe to use font name
if (!File.Exists(fontTexturePath))
fontTexturePath = Path.Combine(fontPath, fontName + ".png");
// If we still can't find the texture
if (!File.Exists(fontTexturePath))
throw new ScriptException(
$@"Could not find a texture file for the selected font.
Try renaming the correct texture file to
{yyFilename}.png
and putting it in the same directory as the .yy file."
);

/*
If true, the script will attempt to add the new font (if any) and the new font glyph texture that it created to a texture group
This was an attempt to get fonts that this script creates appear in a specific 2022.3 game, but was proved unnecessary, as the problem was caused by something else
*/
bool attemptToFixFontNotAppearing = false; // Data.GM2022_3;
// Default to putting the font into the default texgroup
UndertaleTextureGroupInfo fontTexGroup = Data.TextureGroupInfo.ByName("Default");

UndertaleFont font = Data.Fonts.ByName(fontName);
if (font == null)
{
font = new UndertaleFont()
{
Name = Data.Strings.MakeString(fontName)
};
Data.Fonts.Add(font);

if (attemptToFixFontNotAppearing)
{
if (fontTexGroup == null)
throw new ScriptException("The default texture group doesn't exist??? (this shouldn't happen)");
fontTexGroup.Fonts.Add(new UndertaleResourceById<UndertaleFont, UndertaleChunkFONT>() { Resource = font });
}
}
else if (attemptToFixFontNotAppearing)
{
// Try to find the texgroup that the font belongs to
// Scariest LINQ query I've ever written (yet)
fontTexGroup = Data.TextureGroupInfo
.Where(t => t.Fonts.Any(f => f.Resource == font))
.DefaultIfEmpty(fontTexGroup)
.FirstOrDefault();
if (fontTexGroup == null)
throw new ScriptException("Existing font doesn't belong to any texture group AND the default texture group doesn't exist??? (this shouldn't happen)");
// Failsafe - put it in Default if it's not in there
if (!fontTexGroup.Fonts.Any(f => f.Resource == font))
fontTexGroup.Fonts.Add(new UndertaleResourceById<UndertaleFont, UndertaleChunkFONT>() { Resource = font });
}

// Prepare font texture
Bitmap textureBitmap = new Bitmap(fontTexturePath);
// Make the DPI exactly 96 for this bitmap
textureBitmap.SetResolution(96.0F, 96.0F);

UndertaleEmbeddedTexture texture = new UndertaleEmbeddedTexture();
// ??? Why?
texture.Name = new UndertaleString("Texture " + Data.EmbeddedTextures.Count);
texture.TextureData.TextureBlob = File.ReadAllBytes(fontTexturePath);
Data.EmbeddedTextures.Add(texture);
if (attemptToFixFontNotAppearing)
fontTexGroup.TexturePages.Add(new UndertaleResourceById<UndertaleEmbeddedTexture, UndertaleChunkTXTR>() { Resource = texture });

UndertaleTexturePageItem texturePageItem = new UndertaleTexturePageItem();
// ??? Same as above
texturePageItem.Name = new UndertaleString("PageItem " + Data.TexturePageItems.Count);
texturePageItem.TexturePage = texture;
texturePageItem.SourceX = 0;
texturePageItem.SourceY = 0;
texturePageItem.SourceWidth = (ushort)textureBitmap.Width;
texturePageItem.SourceHeight = (ushort)textureBitmap.Height;
texturePageItem.TargetX = 0;
texturePageItem.TargetY = 0;
texturePageItem.TargetWidth = (ushort)textureBitmap.Width;
texturePageItem.TargetHeight = (ushort)textureBitmap.Height;
texturePageItem.BoundingWidth = (ushort)textureBitmap.Width;
texturePageItem.BoundingHeight = (ushort)textureBitmap.Height;
Data.TexturePageItems.Add(texturePageItem);

font.DisplayName = Data.Strings.MakeString((string)fontData["fontName"]);
font.Texture = texturePageItem;
font.Bold = (bool)fontData["bold"];
font.Italic = (bool)fontData["italic"];
// FIXME: Potentially causes float precision to be lost
font.EmSize = (uint)fontData["size"];
// Save font size as a float in GMS2.3+ (shouldn't UML always save EmSize as a float for GMS2.3+ games??)
font.EmSizeIsFloat = Data.IsVersionAtLeast(2, 3);
font.Charset = (byte)fontData["charset"];
font.AntiAliasing = (byte)fontData["AntiAlias"];
// FIXME: ??? All YY files I've saw don't contain this
font.ScaleX = 1;
font.ScaleY = 1;
// Ascender is GM2022.2+
if (fontData.ContainsKey("ascender"))
font.Ascender = (uint)fontData["ascender"];
if (fontData.ContainsKey("ascenderOffset"))
font.AscenderOffset = (int)fontData["ascenderOffset"];
// TODO: SDFSpread

// FIXME: Too complicated?
List<int> charRangesUppersAndLowers = new();
foreach (JObject range in fontData["ranges"].Values<JObject>())
{
charRangesUppersAndLowers.Add((int)range["upper"]);
charRangesUppersAndLowers.Add((int)range["lower"]);
}
charRangesUppersAndLowers.Sort();
// FIXME: Check the range by ourselves if ranges don't have it probably
font.RangeStart = (ushort)charRangesUppersAndLowers.DefaultIfEmpty(0).FirstOrDefault();
font.RangeEnd = (uint)charRangesUppersAndLowers.DefaultIfEmpty(0xFFFF).LastOrDefault();

List<UndertaleFont.Glyph> glyphs = new();
// From what I've seen, the keys of the objects in glyphs is just the character property of the object itself but in string form
foreach (KeyValuePair<string, JToken> glyphKVEntry in (JObject)fontData["glyphs"])
{
var glyphData = (JObject)glyphKVEntry.Value;
glyphs.Add(new UndertaleFont.Glyph()
{
Character = (ushort)glyphData["character"],
SourceX = (ushort)glyphData["x"],
SourceY = (ushort)glyphData["y"],
SourceWidth = (ushort)glyphData["w"],
SourceHeight = (ushort)glyphData["h"],
Shift = (short)glyphData["shift"],
Offset = (short)glyphData["offset"],
});
}
// Sort glyphs like UndertaleFontEditor to be safe
glyphs.Sort((x, y) => x.Character.CompareTo(y.Character));
font.Glyphs.Clear();
foreach (var glyph in glyphs)
font.Glyphs.Add(glyph);

glyphs = font.Glyphs.ToList();
foreach (JObject kerningPair in fontData["kerningPairs"]?.Values<JObject>())
{
// Why do I need to do this. Thanks YoYo
var first = (ushort)kerningPair["first"];
var glyph = glyphs.Find(x => x.Character == first);
glyph.Kerning.Add(new UndertaleFont.Glyph.GlyphKerning()
{
Character = (short)kerningPair["second"],
ShiftModifier = (short)kerningPair["amount"],
});
}

ScriptMessage("Import complete.");

0 comments on commit 008425a

Please sign in to comment.