Skip to content

Commit c4d3b04

Browse files
[Save/Sync]
1 parent 1551baa commit c4d3b04

File tree

5 files changed

+149
-64
lines changed

5 files changed

+149
-64
lines changed

Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/IConfigService.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,5 @@ public partial interface IConfigService
1313
ImmutableArray<IDisplayableConfigBase> GetDisplayableConfigsForPackage(ContentPackage package);
1414

1515
FluentResults.Result<IConfigControl> AddConfigControl(ContentPackage package, string name, KeyOrMouse defaultValue,
16-
NetSync syncMode = NetSync.None,
17-
ClientPermissions permissions = ClientPermissions.None,
18-
Func<KeyOrMouse, bool> valueChangePredicate = null,
19-
Action<IConfigControl> onValueChanged = null);
16+
NetSync syncMode = NetSync.None, ClientPermissions permissions = ClientPermissions.None);
2017
}

Barotrauma/BarotraumaClient/ClientSource/LuaCs/Services/NetworkingService.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
using Barotrauma.LuaCs.Services;
22
using Barotrauma.Networking;
33
using System;
4+
using System.Collections.Concurrent;
45
using System.Collections.Generic;
56

67
namespace Barotrauma.LuaCs.Services;
78

89
partial class NetworkingService : INetworkingService
910
{
10-
private Dictionary<ushort, Queue<IReadMessage>> receiveQueue = new Dictionary<ushort, Queue<IReadMessage>>();
11+
private ConcurrentDictionary<ushort, ConcurrentQueue<IReadMessage>> receiveQueue = new();
1112

1213
public void SendSyncMessage()
1314
{
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
namespace Barotrauma.LuaCs.Data;
1+
using System.Collections.Generic;
2+
using System.Xml.Linq;
23

3-
public interface IConfigProfileInfo
4+
namespace Barotrauma.LuaCs.Data;
5+
6+
public interface IConfigProfileInfo : IDataInfo
47
{
5-
8+
string ProfileName { get; }
9+
IReadOnlyList<(string ConfigName, OneOf.OneOf<string, XElement> Value)> ProfileValues { get; }
610
}

Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/ConfigService.cs

Lines changed: 129 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,51 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Collections.Immutable;
5+
using System.Linq;
46
using System.Threading.Tasks;
7+
using System.Xml.Linq;
58
using Barotrauma.LuaCs.Configuration;
69
using Barotrauma.LuaCs.Data;
10+
using Barotrauma.LuaCs.Events;
11+
using Barotrauma.LuaCs.Services.Processing;
712
using Barotrauma.Networking;
813
using FluentResults;
914
using Microsoft.Xna.Framework;
1015

1116
namespace Barotrauma.LuaCs.Services;
1217

13-
public partial class ConfigService : IConfigService
18+
public partial class ConfigService : IConfigService, IEventAssemblyContextUnloading
1419
{
1520
//--- Internals
16-
private readonly IService _base;
17-
private int _isDisposed = 0;
18-
19-
public ConfigService()
21+
public ConfigService(IConverterServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>> configProfileResourceConverter,
22+
IConverterServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> configResourceConverter)
2023
{
24+
_configProfileResourceConverter = configProfileResourceConverter;
25+
_configResourceConverter = configResourceConverter;
2126
this._base = this;
2227
}
2328

29+
// data, states
30+
private readonly IService _base;
31+
private int _isDisposed = 0;
32+
private readonly ConcurrentDictionary<Type, IConfigTypeInitializer<IConfigBase>> _configTypeInitializers = new();
33+
private readonly ConcurrentDictionary<(ContentPackage Package, string ConfigName), IConfigBase> _configs = new();
34+
private readonly ConcurrentDictionary<ContentPackage, ConcurrentBag<(ContentPackage Package, string ConfigName)>> _packageConfigReverseLookup = new();
35+
private readonly ConcurrentDictionary<(ContentPackage Package, string ProfileName), ImmutableArray<(string ConfigName, OneOf.OneOf<string, XElement> Value)>> _configProfiles = new();
36+
private readonly ConcurrentDictionary<ContentPackage, ConcurrentBag<(ContentPackage Package, string ProfileName)>> _packageProfilesReverseLookup = new();
37+
38+
// converters
39+
private readonly IConverterServiceAsync<IConfigResourceInfo, IReadOnlyList<IConfigInfo>> _configResourceConverter;
40+
private readonly IConverterServiceAsync<IConfigProfileResourceInfo, IReadOnlyList<IConfigProfileInfo>> _configProfileResourceConverter;
41+
2442
//--- GC
2543
public bool IsDisposed => ModUtils.Threading.GetBool(ref _isDisposed);
2644

2745
public void Dispose()
2846
{
2947
ModUtils.Threading.SetBool(ref _isDisposed, true);
48+
_configTypeInitializers.Clear();
3049
throw new NotImplementedException();
3150
}
3251

@@ -150,44 +169,117 @@ public void SetConfigList(string packageName, string configName, string value)
150169

151170
#endregion
152171

153-
public void RegisterTypeInitializer<TData, TConfig>(IConfigTypeInitializer<TData, TConfig> initializer) where TData : IEquatable<TData> where TConfig : IConfigBase
154-
{
155-
throw new NotImplementedException();
156-
}
157-
158-
public async Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources)
172+
public void RegisterTypeInitializer<TData, TConfig>(IConfigTypeInitializer<TConfig> initializer, bool replaceIfExists = false)
173+
where TData : IConvertible, IEquatable<TData> where TConfig : IConfigBase
159174
{
160175
_base.CheckDisposed();
161-
throw new NotImplementedException();
176+
Type dataType = typeof(TData);
177+
if (_configTypeInitializers.ContainsKey(dataType) && !replaceIfExists)
178+
return;
179+
_configTypeInitializers[dataType] = (IConfigTypeInitializer<IConfigBase>)initializer;
162180
}
163181

164-
public async Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigProfileResourceInfo> configProfileResources)
182+
private void AddConfigInstance((ContentPackage Package, string ConfigName) key, IConfigBase instance)
165183
{
166-
_base.CheckDisposed();
167-
throw new NotImplementedException();
184+
_configs[key] = instance;
185+
if (!_packageConfigReverseLookup.TryGetValue(key.Package, out var list))
186+
{
187+
list = new ConcurrentBag<(ContentPackage Package, string ConfigName)>();
188+
_packageConfigReverseLookup[key.Package] = list;
189+
}
190+
list.Add(key);
168191
}
169192

170-
public Result<IConfigEntry<T>> AddConfigEntry<T>(ContentPackage package, string name, T defaultValue, NetSync syncMode = NetSync.None,
171-
ClientPermissions permissions = ClientPermissions.None, Func<T, bool> valueChangePredicate = null,
172-
Action<IConfigEntry<T>> onValueChanged = null) where T : IConvertible, IEquatable<T>
193+
private void AddProfileInstance((ContentPackage Package, string ProfileName) key, IConfigProfileInfo profile)
194+
{
195+
_configProfiles[key] = profile.ProfileValues.ToImmutableArray();
196+
if (!_packageProfilesReverseLookup.TryGetValue(key.Package, out var list))
197+
{
198+
list = new ConcurrentBag<(ContentPackage Package, string ProfileName)>();
199+
_packageProfilesReverseLookup[key.Package] = list;
200+
}
201+
list.Add(key);
202+
}
203+
204+
public async Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources)
173205
{
174206
_base.CheckDisposed();
175-
throw new NotImplementedException();
207+
208+
if (configResources.IsDefaultOrEmpty)
209+
return FluentResults.Result.Fail($"{nameof(LoadConfigsAsync)}: Array is empty.");
210+
211+
var results = await _configResourceConverter.TryParseResourcesAsync(configResources);
212+
var ret = new FluentResults.Result();
213+
214+
foreach (var result in results)
215+
{
216+
if (result.Errors.Any())
217+
ret.Errors.AddRange(result.Errors);
218+
if (result.IsFailed || result.Value is not { Count: > 0 } res)
219+
continue;
220+
221+
foreach (var configInfo in res)
222+
{
223+
if (_configs.ContainsKey((configInfo.OwnerPackage, configInfo.InternalName)))
224+
{
225+
ret.Errors.Add(new Error($"{nameof(LoadConfigsAsync)}: Config already exists for the compound key {configInfo.OwnerPackage.Name} | {configInfo.InternalName}"));
226+
continue;
227+
}
228+
229+
if (!_configTypeInitializers.TryGetValue(configInfo.DataType, out var initializer))
230+
{
231+
ret.Errors.Add(new Error($"{nameof(LoadConfigsAsync)} No type initializer for {configInfo.DataType}"));
232+
continue;
233+
}
234+
235+
var cfg = initializer.Initialize(configInfo);
236+
if (cfg.Errors.Any())
237+
ret.Errors.AddRange(cfg.Errors);
238+
if (cfg.IsFailed || cfg.Value is not {} val)
239+
continue;
240+
241+
AddConfigInstance((configInfo.OwnerPackage, configInfo.InternalName), val);
242+
}
243+
}
244+
245+
return ret;
176246
}
177247

178-
public Result<IConfigList> AddConfigList(ContentPackage package, string name, int defaultIndex, IReadOnlyList<string> values,
179-
NetSync syncMode = NetSync.None, ClientPermissions permissions = ClientPermissions.None,
180-
Func<IConfigList, int, bool> valueChangePredicate = null, Action<IConfigList, int> onValueChanged = null)
248+
public async Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigProfileResourceInfo> configProfileResources)
181249
{
182250
_base.CheckDisposed();
183-
throw new NotImplementedException();
251+
252+
if (configProfileResources.IsDefaultOrEmpty)
253+
return FluentResults.Result.Fail($"{nameof(LoadConfigsProfilesAsync)}: Array is empty.");
254+
255+
var results = await _configProfileResourceConverter.TryParseResourcesAsync(configProfileResources);
256+
var ret = new FluentResults.Result();
257+
258+
foreach (var result in results)
259+
{
260+
if (result.Errors.Any())
261+
ret.Errors.AddRange(result.Errors);
262+
if (result.IsFailed || result.Value is not { Count: > 0 } res)
263+
continue;
264+
265+
foreach (var profileInfo in res)
266+
{
267+
if (_configProfiles.ContainsKey((profileInfo.OwnerPackage, profileInfo.InternalName)))
268+
{
269+
ret.Errors.Add(new Error($"{nameof(LoadConfigsProfilesAsync)}: Config already exists for the compound key {profileInfo.OwnerPackage.Name} | {profileInfo.InternalName}"));
270+
continue;
271+
}
272+
273+
AddProfileInstance((profileInfo.OwnerPackage, profileInfo.ProfileName), profileInfo);
274+
}
275+
}
276+
277+
return ret;
184278
}
185279

186-
public Result<IConfigRangeEntry<T>> AddConfigRangeEntry<T>(ContentPackage package, string name, T defaultValue, T minValue, T maxValue,
187-
Func<IConfigRangeEntry<T>, int> getStepCount, NetSync syncMode = NetSync.None, ClientPermissions permissions = ClientPermissions.None,
188-
Func<T, bool> valueChangePredicate = null, Action<IConfigEntry<T>> onValueChanged = null) where T : IConvertible, IEquatable<T>
280+
public Result<TConfig> AddConfig<T, TConfig>(ContentPackage package, string name, T defaultValue, NetSync syncMode = NetSync.None,
281+
ClientPermissions permissions = ClientPermissions.None) where T : IConvertible, IEquatable<T> where TConfig : IConfigBase
189282
{
190-
_base.CheckDisposed();
191283
throw new NotImplementedException();
192284
}
193285

@@ -220,6 +312,11 @@ public Result<IReadOnlyDictionary<string, IConfigBase>> GetConfigsForPackage(str
220312
throw new NotImplementedException();
221313
}
222314

315+
public bool TryGetConfig<T>(ContentPackage package, string name, out T config) where T : IConfigBase
316+
{
317+
throw new NotImplementedException();
318+
}
319+
223320
public T GetConfig<T>(ContentPackage package, string name) where T : IConfigBase
224321
{
225322
_base.CheckDisposed();
@@ -231,4 +328,9 @@ public T GetConfig<T>(string packageName, string name) where T : IConfigBase
231328
_base.CheckDisposed();
232329
throw new NotImplementedException();
233330
}
331+
332+
public void OnAssemblyUnloading(WeakReference<IAssemblyLoaderService> loaderService)
333+
{
334+
throw new NotImplementedException();
335+
}
234336
}

Barotrauma/BarotraumaShared/SharedSource/LuaCs/Services/_Interfaces/IConfigService.cs

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,49 +18,30 @@ public partial interface IConfigService : IReusableService, ILuaConfigService
1818
/// Registers a type initializer from instancing config types by indicated type from config.
1919
/// </summary>
2020
/// <param name="initializer"></param>
21+
/// <param name="replaceIfExists"></param>
2122
/// <typeparam name="TData">The <see cref="Type"/> as parsed from the configuration info.</typeparam>
2223
/// <typeparam name="TConfig">The resulting configuration instance.</typeparam>
23-
void RegisterTypeInitializer<TData, TConfig>(IConfigTypeInitializer<TData, TConfig> initializer)
24-
where TData : IEquatable<TData> where TConfig : IConfigBase;
24+
void RegisterTypeInitializer<TData, TConfig>(IConfigTypeInitializer<TConfig> initializer, bool replaceIfExists = false)
25+
where TData : IConvertible, IEquatable<TData> where TConfig : IConfigBase;
2526

2627
// Config Files/Resources
2728
Task<FluentResults.Result> LoadConfigsAsync(ImmutableArray<IConfigResourceInfo> configResources);
2829
Task<FluentResults.Result> LoadConfigsProfilesAsync(ImmutableArray<IConfigProfileResourceInfo> configProfileResources);
2930

3031
// Immediate Mode
31-
FluentResults.Result<IConfigEntry<T>> AddConfigEntry<T>(ContentPackage package, string name,
32-
T defaultValue,
33-
NetSync syncMode = NetSync.None,
34-
ClientPermissions permissions = ClientPermissions.None,
35-
Func<T, bool> valueChangePredicate = null,
36-
Action<IConfigEntry<T>> onValueChanged = null) where T : IConvertible, IEquatable<T>;
37-
38-
FluentResults.Result<IConfigList> AddConfigList(ContentPackage package, string name,
39-
int defaultIndex, IReadOnlyList<string> values,
40-
NetSync syncMode = NetSync.None,
41-
ClientPermissions permissions = ClientPermissions.None,
42-
Func<IConfigList, int, bool> valueChangePredicate = null,
43-
Action<IConfigList, int> onValueChanged = null);
44-
45-
FluentResults.Result<IConfigRangeEntry<T>> AddConfigRangeEntry<T>(ContentPackage package, string name,
46-
T defaultValue, T minValue, T maxValue,
47-
Func<IConfigRangeEntry<T>, int> getStepCount,
48-
NetSync syncMode = NetSync.None,
49-
ClientPermissions permissions = ClientPermissions.None,
50-
Func<T, bool> valueChangePredicate = null,
51-
Action<IConfigEntry<T>> onValueChanged = null) where T : IConvertible, IEquatable<T>;
32+
FluentResults.Result<TConfig> AddConfig<T, TConfig>(ContentPackage package, string name,
33+
T defaultValue, NetSync syncMode = NetSync.None, ClientPermissions permissions = ClientPermissions.None)
34+
where T : IConvertible, IEquatable<T> where TConfig : IConfigBase;
5235

5336
// Utility
5437
FluentResults.Result ApplyProfileSettings(ContentPackage package, string profileName);
5538
FluentResults.Result DisposePackageData(ContentPackage package);
5639
FluentResults.Result<IReadOnlyDictionary<string, IConfigBase>> GetConfigsForPackage(ContentPackage package);
57-
FluentResults.Result<IReadOnlyDictionary<string, IConfigBase>> GetConfigsForPackage(string packageName);
58-
IReadOnlyDictionary<(ContentPackage, string), IConfigBase> GetAllConfigs();
59-
T GetConfig<T>(ContentPackage package, string name) where T : IConfigBase;
60-
T GetConfig<T>(string packageName, string name) where T : IConfigBase;
40+
IReadOnlyDictionary<(ContentPackage Package, string Name), IConfigBase> GetAllConfigs();
41+
bool TryGetConfig<T>(ContentPackage package, string name, out T config) where T : IConfigBase;
6142
}
6243

63-
public interface IConfigTypeInitializer<TData, TConfig> where TData : IEquatable<TData> where TConfig : IConfigBase
44+
public interface IConfigTypeInitializer<TConfig> where TConfig : IConfigBase
6445
{
65-
FluentResults.Result<TConfig> GetConfig(IConfigInfo configInfo);
46+
FluentResults.Result<TConfig> Initialize(IConfigInfo configInfo);
6647
}

0 commit comments

Comments
 (0)