Skip to content

Commit befdb9e

Browse files
committed
Added options for game file builder
Cache stock prefabs
1 parent 0d67a6a commit befdb9e

10 files changed

+361
-27
lines changed

Dlls/FancadeLoaderLib.Editing.dll

0 Bytes
Binary file not shown.

Dlls/FancadeLoaderLib.dll

3 KB
Binary file not shown.

FanScript.Cli/Program.cs

+23-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using FanScript.Utils;
99
using MathUtils.Vectors;
1010
using TextCopy;
11+
1112
#if DEBUG
1213
using System.Diagnostics;
1314
#endif
@@ -37,6 +38,21 @@ public class BuildOptions
3738

3839
[Option("showCompiled", Default = false, Required = false, HelpText = "If the compiled code should be displayed.")]
3940
public bool ShowCompiledCode { get; set; }
41+
42+
// builder options
43+
[Option("inGameFile", Default = null, Required = false, HelpText = "(Only used with GameFileBuilder) Path to the game file that will be used by GameFile builder, this file will not be overwriten. If not supplied, a new game is created.")]
44+
public string? InGameFile { get; set; }
45+
46+
[Option("useExistingPrefab", Default = false, Required = false, HelpText = "(Only used with GameFileBuilder) If true an existing prefab from InGameFile will be used (prefabIndex) otherwise a new prefab wiil be created (prefabName, prefabType).")]
47+
public bool UseExistingPrefab { get; set; }
48+
49+
[Option("prefabName", SetName = "gfb_new", Default = "New Block", Required = false, HelpText = "(Only used with GameFileBuilder) Name of the new prefab, in which code will get placed.")]
50+
public string PrefabName { get; set; }
51+
[Option("prefabType", SetName = "gfb_new", Default = PrefabType.Script, Required = false, HelpText = $"(Only used with GameFileBuilder) Type of the new prefab, in which code will get placed. Values: {nameof(PrefabType.Normal)}, {nameof(PrefabType.Physics)}, {nameof(PrefabType.Script)}, {nameof(PrefabType.Level)}.")]
52+
public PrefabType PrefabType { get; set; }
53+
54+
[Option("prefabIndex", SetName = "gfb_existing", Default = (ushort)0, Required = false, HelpText = "(Only used with GameFileBuilder)Index of the custom prefab that code will get placed in. NOT the prefab's id, but it's index as a custom prefab - the first custom prefab would be id 597 and INDEX 0.")]
55+
public ushort PrefabIndex { get; set; }
4056
}
4157
#pragma warning restore CS8618
4258

@@ -155,7 +171,13 @@ static int runBuild(BuildOptions opts)
155171
break;
156172
case CodeBuilderEnum.GameFile:
157173
{
158-
Game game = (Game)builder.Build(pos);
174+
GameFileBlockBuilder.Args args;
175+
if (opts.UseExistingPrefab)
176+
args = new(opts.InGameFile, opts.PrefabIndex);
177+
else
178+
args = new(opts.InGameFile, opts.PrefabName, opts.PrefabType);
179+
180+
Game game = (Game)builder.Build(pos, args);
159181

160182
game.TrimPrefabs();
161183

FanScript/Compiler/Emit/BlockBuilder.cs

+6-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public virtual void Connect(ConnectTarget from, ConnectTarget to)
4141
public virtual void SetBlockValue(Block block, int valueIndex, object value)
4242
=> values.Add(new ValueRecord(block, valueIndex, value));
4343

44-
public abstract object Build(Vector3I posToBuildAt, params object[] args);
44+
public abstract object Build(Vector3I posToBuildAt, IArgs? args = null);
4545

4646
protected Block[] PreBuild(Vector3I posToBuildAt, bool sortByPos)
4747
{
@@ -56,7 +56,7 @@ protected Block[] PreBuild(Vector3I posToBuildAt, bool sortByPos)
5656
for (int i = 0; i < segments.Count; i++)
5757
{
5858
totalBlockCount += segments[i].Blocks.Length;
59-
segmentSizes[i] = segments[i].Size + new Vector3I(2, 0, 2); // margin
59+
segmentSizes[i] = segments[i].Size + new Vector3I(2, 1, 2); // margin
6060
}
6161

6262
Vector3I[] segmentPositions = BinPacker.Compute(segmentSizes);
@@ -167,5 +167,9 @@ private void calculateMinMax()
167167
MaxPos = max - Vector3I.One;
168168
}
169169
}
170+
171+
public interface IArgs
172+
{
173+
}
170174
}
171175
}

FanScript/Compiler/Emit/BlockBuilders/EditorScriptBlockBuilder.cs

+18-9
Original file line numberDiff line numberDiff line change
@@ -125,26 +125,23 @@ public class EditorScriptBlockBuilder : BlockBuilder
125125
///
126126
/// </summary>
127127
/// <param name="startPos"></param>
128-
/// <param name="args">0: [optional] <see cref="Compression"/></param>
128+
/// <param name="_args">Must be null or <see cref="Args"/></param>
129129
/// <returns>The editor script (js) to build the code</returns>
130130
/// <exception cref="Exception"></exception>
131-
public override object Build(Vector3I startPos, params object[] args)
131+
public override string Build(Vector3I startPos, IArgs? _args)
132132
{
133-
Block[] blocks = PreBuild(startPos, sortByPos: true); // sortByPos is requred because of a bug that sometimes deletes objects if they are placed from +Z to -Z, even if they aren't overlaping
134-
135-
Compression compression = Compression.Base64;
133+
Args args = (_args as Args) ?? Args.Default;
136134

137-
if (args.Length > 0 && args[0] is Compression comp)
138-
compression = comp;
135+
Block[] blocks = PreBuild(startPos, sortByPos: true); // sortByPos is requred because of a bug that sometimes deletes objects if they are placed from +Z to -Z, even if they aren't overlaping
139136

140-
switch (compression)
137+
switch (args.Compression)
141138
{
142139
case Compression.None:
143140
return buildNormal(blocks);
144141
case Compression.Base64:
145142
return buildBase64(blocks);
146143
default:
147-
throw new Exception($"Unsuported compression: {compression}");
144+
throw new Exception($"Unsuported compression: {args.Compression}");
148145
}
149146
}
150147

@@ -314,5 +311,17 @@ public enum Compression
314311
None,
315312
Base64,
316313
}
314+
315+
public sealed class Args : IArgs
316+
{
317+
public static readonly Args Default = new Args(Compression.Base64);
318+
319+
public readonly Compression Compression;
320+
321+
public Args(Compression compression)
322+
{
323+
Compression = compression;
324+
}
325+
}
317326
}
318327
}

FanScript/Compiler/Emit/BlockBuilders/GameFileBlockBuilder.cs

+79-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using FancadeLoaderLib;
22
using FancadeLoaderLib.Editing.Utils;
33
using FancadeLoaderLib.Partial;
4+
using FanScript.Utils;
45
using MathUtils.Vectors;
6+
using System.Diagnostics.CodeAnalysis;
57

68
/*
79
log("Block id: " + getBlock(0, 0, 0));
@@ -24,26 +26,56 @@ public class GameFileBlockBuilder : BlockBuilder
2426
///
2527
/// </summary>
2628
/// <param name="startPos"></param>
27-
/// <param name="args">In any order - [optional] <see cref="Game"/> (Game to write to), [optional] <see langword="int"/> (Index of level to write to)</param>
29+
/// <param name="_args">Must be null or <see cref="Args"/></param>
2830
/// <returns>The <see cref="Game"/> object that was written to</returns>
2931
/// <exception cref="InvalidDataException"></exception>
30-
public override object Build(Vector3I startPos, params object[] args)
32+
public override Game Build(Vector3I startPos, IArgs? _args)
3133
{
32-
Game game = (args?.FirstOrDefault(arg => arg is Game) as Game) ?? new Game("My game");
33-
int prefabIndex = (args?.FirstOrDefault(arg => arg is int) as int?) ?? 0;
34+
Args args = (_args as Args) ?? Args.Default;
3435

35-
if (!game.Prefabs.Any())
36-
game.Prefabs.Add(Prefab.CreateLevel("Level 1"));
36+
Game game;
37+
if (string.IsNullOrEmpty(args.InGameFile))
38+
game = new Game("FanScript");
39+
else
40+
{
41+
using (FileStream fs = File.OpenRead(args.InGameFile))
42+
game = Game.LoadCompressed(fs);
43+
}
3744

38-
prefabIndex = Math.Clamp(prefabIndex, 0, game.Prefabs.Count - 1);
45+
Prefab prefab;
46+
if (args.CreateNewPrefab)
47+
{
48+
if (args.PrefabType == PrefabType.Level)
49+
{
50+
prefab = Prefab.CreateLevel(args.PrefabName);
3951

40-
Block[] blocks = PreBuild(startPos, false);
52+
int index = 0;
4153

42-
PartialPrefabList stockPrefabs;
43-
using (FcBinaryReader reader = new FcBinaryReader("stockPrefabs.fcppl")) // fcppl - Fancade partial prefab list
44-
stockPrefabs = PartialPrefabList.Load(reader);
54+
while (index < game.Prefabs.Count && game.Prefabs[index].Type == PrefabType.Level)
55+
index++;
56+
57+
game.Prefabs.Insert(index, prefab);
58+
}
59+
else
60+
{
61+
prefab = Prefab.CreateBlock(args.PrefabName);
62+
prefab.Type = args.PrefabType.Value;
63+
prefab.Voxels = BlockVoxelsGenerator.CreateScript(Vector2I.One).First().Value;
64+
65+
game.Prefabs.Add(prefab);
66+
}
67+
}
68+
else
69+
{
70+
if (args.PrefabIndex < 0 || args.PrefabIndex >= game.Prefabs.Count)
71+
throw new IndexOutOfRangeException($"PrefabIndex must be greater or equal to 0 and smaller than the number of prefabs ({game.Prefabs.Count}).");
72+
73+
prefab = game.Prefabs[args.PrefabIndex.Value];
74+
}
75+
76+
Block[] blocks = PreBuild(startPos, false);
4577

46-
Prefab prefab = game.Prefabs[prefabIndex];
78+
PartialPrefabList stockPrefabs = StockPrefabs.Instance.List;
4779

4880
Dictionary<ushort, PartialPrefabGroup> groupCache = new();
4981

@@ -99,5 +131,40 @@ public override object Build(Vector3I startPos, params object[] args)
99131

100132
return game;
101133
}
134+
135+
public sealed class Args : IArgs
136+
{
137+
public static readonly Args Default = new Args(null, "New Block", FancadeLoaderLib.PrefabType.Script);
138+
139+
public readonly string? InGameFile;
140+
141+
[MemberNotNullWhen(true, nameof(PrefabName), nameof(PrefabType))]
142+
[MemberNotNullWhen(false, nameof(PrefabIndex))]
143+
public bool CreateNewPrefab { get; private set; }
144+
145+
public readonly string? PrefabName;
146+
public readonly PrefabType? PrefabType;
147+
148+
public readonly ushort? PrefabIndex;
149+
150+
public Args(string? inGameFile, string prefabName, PrefabType prefabType)
151+
{
152+
InGameFile = inGameFile;
153+
154+
CreateNewPrefab = true;
155+
156+
PrefabName = prefabName;
157+
PrefabType = prefabType;
158+
}
159+
160+
public Args(string? inGameFile, ushort prefabIndex)
161+
{
162+
InGameFile = inGameFile;
163+
164+
CreateNewPrefab = false;
165+
166+
PrefabIndex = prefabIndex;
167+
}
168+
}
102169
}
103170
}

FanScript/Compiler/Symbols/BuiltinFunctions.cs

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using FanScript.Compiler.Binding;
1+
using FancadeLoaderLib.Editing.Utils;
2+
using FancadeLoaderLib.Partial;
3+
using FancadeLoaderLib.Raw;
4+
using FanScript.Compiler.Binding;
25
using FanScript.Compiler.Emit;
36
using FanScript.Compiler.Emit.Utils;
47
using FanScript.Compiler.Symbols.Variables;
@@ -2429,8 +2432,25 @@ public static readonly FunctionSymbol GetBlockById
24292432
float _id = (constants[0] as float?) ?? 0f;
24302433
ushort id = (ushort)System.Math.Clamp((int)_id, ushort.MinValue, ushort.MaxValue);
24312434

2432-
// TODO: somehow calculate the size, for now just use the largest stock one
2433-
Block block = context.AddBlock(new BlockDef(string.Empty, id, BlockType.NonScript, new Vector2I(2, 4)));
2435+
BlockDef def;
2436+
if (id < RawGame.CurrentNumbStockPrefabs)
2437+
{
2438+
var groupEnumerable = StockPrefabs.Instance.List.GetGroup(id);
2439+
2440+
if (groupEnumerable.Any())
2441+
{
2442+
PartialPrefabGroup group = new PartialPrefabGroup(groupEnumerable);
2443+
PartialPrefab mainPrefab = group[Vector3B.Zero];
2444+
2445+
def = new BlockDef(mainPrefab.Name, id, BlockType.NonScript, group.Size, []);
2446+
}
2447+
else
2448+
def = new BlockDef(string.Empty, id, BlockType.NonScript, new Vector2I(1, 1));
2449+
}
2450+
else
2451+
def = new BlockDef(string.Empty, id, BlockType.NonScript, new Vector2I(1, 1));
2452+
2453+
Block block = context.AddBlock(def);
24342454

24352455
if (!context.Builder.PlatformInfo.HasFlag(BuildPlatformInfo.CanGetBlocks))
24362456
{

FanScript/FanScript.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<PropertyGroup>
1111
<AssemblyVersion>$(Version)</AssemblyVersion>
1212
<FileVersion>$(Version)</FileVersion>
13+
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
1314
</PropertyGroup>
1415

1516
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

0 commit comments

Comments
 (0)