Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
DatabaseObject.cs
浏览该文件的文档.
1using System;
2using System.Collections.Generic;
3
4namespace TemplatesDatabase {
5 public class DatabaseObject {
6 public class StringBin {
7 int m_mask;
8
9 List<string> m_list = [];
10
11 public bool Contains(string s) {
12 int num = Hash(s) & 0x1F;
13 int num2 = 1 << num;
14 if ((m_mask & num2) != 0) {
15 return m_list.Contains(s);
16 }
17 return false;
18 }
19
20 public void Add(string s) {
21 int num = Hash(s) & 0x1F;
22 int num2 = 1 << num;
23 m_mask |= num2;
24 m_list.Add(s);
25 }
26
27 static int Hash(string s) {
28 int length = s.Length;
29 return s[0] + s[length >> 1] + s[length - 1];
30 }
31 }
32
34
36
38
39 string m_name;
40
41 object m_value;
42
43 string m_description = string.Empty;
44
45#pragma warning disable CS0649
47#pragma warning restore CS0649
48
50
52
53 List<DatabaseObject> m_nestingChildren;
54
56
58
59 public Guid Guid => m_guid;
60
61 public string Name {
62 get => m_name;
63 set {
64 if (m_readOnly) {
65 throw new InvalidOperationException("Cannot change name of a read-only database object.");
66 }
67 if (value != m_name) {
68 if (value.Length > Type.NameLengthLimit) {
69 throw new InvalidOperationException(
70 $"Name \"{value}\" is too long, maximum name length for database object of type \"{Type.Name}\" is {Type.NameLengthLimit}."
71 );
72 }
73 if (NestingParent != null) {
74 foreach (DatabaseObject explicitNestingChild in NestingParent.GetExplicitNestingChildren(null, true)) {
75 if (explicitNestingChild.Name == value) {
76 throw new InvalidOperationException(
77 $"Database object \"{explicitNestingChild.Name}\" is already nested in parent database object \"{NestingParent.Name}\"."
78 );
79 }
80 }
81 }
82 m_name = value;
83 }
84 }
85 }
86
87 public string Description {
88 get => m_description;
89 set {
90 if (m_readOnly) {
91 throw new InvalidOperationException("Cannot change description of a read-only database object.");
92 }
93 if (value == null) {
94 throw new ArgumentNullException(nameof(value), "Description cannot be null.");
95 }
96 m_description = value;
97 }
98 }
99
100 public object Value {
101 get => m_value;
102 set {
103 if (m_readOnly) {
104 throw new InvalidOperationException("Cannot change value of a read-only database object.");
105 }
106 if (!Type.SupportsValue) {
107 throw new InvalidOperationException($"Database objects of type \"{Type.Name}\" do not support values.");
108 }
109 if (value == null) {
110 throw new ArgumentNullException(nameof(value), "Value cannot be null.");
111 }
112 m_value = value;
113 }
114 }
115
116 public bool ReadOnly => m_readOnly;
117
119 get => m_nestingParent;
120 set {
121 if (m_readOnly) {
122 throw new InvalidOperationException("Cannot change nesting parent of a read-only database object.");
123 }
124 if (value == m_nestingParent) {
125 return;
126 }
127 if (value != null) {
128 if (m_database != null
129 && m_database.Root == this) {
130 throw new InvalidOperationException("Root database object cannot be nested.");
131 }
132 if (!Type.AllowedNestingParents.Contains(value.Type)) {
133 throw new InvalidOperationException($"Database object of type {Type.Name} cannot be nested in {value.Type.Name}.");
134 }
135 if (value == this
136 || value.EffectivelyInheritsFrom(this)
138 || value.IsNestedIn(this)) {
139 throw new InvalidOperationException(
140 $"Cannot set nesting parent of database object \"{Name}\" to database object \"{value.Name}\" because it would create recursive nesting/inheritance."
141 );
142 }
143 if (value.FindExplicitNestedChild(Name, null, true, false) != null) {
144 throw new InvalidOperationException(
145 $"Another database object with name \"{Name}\" is already nested in database object \"{value.Name}\"."
146 );
147 }
148 }
149 if (m_nestingParent != null) {
150 if (!m_nestingParent.InternalNestingChildren.Remove(this)) {
151 throw new InvalidOperationException("DatabaseObject internal error: nested DatabaseObject not found in container.");
152 }
153 m_nestingParent = null;
154 if (m_database != null) {
155 m_database.RemoveDatabaseObject(this);
156 }
157 }
158 if (value != null) {
159 if (value.m_database != null) {
160 value.m_database.AddDatabaseObject(this, true);
161 }
162 m_nestingParent = value;
163 m_nestingParent.InternalNestingChildren.Add(this);
164 }
165 }
166 }
167
169 get {
170 if (m_nestingParent == null) {
171 return this;
172 }
173 return m_nestingParent.NestingRoot;
174 }
175 }
176
179 set {
180 if (m_readOnly) {
181 throw new InvalidOperationException("Cannot change inheritance parent of a read-only database object.");
182 }
183 if (value == m_explicitInheritanceParent) {
184 return;
185 }
186 if (value != null) {
187 if (value == this
188 || value.EffectivelyInheritsFrom(this)
189 || value.IsNestedIn(this)
190 || IsNestedIn(value)) {
191 throw new InvalidOperationException(
192 $"Cannot set inheritance parent of database object \"{Name}\" to database object \"{value.Name}\" because it would create recursive nesting/inheritance."
193 );
194 }
195 if (!Type.AllowedInheritanceParents.Contains(value.Type)) {
196 throw new InvalidOperationException($"Database object of type {Type.Name} cannot inherit from {value.Type.Name}.");
197 }
198 }
200 }
201 }
202
204 get {
205 if (m_explicitInheritanceParent == null) {
206 return this;
207 }
208 return m_explicitInheritanceParent.ExplicitInheritanceRoot;
209 }
210 }
211
213 get {
214 if (NestingParent != null) {
215 return NestingParent.EffectiveInheritanceParent?.FindEffectiveNestedChild(Name, null, true, false);
216 }
217 return null;
218 }
219 }
220
222 get {
223 DatabaseObject implicitInheritanceParent = ImplicitInheritanceParent;
224 if (implicitInheritanceParent == null) {
225 return this;
226 }
227 return implicitInheritanceParent.ImplicitInheritanceRoot;
228 }
229 }
230
232 get {
233 if (m_explicitInheritanceParent == null) {
235 }
237 }
238 }
239
241 get {
242 DatabaseObject effectiveInheritanceParent = EffectiveInheritanceParent;
243 if (effectiveInheritanceParent == null) {
244 return this;
245 }
246 return effectiveInheritanceParent.EffectiveInheritanceRoot;
247 }
248 }
249
250 List<DatabaseObject> InternalNestingChildren {
251 get {
252 if (m_nestingChildren == null) {
254 }
255 return m_nestingChildren;
256 }
257 }
258
259 public DatabaseObject(DatabaseObjectType databaseObjectType, Guid guid, string name, object value) {
260 if (!databaseObjectType.IsInitialized) {
261 throw new InvalidOperationException($"InitializeRelations of DatabaseObjectType \"{databaseObjectType.Name}\" not called.");
262 }
263 m_databaseObjectType = databaseObjectType;
264 m_guid = guid;
265 Name = name;
266 if (value != null) {
267 Value = value;
268 }
269 }
270
271 public DatabaseObject(DatabaseObjectType databaseObjectType, string name, object value) : this(
272 databaseObjectType,
273 Guid.NewGuid(),
274 name,
275 value
276 ) { }
277
278 public DatabaseObject(DatabaseObjectType databaseObjectType, string name) : this(databaseObjectType, Guid.NewGuid(), name, null) { }
279
280 public bool IsNestedIn(DatabaseObject databaseObject) {
281 if (NestingParent == null) {
282 return false;
283 }
284 if (NestingParent != databaseObject) {
285 return NestingParent.IsNestedIn(databaseObject);
286 }
287 return true;
288 }
289
290 public IEnumerable<DatabaseObject> GetExplicitNestingChildren(DatabaseObjectType type, bool directChildrenOnly) {
291 foreach (DatabaseObject databaseObject in InternalNestingChildren) {
292 if (type == null
293 || databaseObject.Type == type) {
294 yield return databaseObject;
295 }
296 if (!directChildrenOnly) {
297 foreach (DatabaseObject explicitNestingChild in databaseObject.GetExplicitNestingChildren(type, false)) {
298 yield return explicitNestingChild;
299 }
300 }
301 }
302 }
303
304 public DatabaseObject FindExplicitNestedChild(string name, DatabaseObjectType type, bool directChildrenOnly, bool throwIfNotFound) {
305 foreach (DatabaseObject explicitNestingChild in GetExplicitNestingChildren(type, directChildrenOnly)) {
306 if (explicitNestingChild.Name == name) {
307 return explicitNestingChild;
308 }
309 }
310 if (throwIfNotFound) {
311 throw new InvalidOperationException($"Required database object \"{name}\" not found in database object \"{Name}\"");
312 }
313 return null;
314 }
315
316 public bool ExplicitlyInheritsFrom(DatabaseObject databaseObject) {
317 DatabaseObject explicitInheritanceParent = ExplicitInheritanceParent;
318 if (explicitInheritanceParent != null) {
319 if (explicitInheritanceParent != databaseObject) {
320 return explicitInheritanceParent.ExplicitlyInheritsFrom(databaseObject);
321 }
322 return true;
323 }
324 return false;
325 }
326
327 public bool ImplicitlyInheritsFrom(DatabaseObject databaseObject) {
328 DatabaseObject implicitInheritanceParent = ImplicitInheritanceParent;
329 if (implicitInheritanceParent != null) {
330 if (implicitInheritanceParent != databaseObject) {
331 return implicitInheritanceParent.ImplicitlyInheritsFrom(databaseObject);
332 }
333 return true;
334 }
335 return false;
336 }
337
338 public bool EffectivelyInheritsFrom(DatabaseObject databaseObject) {
339 DatabaseObject effectiveInheritanceParent = EffectiveInheritanceParent;
340 if (effectiveInheritanceParent != null) {
341 if (effectiveInheritanceParent != databaseObject) {
342 return effectiveInheritanceParent.EffectivelyInheritsFrom(databaseObject);
343 }
344 return true;
345 }
346 return false;
347 }
348
349 public IEnumerable<DatabaseObject> GetEffectiveNestingChildren(DatabaseObjectType type, bool directChildrenOnly) {
350 if (directChildrenOnly) {
351 foreach (DatabaseObject item in InternalGetEffectiveNestingChildren(new StringBin(), type)) {
352 if (type == null
353 || item.Type == type) {
354 yield return item;
355 }
356 }
357 }
358 else {
359 foreach (DatabaseObject databaseObject in GetEffectiveNestingChildren(null, true)) {
360 if (type == null
361 || databaseObject.Type == type) {
362 yield return databaseObject;
363 }
364 foreach (DatabaseObject effectiveNestingChild in databaseObject.GetEffectiveNestingChildren(type, false)) {
365 yield return effectiveNestingChild;
366 }
367 }
368 }
369 }
370
371 public DatabaseObject FindEffectiveNestedChild(string name, DatabaseObjectType type, bool directChildrenOnly, bool throwIfNotFound) {
372 foreach (DatabaseObject effectiveNestingChild in GetEffectiveNestingChildren(type, directChildrenOnly)) {
373 if (effectiveNestingChild.Name == name) {
374 return effectiveNestingChild;
375 }
376 }
377 if (throwIfNotFound) {
378 throw new InvalidOperationException($"Required database object \"{name}\" not found in database object \"{Name}\"");
379 }
380 return null;
381 }
382
383 public T GetNestedValue<T>(string name) {
384 DatabaseObject databaseObject = FindEffectiveNestedChild(name, Type.NestedValueType, true, true);
385 return CastValue<T>(databaseObject);
386 }
387
388 public T GetNestedValue<T>(string name, T defaultValue) {
389 DatabaseObject databaseObject = FindEffectiveNestedChild(name, Type.NestedValueType, true, false);
390 if (databaseObject == null) {
391 return defaultValue;
392 }
393 return CastValue<T>(databaseObject);
394 }
395
396 public void SetNestedValue<T>(string name, T value) {
397 DatabaseObject databaseObject = FindEffectiveNestedChild(name, Type.NestedValueType, true, false);
398 if (databaseObject == null
399 || databaseObject.NestingParent != this) {
400 new DatabaseObject(Type.NestedValueType, Guid.Empty, name, value).NestingParent = this;
401 }
402 else {
403 databaseObject.Value = value;
404 }
405 }
406
407 public override string ToString() {
408 if (NestingParent != null) {
409 return $"{Name} in {NestingParent}";
410 }
411 return $"{Name}";
412 }
413
414 T CastValue<T>(DatabaseObject databaseObject) {
415 if (databaseObject.Value != null
416 && !(databaseObject.Value is T)) {
417 throw new Exception(
418 $"Database object \"{databaseObject.Name}\" has invalid type \"{databaseObject.Value.GetType().FullName}\", required type is \"{typeof(T).FullName}\"."
419 );
420 }
421 return (T)databaseObject.Value;
422 }
423
424 IEnumerable<DatabaseObject> InternalGetEffectiveNestingChildren(StringBin names, DatabaseObjectType type) {
425 if (Type.AllowedNestingChildren.Count != 0) {
426 foreach (DatabaseObject explicitNestingChild in GetExplicitNestingChildren(type, true)) {
427 if (!names.Contains(explicitNestingChild.Name)) {
428 names.Add(explicitNestingChild.Name);
429 yield return explicitNestingChild;
430 }
431 }
432 DatabaseObject effectiveInheritanceParent = EffectiveInheritanceParent;
433 if (effectiveInheritanceParent != null) {
434 foreach (DatabaseObject item in effectiveInheritanceParent.InternalGetEffectiveNestingChildren(names, type)) {
435 yield return item;
436 }
437 }
438 }
439 }
440 }
441}
bool ExplicitlyInheritsFrom(DatabaseObject databaseObject)
DatabaseObject FindEffectiveNestedChild(string name, DatabaseObjectType type, bool directChildrenOnly, bool throwIfNotFound)
List< DatabaseObject > InternalNestingChildren
bool ImplicitlyInheritsFrom(DatabaseObject databaseObject)
T CastValue< T >(DatabaseObject databaseObject)
bool EffectivelyInheritsFrom(DatabaseObject databaseObject)
IEnumerable< DatabaseObject > InternalGetEffectiveNestingChildren(StringBin names, DatabaseObjectType type)
IEnumerable< DatabaseObject > GetEffectiveNestingChildren(DatabaseObjectType type, bool directChildrenOnly)
DatabaseObject(DatabaseObjectType databaseObjectType, string name, object value)
List< DatabaseObject > m_nestingChildren
void SetNestedValue< T >(string name, T value)
DatabaseObject FindExplicitNestedChild(string name, DatabaseObjectType type, bool directChildrenOnly, bool throwIfNotFound)
DatabaseObject(DatabaseObjectType databaseObjectType, string name)
bool IsNestedIn(DatabaseObject databaseObject)
DatabaseObject(DatabaseObjectType databaseObjectType, Guid guid, string name, object value)
IEnumerable< DatabaseObject > GetExplicitNestingChildren(DatabaseObjectType type, bool directChildrenOnly)