Skip to content

Commit 364ec59

Browse files
committed
Update CuiHelper serialization thread safety
1 parent a0790bf commit 364ec59

2 files changed

Lines changed: 54 additions & 32 deletions

File tree

src/Oxide.Rust.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
</PropertyGroup>
2626
<ItemGroup>
2727
<PackageReference Include="Oxide.References" Version="2.0.*" />
28-
<PackageReference Include="Oxide.Core" Version="2.0.*" />
28+
<PackageReference Include="Oxide.Core" Version="2.0.4137-develop" />
2929
<PackageReference Include="Oxide.CSharp" Version="2.0.*" />
3030
<PackageReference Include="Oxide.MySql" Version="2.0.*" />
3131
<PackageReference Include="Oxide.SQLite" Version="2.0.*" />

src/RustCui.cs

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
using System.Globalization;
1010
using System.IO;
1111
using System.Text;
12-
using Facepunch;
12+
using System.Threading;
13+
using Oxide.Pooling;
1314
using UnityEngine;
1415
using UnityEngine.UI;
1516

@@ -18,14 +19,50 @@ namespace Oxide.Game.Rust.Cui
1819
public sealed class JsonArrayPool<T> : IArrayPool<T>
1920
{
2021
public static readonly JsonArrayPool<T> Shared = new JsonArrayPool<T>();
21-
private readonly ArrayPool<T> _pool = new ArrayPool<T>(50);
22-
public T[] Rent(int minimumLength) => _pool.Rent(minimumLength);
23-
public void Return(T[] array) => _pool.Return(array);
22+
private static readonly IArrayPoolProvider<T> Provider = GetOrCreateProvider();
23+
24+
private static IArrayPoolProvider<T> GetOrCreateProvider()
25+
{
26+
if (Interface.Oxide.PoolFactory.IsHandledType<T[]>())
27+
{
28+
return Interface.Oxide.PoolFactory.GetArrayProvider<T>();
29+
}
30+
31+
Interface.Oxide.PoolFactory.RegisterProvider<BaseArrayPoolProvider<T>>(out var provider, 1000, 16384);
32+
return provider;
33+
}
34+
35+
public T[] Rent(int minimumLength) => Provider.Take(minimumLength);
36+
public void Return(T[] array) => Provider.Return(array);
2437
}
2538

2639
public static class CuiHelper
2740
{
28-
private static readonly StringBuilder sb = new StringBuilder(64 * 1024);
41+
private class JsonWriterResources
42+
{
43+
public readonly StringBuilder StringBuilder = new StringBuilder(64 * 1024);
44+
public readonly StringWriter StringWriter;
45+
public readonly JsonTextWriter JsonWriter;
46+
public readonly JsonSerializer Serializer;
47+
48+
public JsonWriterResources()
49+
{
50+
StringWriter = new StringWriter(StringBuilder, CultureInfo.InvariantCulture);
51+
JsonWriter = new JsonTextWriter(StringWriter)
52+
{
53+
ArrayPool = JsonArrayPool<char>.Shared,
54+
CloseOutput = false
55+
};
56+
Serializer = JsonSerializer.Create(Settings);
57+
}
58+
59+
public void Reset(bool format = false)
60+
{
61+
StringBuilder.Clear();
62+
JsonWriter.Formatting = format ? Formatting.Indented : Formatting.None;
63+
}
64+
}
65+
2966
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
3067
{
3168
DefaultValueHandling = DefaultValueHandling.Ignore,
@@ -35,28 +72,18 @@ public static class CuiHelper
3572
StringEscapeHandling = StringEscapeHandling.Default
3673
};
3774

38-
private static readonly JsonSerializer _serializer = JsonSerializer.Create(Settings);
39-
private static readonly StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);
40-
private static readonly JsonTextWriter jw = new JsonTextWriter(sw)
41-
{
42-
Formatting = Formatting.None,
43-
ArrayPool = JsonArrayPool<char>.Shared,
44-
CloseOutput = false
45-
};
46-
private static readonly JsonTextWriter jwFormated = new JsonTextWriter(sw)
47-
{
48-
Formatting = Formatting.Indented,
49-
ArrayPool = JsonArrayPool<char>.Shared,
50-
CloseOutput = false
51-
};
75+
private static readonly ThreadLocal<JsonWriterResources> SharedWriterResources =
76+
new ThreadLocal<JsonWriterResources>(() => new JsonWriterResources());
5277

5378
public static string ToJson(IReadOnlyList<CuiElement> elements, bool format = false)
5479
{
55-
sb.Clear();
56-
var writer = format ? jwFormated : jw;
57-
_serializer.Serialize(writer, elements);
58-
var json = sb.ToString().Replace("\\n", "\n");
59-
return json;
80+
var resources = SharedWriterResources.Value;
81+
resources.Reset(format);
82+
83+
resources.Serializer.Serialize(resources.JsonWriter, elements);
84+
resources.JsonWriter.Flush();
85+
86+
return resources.StringBuilder.ToString().Replace("\\n", "\n");
6087
}
6188

6289
public static List<CuiElement> FromJson(string json) => JsonConvert.DeserializeObject<List<CuiElement>>(json);
@@ -72,7 +99,7 @@ public static bool AddUi(BasePlayer player, List<CuiElement> elements)
7299

73100
return AddUi(player, ToJson(elements));
74101
}
75-
102+
76103
public static bool AddUi(BasePlayer player, string json)
77104
{
78105
if (player?.net != null && Interface.CallHook("CanUseUI", player, json) == null)
@@ -98,12 +125,7 @@ public static bool DestroyUi(BasePlayer player, string elem)
98125

99126
public static void SetColor(this ICuiColor elem, Color color)
100127
{
101-
sb.Clear();
102-
sb.Append(color.r).Append(' ')
103-
.Append(color.g).Append(' ')
104-
.Append(color.b).Append(' ')
105-
.Append(color.a);
106-
elem.Color = sb.ToString();
128+
elem.Color = $"{color.r} {color.g} {color.b} {color.a}";
107129
}
108130

109131
public static Color GetColor(this ICuiColor elem) => ColorEx.Parse(elem.Color);

0 commit comments

Comments
 (0)