mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
ftl hot reloading (#5874)
* sloth is so going to kill me * the voices in my head told me to do this * Register ILocalizationManagerInternal on client * Avoid breaking change * Cleanup * Release notes
This commit is contained in:
@@ -39,7 +39,7 @@ END TEMPLATE-->
|
||||
|
||||
### New features
|
||||
|
||||
*None yet*
|
||||
* The client localisation manager now supports hot-reloading ftl files.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Clyde;
|
||||
using Robust.Client.HWId;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Localization;
|
||||
using Robust.Client.Map;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.Player;
|
||||
@@ -36,6 +37,7 @@ using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
@@ -104,6 +106,8 @@ namespace Robust.Client
|
||||
deps.Register<IGamePrototypeLoadManager, GamePrototypeLoadManager>();
|
||||
deps.Register<NetworkResourceManager>();
|
||||
deps.Register<IReloadManager, ReloadManager>();
|
||||
deps.Register<ILocalizationManager, ClientLocalizationManager>();
|
||||
deps.Register<ILocalizationManagerInternal, ClientLocalizationManager>();
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ using Robust.Shared.Configuration;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
@@ -94,6 +95,7 @@ namespace Robust.Client
|
||||
[Dependency] private readonly IReplayRecordingManagerInternal _replayRecording = default!;
|
||||
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
|
||||
[Dependency] private readonly IReloadManager _reload = default!;
|
||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
||||
|
||||
private IWebViewManagerHook? _webViewHook;
|
||||
|
||||
@@ -180,6 +182,7 @@ namespace Robust.Client
|
||||
_serializer.Initialize();
|
||||
_inputManager.Initialize();
|
||||
_console.Initialize();
|
||||
_loc.Initialize();
|
||||
|
||||
// Make sure this is done before we try to load prototypes,
|
||||
// avoid any possibility of race conditions causing the check to not finish
|
||||
|
||||
33
Robust.Client/Localization/ClientLocalizationManager.cs
Normal file
33
Robust.Client/Localization/ClientLocalizationManager.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client.Localization;
|
||||
|
||||
internal sealed class ClientLocalizationManager : LocalizationManager, ILocalizationManagerInternal
|
||||
{
|
||||
[Dependency] private readonly IReloadManager _reload = default!;
|
||||
|
||||
void ILocalizationManager.Initialize() => Initialize();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_reload.Register(LocaleDirPath, "*.ftl");
|
||||
|
||||
_reload.OnChanged += OnReload;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles Fluent hot reloading via LocalizationManager.ReloadLocalizations()
|
||||
/// </summary>
|
||||
private void OnReload(ResPath args)
|
||||
{
|
||||
if (args.Extension != "ftl")
|
||||
return;
|
||||
|
||||
ReloadLocalizations();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared;
|
||||
@@ -26,7 +25,6 @@ internal sealed class ReloadManager : IReloadManager
|
||||
private readonly TimeSpan _reloadDelay = TimeSpan.FromMilliseconds(10);
|
||||
private CancellationTokenSource _reloadToken = new();
|
||||
private readonly HashSet<ResPath> _reloadQueue = new();
|
||||
private List<FileSystemWatcher> _watchers = new();
|
||||
|
||||
public event Action<ResPath>? OnChanged;
|
||||
|
||||
@@ -69,6 +67,11 @@ internal sealed class ReloadManager : IReloadManager
|
||||
_reloadQueue.Clear();
|
||||
}
|
||||
|
||||
public void Register(ResPath directory, string filter)
|
||||
{
|
||||
Register(directory.ToString(), filter);
|
||||
}
|
||||
|
||||
public void Register(string directory, string filter)
|
||||
{
|
||||
if (!_cfg.GetCVar(CVars.ResPrototypeReloadWatch))
|
||||
@@ -90,7 +93,6 @@ internal sealed class ReloadManager : IReloadManager
|
||||
NotifyFilter = NotifyFilters.LastWrite
|
||||
};
|
||||
|
||||
_watchers.Add(watcher);
|
||||
|
||||
watcher.Changed += OnWatch;
|
||||
|
||||
@@ -100,7 +102,7 @@ internal sealed class ReloadManager : IReloadManager
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Logger.Error($"Watching resources in path {path} threw an exception:\n{ex}");
|
||||
_sawmill.Error($"Watching resources in path {path} threw an exception:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -331,6 +331,7 @@ namespace Robust.Server
|
||||
// TODO: solve this properly.
|
||||
_serializer.Initialize();
|
||||
|
||||
_loc.Initialize();
|
||||
_loc.AddLoadedToStringSerializer(_stringSerializer);
|
||||
|
||||
//IoCManager.Resolve<IMapLoader>().LoadedMapData +=
|
||||
|
||||
8
Robust.Server/Localization/ServerLocalizationManager.cs
Normal file
8
Robust.Server/Localization/ServerLocalizationManager.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Robust.Server.Localization;
|
||||
|
||||
internal sealed class ServerLocalizationManager : LocalizationManager, ILocalizationManager
|
||||
{
|
||||
void ILocalizationManager.Initialize() => Initialize();
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Robust.Server.Console;
|
||||
using Robust.Server.DataMetrics;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Server.Localization;
|
||||
using Robust.Server.Placement;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Server.Prototypes;
|
||||
@@ -21,6 +22,7 @@ using Robust.Shared.Console;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
@@ -97,7 +99,9 @@ namespace Robust.Server
|
||||
deps.Register<NetworkResourceManager>();
|
||||
deps.Register<IHttpClientHolder, HttpClientHolder>();
|
||||
deps.Register<UploadedContentManager>();
|
||||
deps.Register<IHWId, DummyHWId>();
|
||||
deps.Register<IHWId, DummyHWId>();
|
||||
deps.Register<ILocalizationManager, ServerLocalizationManager>();
|
||||
deps.Register<ILocalizationManagerInternal, ServerLocalizationManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,13 @@ namespace Robust.Shared.Localization
|
||||
/// Gets localization data for an entity prototype.
|
||||
/// </summary>
|
||||
EntityLocData GetEntityData(string prototypeId);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the <see cref="LocalizationManager"/>.
|
||||
/// </summary>
|
||||
void Initialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal interface ILocalizationManagerInternal : ILocalizationManager
|
||||
|
||||
@@ -12,7 +12,7 @@ using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Robust.Shared.Localization
|
||||
{
|
||||
internal sealed partial class LocalizationManager
|
||||
internal abstract partial class LocalizationManager
|
||||
{
|
||||
// Concurrent dict so that multiple threads "reading" .Name won't cause a concurrent write issue
|
||||
// when the cache gets populated.
|
||||
@@ -134,7 +134,7 @@ namespace Robust.Shared.Localization
|
||||
.Select(x => GetString(x.Suffix!));
|
||||
suffix = string.Join(", ", suffixes);
|
||||
}
|
||||
|
||||
|
||||
return new EntityLocData(
|
||||
name ?? "",
|
||||
desc ?? "",
|
||||
|
||||
@@ -12,7 +12,7 @@ using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Shared.Localization
|
||||
{
|
||||
internal sealed partial class LocalizationManager
|
||||
internal abstract partial class LocalizationManager
|
||||
{
|
||||
private static readonly Regex RegexWordMatch = new Regex(@"\w+");
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Shared.Localization
|
||||
{
|
||||
internal sealed partial class LocalizationManager : ILocalizationManagerInternal, IPostInjectInit
|
||||
internal abstract partial class LocalizationManager : ILocalizationManagerInternal
|
||||
{
|
||||
private static readonly ResPath LocaleDirPath = new("/Locale");
|
||||
protected static readonly ResPath LocaleDirPath = new("/Locale");
|
||||
|
||||
[Dependency] private readonly IConfigurationManager _configuration = default!;
|
||||
[Dependency] private readonly IResourceManager _res = default!;
|
||||
@@ -40,7 +40,9 @@ namespace Robust.Shared.Localization
|
||||
private (CultureInfo, FluentBundle)? _defaultCulture;
|
||||
private (CultureInfo, FluentBundle)[] _fallbackCultures = Array.Empty<(CultureInfo, FluentBundle)>();
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
void ILocalizationManager.Initialize() => Initialize();
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
_logSawmill = _log.GetSawmill("loc");
|
||||
_prototype.PrototypesReloaded += OnPrototypesReloaded;
|
||||
|
||||
@@ -30,8 +30,6 @@ namespace Robust.Shared
|
||||
deps.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
deps.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
|
||||
deps.Register<IEntitySystemManager, EntitySystemManager>();
|
||||
deps.Register<ILocalizationManager, LocalizationManager>();
|
||||
deps.Register<ILocalizationManagerInternal, LocalizationManager>();
|
||||
deps.Register<ILogManager, LogManager>();
|
||||
deps.Register<IModLoader, ModLoader>();
|
||||
deps.Register<IModLoaderInternal, ModLoader>();
|
||||
|
||||
@@ -17,6 +17,11 @@ internal interface IReloadManager
|
||||
/// </summary>
|
||||
internal void Register(string directory, string filter);
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified directory as a <see cref="ResPath"/> and specified file extension to subscribe to.
|
||||
/// </summary>
|
||||
internal void Register(ResPath directory, string filter);
|
||||
|
||||
void Initialize();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ using Robust.Server.Containers;
|
||||
using Robust.Server.Debugging;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Server.Localization;
|
||||
using Robust.Server.Physics;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Server.Prototypes;
|
||||
@@ -192,7 +193,7 @@ namespace Robust.UnitTesting.Server
|
||||
container.Register<INetConfigurationManagerInternal, ServerNetConfigurationManager>();
|
||||
container.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
container.Register<IDynamicTypeFactoryInternal, DynamicTypeFactory>();
|
||||
container.Register<ILocalizationManager, LocalizationManager>();
|
||||
container.Register<ILocalizationManager, ServerLocalizationManager>();
|
||||
container.Register<IModLoader, TestingModLoader>();
|
||||
container.Register<IModLoaderInternal, TestingModLoader>();
|
||||
container.Register<ProfManager, ProfManager>();
|
||||
|
||||
@@ -31,6 +31,7 @@ term1 = 2
|
||||
res.MountString("/Locale/en-US/a.ftl", DuplicateTerm);
|
||||
|
||||
var loc = IoCManager.Resolve<ILocalizationManager>();
|
||||
loc.Initialize();
|
||||
|
||||
var spyLog = (SpyLogManager) IoCManager.Resolve<ILogManager>();
|
||||
var culture = new CultureInfo("en-US", false);
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Robust.UnitTesting.Shared.Localization
|
||||
|
||||
var loc = IoCManager.Resolve<ILocalizationManager>();
|
||||
var culture = new CultureInfo("en-US", false);
|
||||
loc.Initialize();
|
||||
loc.LoadCulture(culture);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user