Skip to content

Commit 510f701

Browse files
killzomsMeasurity
andauthored
Config changed to easier to read format (SubnauticaNitrox#1276)
* Config changed to easier to read format * Forgot to remove * Changed to generic serializer * change to only splitting after first "=" * Add PropertyDescription and TypeCaching * forgot Serialize method * Add class PropertyDescription * add various failure checks * Set default infection value to 0.1f from bugfix on master Reformatted the server settings class. * Improved UX for players when changing server .properties file Changed properties matching for backing type to case-insensitive Added more details to errors and warnings Added throw error on duplicated members because of case-insensitivity * Renamed ServerProperties class to ServerConfig * Added property description for infection value * Renamed PropertiesSerializer to PropertiesWriter Co-authored-by: Measurity <measuring.infinity@gmail.com>
1 parent 7f5bc50 commit 510f701

21 files changed

Lines changed: 292 additions & 305 deletions

NitroxModel/NitroxModel.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,9 @@
216216
<Compile Include="Packets\VehicleNameChange.cs" />
217217
<Compile Include="Packets\WrapperPacket.cs" />
218218
<Compile Include="Properties\AssemblyInfo.cs" />
219+
<Compile Include="Serialization\IProperties.cs" />
220+
<Compile Include="Serialization\PropertiesWriter.cs" />
219221
<Compile Include="Server\ServerSerializerMode.cs" />
220-
<Compile Include="Server\ServerConfig.cs" />
221-
<Compile Include="Server\ServerConfigItem.cs" />
222222
<Compile Include="Server\ServerGameMode.cs" />
223223
</ItemGroup>
224224
<ItemGroup>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.ComponentModel;
3+
4+
namespace NitroxModel.Serialization
5+
{
6+
public interface IProperties
7+
{
8+
public string FileName { get; }
9+
}
10+
11+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class, Inherited = false)]
12+
public sealed class PropertyDescriptionAttribute : DescriptionAttribute
13+
{
14+
public PropertyDescriptionAttribute(string desc) : base(desc)
15+
{
16+
}
17+
18+
public PropertyDescriptionAttribute(string desc, Type type)
19+
{
20+
if (type.IsEnum)
21+
{
22+
desc += $" {string.Join(", ", type.GetEnumNames())}";
23+
DescriptionValue = desc;
24+
}
25+
}
26+
}
27+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Reflection;
7+
using System.Text;
8+
using NitroxModel.Logger;
9+
10+
namespace NitroxModel.Serialization
11+
{
12+
public static class PropertiesWriter
13+
{
14+
private static readonly Dictionary<Type, Dictionary<string, MemberInfo>> typeCache = new Dictionary<Type, Dictionary<string, MemberInfo>>();
15+
16+
public static T Deserialize<T>() where T : IProperties, new()
17+
{
18+
T props = new T();
19+
if (!File.Exists(props.FileName))
20+
{
21+
return props;
22+
}
23+
24+
Dictionary<string, MemberInfo> typeCachedDict = GetTypeCacheDictionary<T>();
25+
using StreamReader reader = new StreamReader(new FileStream(props.FileName, FileMode.Open), Encoding.UTF8);
26+
27+
char[] lineSeparator = { '=' };
28+
int lineNum = 0;
29+
string readLine;
30+
while ((readLine = reader.ReadLine()) != null)
31+
{
32+
lineNum++;
33+
if (readLine.Length < 1 || readLine[0] == '#')
34+
{
35+
continue;
36+
}
37+
38+
if (readLine.Contains('='))
39+
{
40+
string[] keyValuePair = readLine.Split(lineSeparator, 2);
41+
keyValuePair[0] = keyValuePair[0].ToLowerInvariant(); // Ignore case for property names in file.
42+
if (!typeCachedDict.TryGetValue(keyValuePair[0], out MemberInfo member))
43+
{
44+
Log.Warn($"Property {keyValuePair[0]} does not exist on type {typeof(T).FullName}!");
45+
continue;
46+
}
47+
48+
FieldInfo field = member as FieldInfo;
49+
if (field != null)
50+
{
51+
field.SetValue(props, TypeDescriptor.GetConverter(field.FieldType).ConvertFrom(keyValuePair[1]));
52+
}
53+
PropertyInfo prop = member as PropertyInfo;
54+
if (prop != null)
55+
{
56+
prop.SetValue(props, TypeDescriptor.GetConverter(prop.PropertyType).ConvertFrom(keyValuePair[1]));
57+
}
58+
}
59+
else
60+
{
61+
Log.Error($"Incorrect format detected on line {lineNum} in {Path.GetFullPath(props.FileName)}:{Environment.NewLine}{readLine}");
62+
}
63+
}
64+
65+
return props;
66+
}
67+
68+
public static void Serialize<T>(T props) where T : IProperties, new()
69+
{
70+
Dictionary<string, MemberInfo> typeCachedDict = GetTypeCacheDictionary<T>();
71+
72+
using StreamWriter stream = new StreamWriter(new FileStream(props.FileName, FileMode.OpenOrCreate), Encoding.UTF8);
73+
WritePropertyDescription(typeof(T), stream);
74+
75+
foreach (string name in typeCachedDict.Keys)
76+
{
77+
MemberInfo member = typeCachedDict[name];
78+
79+
FieldInfo field = member as FieldInfo;
80+
if (field != null)
81+
{
82+
WritePropertyDescription(member, stream);
83+
WriteProperty(field, field.GetValue(props), stream);
84+
}
85+
86+
PropertyInfo property = member as PropertyInfo;
87+
if (property != null)
88+
{
89+
WritePropertyDescription(member, stream);
90+
WriteProperty(property, property.GetValue(props), stream);
91+
}
92+
}
93+
}
94+
95+
private static Dictionary<string, MemberInfo> GetTypeCacheDictionary<T>()
96+
{
97+
if (!typeCache.TryGetValue(typeof(T), out Dictionary<string, MemberInfo> typeCachedDict))
98+
{
99+
IEnumerable<MemberInfo> members = typeof(T).GetFields()
100+
.Where(f => f.Attributes != FieldAttributes.NotSerialized)
101+
.Concat(typeof(T).GetProperties()
102+
.Where(p => p.CanWrite)
103+
.Cast<MemberInfo>());
104+
105+
try
106+
{
107+
typeCachedDict = new Dictionary<string, MemberInfo>();
108+
foreach (MemberInfo member in members)
109+
{
110+
typeCachedDict.Add(member.Name.ToLowerInvariant(), member);
111+
}
112+
}
113+
catch (ArgumentException e)
114+
{
115+
Log.Error(e, $"Type {typeof(T).FullName} has properties that require case-sensitivity to be unique which is unsuitable for .properties format.");
116+
throw;
117+
}
118+
119+
typeCache.Add(typeof(T), typeCachedDict);
120+
}
121+
return typeCachedDict;
122+
}
123+
124+
private static void WriteProperty<T>(T member, object value, StreamWriter stream) where T : MemberInfo
125+
{
126+
stream.Write(member.Name);
127+
stream.Write("=");
128+
stream.WriteLine(value);
129+
}
130+
131+
private static void WritePropertyDescription(MemberInfo member, StreamWriter stream)
132+
{
133+
PropertyDescriptionAttribute attribute = member.GetCustomAttribute<PropertyDescriptionAttribute>();
134+
if (attribute != null)
135+
{
136+
foreach (string line in attribute.Description.Split(Environment.NewLine.ToCharArray()))
137+
{
138+
stream.Write("# ");
139+
stream.WriteLine(line);
140+
}
141+
}
142+
}
143+
}
144+
}

NitroxModel/Server/ServerConfig.cs

Lines changed: 0 additions & 196 deletions
This file was deleted.

0 commit comments

Comments
 (0)