Add map support for inline base64 fluent messages.
This enables the RC to parse and share custom messages as part of the map's custom rules without any additional API changes.
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using OpenRA.FileSystem;
|
||||
|
||||
namespace OpenRA
|
||||
@@ -25,9 +27,25 @@ namespace OpenRA
|
||||
lock (SyncObject)
|
||||
{
|
||||
modFluentBundle = new FluentBundle(Game.Settings.Player.Language, modData.Manifest.Translations, fileSystem);
|
||||
mapFluentBundle = fileSystem is Map map && map.FluentMessageDefinitions != null
|
||||
? new FluentBundle(Game.Settings.Player.Language, FieldLoader.GetValue<string[]>("value", map.FluentMessageDefinitions.Value), fileSystem)
|
||||
: null;
|
||||
if (fileSystem is Map map && map.FluentMessageDefinitions != null)
|
||||
{
|
||||
var files = Array.Empty<string>();
|
||||
if (map.FluentMessageDefinitions.Value != null)
|
||||
files = FieldLoader.GetValue<string[]>("value", map.FluentMessageDefinitions.Value);
|
||||
|
||||
string text = null;
|
||||
if (map.FluentMessageDefinitions.Nodes.Length > 0)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var node in map.FluentMessageDefinitions.Nodes)
|
||||
if (node.Key == "base64")
|
||||
builder.Append(Encoding.UTF8.GetString(Convert.FromBase64String(node.Value.Value)));
|
||||
|
||||
text = builder.ToString();
|
||||
}
|
||||
|
||||
mapFluentBundle = new FluentBundle(Game.Settings.Player.Language, files, fileSystem, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,13 +122,32 @@ namespace OpenRA
|
||||
NotificationDefinitions = LoadRuleSection(yaml, "Notifications");
|
||||
SequenceDefinitions = LoadRuleSection(yaml, "Sequences");
|
||||
ModelSequenceDefinitions = LoadRuleSection(yaml, "ModelSequences");
|
||||
|
||||
FluentBundle = yaml.TryGetValue("Translations", out var node) && node != null
|
||||
? new FluentBundle(Game.Settings.Player.Language, FieldLoader.GetValue<string[]>("value", node.Value), fileSystem)
|
||||
: null;
|
||||
FluentMessageDefinitions = LoadRuleSection(yaml, "Translations");
|
||||
|
||||
try
|
||||
{
|
||||
if (FluentMessageDefinitions != null)
|
||||
{
|
||||
var files = Array.Empty<string>();
|
||||
if (FluentMessageDefinitions.Value != null)
|
||||
files = FieldLoader.GetValue<string[]>("value", FluentMessageDefinitions.Value);
|
||||
|
||||
string text = null;
|
||||
if (FluentMessageDefinitions.Nodes.Length > 0)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var node in FluentMessageDefinitions.Nodes)
|
||||
if (node.Key == "base64")
|
||||
builder.Append(Encoding.UTF8.GetString(Convert.FromBase64String(node.Value.Value)));
|
||||
|
||||
text = builder.ToString();
|
||||
}
|
||||
|
||||
FluentBundle = new FluentBundle(Game.Settings.Player.Language, files, fileSystem, text);
|
||||
}
|
||||
else
|
||||
FluentBundle = null;
|
||||
|
||||
// PERF: Implement a minimal custom loader for custom world and player actors to minimize loading time
|
||||
// This assumes/enforces that these actor types can only inherit abstract definitions (starting with ^)
|
||||
if (RuleDefinitions != null)
|
||||
|
||||
@@ -71,6 +71,11 @@ namespace OpenRA.Mods.Common.Lint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (map.FluentMessageDefinitions.Nodes.Length > 0)
|
||||
emitWarning(
|
||||
$"Lint pass ({nameof(CheckFluentReferences)}) lacks the know-how to test inline map fluent messages " +
|
||||
"- previous warnings may be incorrect");
|
||||
}
|
||||
|
||||
void ILintPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData)
|
||||
|
||||
@@ -47,6 +47,35 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
Console.WriteLine(output.ToLines(key).JoinWith("\n"));
|
||||
}
|
||||
|
||||
static void MergeAndPrintFluentMessages(Map map, string key, MiniYaml value)
|
||||
{
|
||||
var nodes = new List<MiniYamlNode>();
|
||||
var includes = new List<string>();
|
||||
if (value != null && value.Value != null)
|
||||
{
|
||||
// The order of the included files matter, so we can defer to system files
|
||||
// only as long as they are included first.
|
||||
var include = false;
|
||||
var files = FieldLoader.GetValue<string[]>("value", value.Value);
|
||||
foreach (var f in files)
|
||||
{
|
||||
include |= map.Package.Contains(f);
|
||||
if (include)
|
||||
{
|
||||
nodes.Add(new MiniYamlNode("base64", Convert.ToBase64String(map.Open(f).ReadAllBytes())));
|
||||
}
|
||||
else
|
||||
includes.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
nodes.AddRange(value.Nodes);
|
||||
|
||||
var output = new MiniYaml(includes.JoinWith(", "), nodes);
|
||||
Console.WriteLine(output.ToLines(key).JoinWith("\n"));
|
||||
}
|
||||
|
||||
[Desc("MAPFILE", "Merge custom map rules into a form suitable for including in map.yaml.")]
|
||||
void IUtilityCommand.Run(Utility utility, string[] args)
|
||||
{
|
||||
@@ -60,6 +89,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
||||
MergeAndPrint(map, "Voices", map.VoiceDefinitions);
|
||||
MergeAndPrint(map, "Music", map.MusicDefinitions);
|
||||
MergeAndPrint(map, "Notifications", map.NotificationDefinitions);
|
||||
MergeAndPrintFluentMessages(map, "Translations", map.FluentMessageDefinitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user