diff --git a/LDtk.Codegen/Generators/BaseGenerator.cs b/LDtk.Codegen/Generators/BaseGenerator.cs index 85eb19f3..5952d10c 100644 --- a/LDtk.Codegen/Generators/BaseGenerator.cs +++ b/LDtk.Codegen/Generators/BaseGenerator.cs @@ -31,6 +31,18 @@ public void EndBlock() Line("}"); } + public void EndBlockSeparator() + { + indent--; + Line("},"); + } + + public void EndCodeBlock() + { + indent--; + Line("};"); + } + public static string Call(string functionName, string contents) { return $"{functionName}({contents})"; diff --git a/LDtk.Codegen/Generators/ClassGenerator.cs b/LDtk.Codegen/Generators/ClassGenerator.cs index 52763756..e8f989a3 100644 --- a/LDtk.Codegen/Generators/ClassGenerator.cs +++ b/LDtk.Codegen/Generators/ClassGenerator.cs @@ -1,72 +1,222 @@ namespace LDtk.Codegen.Generators; -using LDtk.Codegen; -using LDtk.Full; +using System.Globalization; +using System.Linq; +using System.Text.Json; + +using Full; public class ClassGenerator(LDtkFileFull ldtkFile, Options options) : BaseGenerator(ldtkFile, options) { public void Generate() { // Level Classes - GenClass(Options.LevelClassName, LDtkFile.Defs.LevelFields, string.Empty, false); + GenClass(Options.LevelClassName, string.Empty, fieldDefinitions: LDtkFile.Defs.LevelFields); // Entity Classes foreach (EntityDefinition e in LDtkFile.Defs.Entities) { - GenClass(e.Identifier, e.FieldDefs, "Entities", true); + GenClass(e.Identifier, "Entities", e); } } - void GenClass(string identifier, FieldDefinition[] fields, string folder, bool isEntity) + void GenClass(string identifier, string folder, EntityDefinition entityDefinition = null, + FieldDefinition[] fieldDefinitions = null) { - Line($"namespace {Options.Namespace};"); - Blank(); - Line("// This file was automatically generated, any modifications will be lost!"); - Line("#pragma warning disable"); - Blank(); - Line("using LDtk;"); - Line("using Microsoft.Xna.Framework;"); - Blank(); + GenHeaders(); string classDef = $"public partial class {identifier}"; - if (isEntity && Options.EntityInterface) + if (entityDefinition != null && Options.EntityInterface) { classDef += " : ILDtkEntity"; } Line(classDef); + + StartBlock(); + { + if (entityDefinition != null) + { + GenEntityFields(identifier, entityDefinition); + } + else if (fieldDefinitions != null) + { + GenFieldDefs(fieldDefinitions); + } + } + EndBlock(); + + Line("#pragma warning restore"); + Output(folder, identifier); + } + + void GenEntityFields(string identifier, EntityDefinition entityDefinition) + { + //generate the default data for fields. + Line($"public static {identifier} Default() => new()"); StartBlock(); { - if (isEntity) + Line($"Identifier = \"{identifier}\","); + Line($"Uid = {entityDefinition.Uid},"); + Line($"Size = new Vector2({entityDefinition.Width}f, {entityDefinition.Height}f),"); + Line($"Pivot = new Vector2({entityDefinition.PivotX}f, {entityDefinition.PivotY}f),"); + if (entityDefinition.TileRect != null) + { + GenTilesetRectangle("Tile", entityDefinition.TileRect); + } + + byte r = entityDefinition.Color.R; + byte g = entityDefinition.Color.G; + byte b = entityDefinition.Color.B; + byte a = entityDefinition.Color.A; + + Line($"SmartColor = new Color({r}, {g}, {b}, {a}),"); + + //generate default data for custom fields + GenCustomFieldDefData(entityDefinition.FieldDefs); + } + EndCodeBlock(); + Blank(); + + //generate the rest of the class + Line("public string Identifier { get; set; }"); + Line("public System.Guid Iid { get; set; }"); + Line("public int Uid { get; set; }"); + Line("public Vector2 Position { get; set; }"); + Line("public Vector2 Size { get; set; }"); + Line("public Vector2 Pivot { get; set; }"); + Line("public Rectangle Tile { get; set; }"); + Blank(); + Line("public Color SmartColor { get; set; }"); + + FieldDefinition[] fields = entityDefinition.FieldDefs; + GenFieldDefs(fields); + } + + void GenFieldDefs(FieldDefinition[] fields) + { + if (fields.Length > 0) + { + Blank(); + } + + foreach (FieldDefinition value in fields) + { + string type = Converter.ConvertFieldDefinitionTypes(value._Type, Options.PointAsVector2); + + if (value.CanBeNull) + { + type += "?"; + } + + Line($"public {type} {value.Identifier} {{ get; set; }}"); + } + } + + void GenCustomFieldDefData(FieldDefinition[] fieldDefs) + { + if (fieldDefs.Length > 0) + { + Blank(); + } + + foreach (FieldDefinition field in fieldDefs) + { + if (field.DefaultOverride == null) { - Line("public string Identifier { get; set; }"); - Line("public System.Guid Iid { get; set; }"); - Line("public int Uid { get; set; }"); - Line("public Vector2 Position { get; set; }"); - Line("public Vector2 Size { get; set; }"); - Line("public Vector2 Pivot { get; set; }"); - Line("public Rectangle Tile { get; set; }"); - Blank(); - Line("public Color SmartColor { get; set; }"); - Blank(); + continue; } - foreach (FieldDefinition value in fields) + if (field.DefaultOverride.Params.ValueKind != JsonValueKind.Array) { - string type = Converter.ConvertFieldDefinitionTypes(value._Type, Options.PointAsVector2); + continue; + } + + JsonElement defaultValue = field.DefaultOverride.Params.EnumerateArray().First(); + + if (field._Type.Contains("Enum")) + { + string enumName = field._Type.Replace("LocalEnum.", ""); + string value = defaultValue.GetString(); + string enumValue = $"{enumName}.{value}"; + + Line($"entity.{field.Identifier} = {enumValue};"); + } + + switch (field._Type) + { + case Field.IntType: + Line($"{field.Identifier} = {defaultValue.GetInt32()},"); + break; + + case Field.FloatType: + Line($"{field.Identifier} = {defaultValue.GetSingle().ToString(CultureInfo.InvariantCulture)}f,"); + break; + + case Field.BoolType: + Line($"{field.Identifier} = {defaultValue.GetBoolean().ToString().ToLower()},"); + break; - if (value.CanBeNull) + case Field.StringType: + Line($"{field.Identifier} = {defaultValue.GetRawText()},"); + break; + + case Field.FilePathType: + Line($"{field.Identifier} = {defaultValue.GetString()},"); + break; + + case Field.TileType: + string[] rectValues = defaultValue.GetString()!.Split(','); + int x = int.Parse(rectValues[0]); + int y = int.Parse(rectValues[1]); + int width = int.Parse(rectValues[2]); + int height = int.Parse(rectValues[3]); + int tilesetUid = (int)field.TilesetUid!; + TilesetRectangle finalRect = new() { - type += "?"; - } + X = x, + Y = y, + W = width, + H = height, + TilesetUid = tilesetUid + }; + GenTilesetRectangle(field.Identifier, finalRect); + break; - Line($"public {type} {value.Identifier} {{ get; set; }}"); + case Field.ColorType: + int colorValue = defaultValue.GetInt32(); + int r = (colorValue >> 16) & 0xFF; + int g = (colorValue >> 8) & 0xFF; + int b = colorValue & 0xFF; + Line($"{field.Identifier} = new Color({r}, {g}, {b}, {1}),"); + break; } } - EndBlock(); - Line("#pragma warning restore"); + } - Output(folder, identifier); + void GenHeaders() + { + Line($"namespace {Options.Namespace};"); + Blank(); + Line("// This file was automatically generated, any modifications will be lost!"); + Line("#pragma warning disable"); + Blank(); + Line("using LDtk;"); + Line("using Microsoft.Xna.Framework;"); + Blank(); + } + + void GenTilesetRectangle(string identifier, TilesetRectangle rect) + { + Line($"{identifier} = new TilesetRectangle()"); + StartBlock(); + { + Line($"X = {rect.X},"); + Line($"Y = {rect.Y},"); + Line($"W = {rect.W},"); + Line($"H = {rect.H}"); + } + EndBlockSeparator(); } } diff --git a/LDtk.Example/Entry.cs b/LDtk.Example/Entry.cs index 1d13ac9f..949359b8 100644 --- a/LDtk.Example/Entry.cs +++ b/LDtk.Example/Entry.cs @@ -117,6 +117,15 @@ protected override void Initialize() _ = renderer.PrerenderLevel(world.Levels[i]); } + // Default value instance example + var prefab = Enemy.Default(); + prefab.Wander = new Vector2[] { Vector2.One * 180, Vector2.One * 120 }; + enemies.Add(new EnemyEntity(prefab, spriteSheet, renderer)); + + var prefab2 = Enemy.Default(); + prefab2.Wander = new Vector2[] { Vector2.One * 200, Vector2.One * 100 }; + enemies.Add(new EnemyEntity(prefab2, spriteSheet, renderer)); + Gun_Pickup gunData = world.GetEntity(); gun = new GunEntity(gunData, spriteSheet, renderer); diff --git a/LDtk.Example/LDtkTypes/World/CustomLevelDataName.cs b/LDtk.Example/LDtkTypes/World/CustomLevelDataName.cs index 4f14acdb..009f5b26 100644 --- a/LDtk.Example/LDtkTypes/World/CustomLevelDataName.cs +++ b/LDtk.Example/LDtkTypes/World/CustomLevelDataName.cs @@ -4,11 +4,11 @@ namespace LDtkTypes; #pragma warning disable using LDtk; - using Microsoft.Xna.Framework; public partial class CustomLevelDataName { + public float Float { get; set; } public TilesetRectangle[] Tile { get; set; } public string? Multilines { get; set; } diff --git a/LDtk.Example/LDtkTypes/World/Entities/Enemy.cs b/LDtk.Example/LDtkTypes/World/Entities/Enemy.cs index 2b8e00ab..1ef21ac0 100644 --- a/LDtk.Example/LDtkTypes/World/Entities/Enemy.cs +++ b/LDtk.Example/LDtkTypes/World/Entities/Enemy.cs @@ -4,11 +4,28 @@ namespace LDtkTypes; #pragma warning disable using LDtk; - using Microsoft.Xna.Framework; public partial class Enemy : ILDtkEntity { + public static Enemy Default() => new() + { + Identifier = "Enemy", + Uid = 98, + Size = new Vector2(16f, 16f), + Pivot = new Vector2(0.5f, 0.5f), + Tile = new TilesetRectangle() + { + X = 16, + Y = 16, + W = 16, + H = 16 + }, + SmartColor = new Color(255, 107, 25, 255), + + Color = new Color(166, 80, 80, 1), + }; + public string Identifier { get; set; } public System.Guid Iid { get; set; } public int Uid { get; set; } diff --git a/LDtk.Example/LDtkTypes/World/Entities/Gun_Pickup.cs b/LDtk.Example/LDtkTypes/World/Entities/Gun_Pickup.cs index 1300e5cc..c00923d8 100644 --- a/LDtk.Example/LDtkTypes/World/Entities/Gun_Pickup.cs +++ b/LDtk.Example/LDtkTypes/World/Entities/Gun_Pickup.cs @@ -4,11 +4,26 @@ namespace LDtkTypes; #pragma warning disable using LDtk; - using Microsoft.Xna.Framework; public partial class Gun_Pickup : ILDtkEntity { + public static Gun_Pickup Default() => new() + { + Identifier = "Gun_Pickup", + Uid = 107, + Size = new Vector2(16f, 16f), + Pivot = new Vector2(0.5f, 1f), + Tile = new TilesetRectangle() + { + X = 0, + Y = 16, + W = 16, + H = 16 + }, + SmartColor = new Color(75, 224, 96, 255), + }; + public string Identifier { get; set; } public System.Guid Iid { get; set; } public int Uid { get; set; } @@ -18,6 +33,5 @@ public partial class Gun_Pickup : ILDtkEntity public Rectangle Tile { get; set; } public Color SmartColor { get; set; } - } #pragma warning restore diff --git a/LDtk.Example/LDtkTypes/World/Entities/Player.cs b/LDtk.Example/LDtkTypes/World/Entities/Player.cs index 31430479..818678f0 100644 --- a/LDtk.Example/LDtkTypes/World/Entities/Player.cs +++ b/LDtk.Example/LDtkTypes/World/Entities/Player.cs @@ -4,11 +4,26 @@ namespace LDtkTypes; #pragma warning disable using LDtk; - using Microsoft.Xna.Framework; public partial class Player : ILDtkEntity { + public static Player Default() => new() + { + Identifier = "Player", + Uid = 120, + Size = new Vector2(16f, 16f), + Pivot = new Vector2(0.5f, 0.5f), + Tile = new TilesetRectangle() + { + X = 80, + Y = 0, + W = 16, + H = 16 + }, + SmartColor = new Color(148, 217, 179, 255), + }; + public string Identifier { get; set; } public System.Guid Iid { get; set; } public int Uid { get; set; } @@ -18,6 +33,5 @@ public partial class Player : ILDtkEntity public Rectangle Tile { get; set; } public Color SmartColor { get; set; } - } #pragma warning restore diff --git a/LDtk.Example/LDtkTypes/World/Entities/RefTest.cs b/LDtk.Example/LDtkTypes/World/Entities/RefTest.cs index da916e13..b137c80e 100644 --- a/LDtk.Example/LDtkTypes/World/Entities/RefTest.cs +++ b/LDtk.Example/LDtkTypes/World/Entities/RefTest.cs @@ -4,11 +4,34 @@ namespace LDtkTypes; #pragma warning disable using LDtk; - using Microsoft.Xna.Framework; public partial class RefTest : ILDtkEntity { + public static RefTest Default() => new() + { + Identifier = "RefTest", + Uid = 123, + Size = new Vector2(16f, 16f), + Pivot = new Vector2(0f, 0f), + Tile = new TilesetRectangle() + { + X = 16, + Y = 48, + W = 16, + H = 16 + }, + SmartColor = new Color(148, 217, 179, 255), + + TileTest = new TilesetRectangle() + { + X = 112, + Y = 32, + W = 16, + H = 16 + }, + }; + public string Identifier { get; set; } public System.Guid Iid { get; set; } public int Uid { get; set; } diff --git a/LDtk.JsonSchema/Program.cs b/LDtk.JsonSchema/Program.cs index c7a6e634..7582a7f7 100644 --- a/LDtk.JsonSchema/Program.cs +++ b/LDtk.JsonSchema/Program.cs @@ -69,6 +69,9 @@ public static partial class Program {"AutoRuleDef", new() { {"TileRectsIds","int[][]"}, }}, + {"FieldDefinition", new () { + {"DefaultOverride", "DefaultOverride"} + }}, }; static readonly Dictionary Enums = new(); diff --git a/LDtk/DefaultOverride.cs b/LDtk/DefaultOverride.cs new file mode 100644 index 00000000..0aa2c62b --- /dev/null +++ b/LDtk/DefaultOverride.cs @@ -0,0 +1,13 @@ +namespace LDtk; + +using System.Text.Json; +using System.Text.Json.Serialization; + +public class DefaultOverride +{ + [JsonPropertyName("id")] + public required string Id { get; set; } + + [JsonPropertyName("params")] + public JsonElement Params { get; set; } +} diff --git a/LDtk/Field.cs b/LDtk/Field.cs index eddd8eb0..72410dc7 100644 --- a/LDtk/Field.cs +++ b/LDtk/Field.cs @@ -1,6 +1,6 @@ namespace LDtk; -static class Field +public static class Field { public const string IntType = "Int"; public const string IntArrayType = "Array"; diff --git a/LDtk/Full/LDtkJsonFull.cs b/LDtk/Full/LDtkJsonFull.cs index ef88c8f3..54dc7fe8 100644 --- a/LDtk/Full/LDtkJsonFull.cs +++ b/LDtk/Full/LDtkJsonFull.cs @@ -521,6 +521,7 @@ public partial class EntityDefinition /// Pixel width [JsonPropertyName("width")] public int Width { get; set; } + } /// Entity instance @@ -712,7 +713,7 @@ public partial class FieldDefinition /// Default value if selected value is null or invalid. [JsonPropertyName("defaultOverride")] - public object DefaultOverride { get; set; } + public DefaultOverride DefaultOverride { get; set; } /// User defined documentation for this field to provide help/tips to level designers about accepted values. [JsonPropertyName("doc")] @@ -814,7 +815,6 @@ public partial class FieldDefinition [JsonPropertyName("useForSmartColor")] public bool UseForSmartColor { get; set; } } - /// Field instance public partial class FieldInstance { diff --git a/LDtk/LDtkFieldParser.cs b/LDtk/LDtkFieldParser.cs index 741779a2..ae94afd8 100644 --- a/LDtk/LDtkFieldParser.cs +++ b/LDtk/LDtkFieldParser.cs @@ -7,6 +7,7 @@ namespace LDtk; using Microsoft.Xna.Framework; + /// Utility for parsing ldtk json data into more typed versions. static class LDtkFieldParser {