Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
Project.cs
浏览该文件的文档.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5using Engine;
8
9namespace GameEntitySystem {
10 public class Project : IDisposable {
12
14
15 public List<Subsystem> m_subsystems = [];
16
17 public Dictionary<Entity, bool> m_entities = [];
18
20
22
23 public virtual List<Subsystem> Subsystems => m_subsystems;
24
25 public virtual Dictionary<Entity, bool>.KeyCollection Entities => m_entities.Keys;
26
27 public static event EventHandler<EntityAddRemoveEventArgs> EntityAdded;
28
29 public static event EventHandler<EntityAddRemoveEventArgs> EntityRemoved;
30
31 public static event Action<Project> OnProjectLoad;
32
33 public static event Action<Project> BeforeSubsystemsAndEntitiesLoad;
34
36
37 public int NextEntityID = 1;
38
40
41 public Project() { }
42 public Project(GameDatabase gameDatabase, ProjectData projectData) {
43 try {
44 m_gameDatabase = gameDatabase;
45 m_projectData = projectData;
46 m_projectTemplate = m_projectData.ValuesDictionary.DatabaseObject;
47 Dictionary<string, Subsystem> dictionary = [];
48 foreach (ValuesDictionary item in from x in projectData.ValuesDictionary.Values
49 select x as ValuesDictionary
50 into x
51 where x != null && x.DatabaseObject != null && x.DatabaseObject.Type == gameDatabase.MemberSubsystemTemplateType
52 select x) {
53 bool value = item.GetValue<bool>("IsOptional");
54 string value2 = item.GetValue<string>("Class");
55 Type type = TypeCache.FindType(value2, false, !value);
56 if (type != null) {
57 object obj;
58 try {
59#pragma warning disable IL2072
60 obj = Activator.CreateInstance(type);
61#pragma warning restore IL2072
62 }
63 catch (TargetInvocationException ex) {
64 if (ex.InnerException != null) {
65 throw ex.InnerException;
66 }
67 throw;
68 }
69 if (obj is not Subsystem subsystem) {
70 throw new InvalidOperationException(
71 $"Type \"{value2}\" cannot be used as a subsystem because it does not inherit from Subsystem class."
72 );
73 }
74 subsystem.Initialize(this, item);
75 dictionary.Add(item.DatabaseObject.Name, subsystem);
76 m_subsystems.Add(subsystem);
77 }
78 }
79 Dictionary<Subsystem, bool> loadedSubsystems = [];
80 List<Entity> entities = new();
81 if (projectData.EntityDataList != null) {
82 entities = InitializeEntities(projectData.EntityDataList);
83 NextEntityID = projectData.NextEntityID;
84 AddEntities(entities);
85 }
87 foreach (Subsystem value3 in dictionary.Values) {
88 LoadSubsystem(value3, dictionary, loadedSubsystems, 0);
89 }
90 LoadEntities(projectData.EntityDataList, entities);
91 OnProjectLoad?.Invoke(this);
92 }
93 catch (Exception e) {
94 try {
95 Log.Error($"Loading World Failed!\n{e}");
96 }
97 catch {
98 // ignored
99 }
100 try {
101 Dispose();
102 }
103 catch (Exception e2) {
104 Log.Error(e2);
105 }
106 throw;
107 }
108 }
109
110 public virtual Subsystem FindSubsystem(Type type, string name, bool throwOnError) {
111 foreach (Subsystem subsystem in Subsystems) {
112 if (type.GetTypeInfo().IsAssignableFrom(subsystem.GetType().GetTypeInfo())
113 && (name == null || subsystem.ValuesDictionary.DatabaseObject.Name == name)) {
114 return subsystem;
115 }
116 }
117 if (throwOnError) {
118 if (name != null) {
119 throw new Exception($"Required subsystem {type.FullName} with name \"{name}\" does not exist in project.");
120 }
121 throw new Exception($"Required subsystem {type.FullName} does not exist in project.");
122 }
123 return null;
124 }
125
126 public virtual Subsystem FindSubsystem(string name, bool throwOnError) {
127 if (throwOnError) {
128 if (string.IsNullOrEmpty(name)) {
129 throw new ArgumentNullException(nameof(name));
130 }
131 }
132 foreach (Subsystem subsystem in Subsystems) {
133 if (subsystem.ValuesDictionary.DatabaseObject.Name == name) {
134 return subsystem;
135 }
136 }
137 if (throwOnError) {
138 throw new Exception($"Required subsystem with name \"{name}\" does not exist in project.");
139 }
140 return null;
141 }
142
143 public virtual T FindSubsystem<T>() where T : class => FindSubsystem(typeof(T), null, false) as T;
144
145 public virtual T FindSubsystem<T>(bool throwOnError) where T : class => FindSubsystem(typeof(T), null, throwOnError) as T;
146
147 public virtual T FindSubsystem<T>(string name, bool throwOnError) where T : class => FindSubsystem(typeof(T), name, throwOnError) as T;
148
149 public virtual IEnumerable<Subsystem> FindSubsystems(Type type) {
150 foreach (Subsystem subsystem in Subsystems) {
151 if (type.GetTypeInfo().IsAssignableFrom(subsystem.GetType().GetTypeInfo())) {
152 yield return subsystem;
153 }
154 }
155 }
156
157 public virtual IEnumerable<T> FindSubsystems<T>() where T : class {
158 foreach (Subsystem subsystem in Subsystems) {
159 if (subsystem is T val) {
160 yield return val;
161 }
162 }
163 }
164
165 public virtual Entity FindEntity(int EntityID) {
166 return Entities.FirstOrDefault(entity => entity.Id == EntityID, null);
167 }
168
169 public virtual Entity CreateEntity(ValuesDictionary valuesDictionary, int entityId = 0) {
170 try {
171 Entity entity = new(this, valuesDictionary, entityId);
172 IdToEntityMap idToEntityMap = new([]);
173 entity.InternalLoadEntity(valuesDictionary, idToEntityMap);
174 return entity;
175 }
176 catch (Exception innerException) {
177 throw new Exception($"Error creating entity from template \"{valuesDictionary.DatabaseObject.Name}\".", innerException);
178 }
179 }
180
181 public virtual void AddEntity(Entity entity) {
182 if (entity.Project != this) {
183 throw new Exception("Entity does not belong to this project.");
184 }
185 if (!entity.IsAddedToProject) {
186 m_entities.Add(entity, true);
187 if (entity.Id == 0) {
188 entity.Id = NextEntityID;
189 NextEntityID++;
190 }
191 entity.m_isAddedToProject = true;
193 FireEntityAddedEvents(entity);
194 }
195 }
196 }
197
198 public virtual void RemoveEntity(Entity entity, bool disposeEntity) {
199 if (entity.Project != this) {
200 throw new Exception("Entity does not belong to this project.");
201 }
202 if (entity.IsAddedToProject) {
203 m_entities.Remove(entity);
204 entity.m_isAddedToProject = false;
206 if (disposeEntity) {
207 entity.Dispose();
208 }
209 }
210 }
211
212 public virtual void AddEntities(IEnumerable<Entity> entities) {
213 foreach (Entity entity in entities) {
214 AddEntity(entity);
215 }
216 }
217
218 public virtual void RemoveEntities(IEnumerable<Entity> entities, bool disposeEntities) {
219 foreach (Entity entity in entities) {
220 RemoveEntity(entity, disposeEntities);
221 }
222 }
223
224 public virtual List<Entity> InitializeEntities(EntityDataList entityDataList) {
225 List<Entity> list = new(entityDataList.EntitiesData.Count);
226 Dictionary<int, Entity> dictionary = [];
227 foreach (EntityData entitiesDatum in entityDataList.EntitiesData) {
228 try {
229 Entity entity = new(this, entitiesDatum.ValuesDictionary, entitiesDatum.Id);
230 list.Add(entity);
231 if (entitiesDatum.Id != 0) {
232 if (dictionary.ContainsKey(entitiesDatum.Id)) {
233 Log.Warning($"Multiple Entities use the same ID{entitiesDatum.Id}");
234 }
235 dictionary[entitiesDatum.Id] = entity;
236 }
237 }
238 catch (Exception innerException) {
239 throw new Exception(
240 $"Error creating entity from template \"{entitiesDatum.ValuesDictionary.DatabaseObject.Name}\".",
241 innerException
242 );
243 }
244 }
245 return list;
246 }
247
248 public virtual void LoadEntities(EntityDataList entityDataList, List<Entity> entityList) {
249 int num = 0;
250 if (entityDataList?.EntitiesData != null) {
251 foreach (EntityData entitiesDatum2 in entityDataList.EntitiesData) {
252 entityList[num].InternalLoadEntity(entitiesDatum2.ValuesDictionary, null);
253 num++;
254 }
255 }
256 if (Entities != null) {
257 foreach (Entity entity in Entities) {
258 FireEntityAddedEvents(entity);
259 }
260 }
262 }
263
264 public virtual EntityDataList SaveEntities(IEnumerable<Entity> entities) {
265 IEnumerable<Entity> enumerable = entities as Entity[] ?? entities.ToArray();
266 Dictionary<Entity, bool> dictionary = DetermineNotOwnedEntities(enumerable);
267 int num = 1;
268 Dictionary<Entity, int> dictionary2 = [];
269 EntityToIdMap entityToIdMap = new(dictionary2);
270 foreach (Entity key in dictionary.Keys) {
271 dictionary2.Add(key, num);
272 num++;
273 }
274 EntityDataList entityDataList = new() { EntitiesData = new List<EntityData>(dictionary.Keys.Count) };
275 foreach (Entity key2 in enumerable) {
276 EntityData entityData = new() { Id = key2.Id, ValuesDictionary = [] };
277 entityData.ValuesDictionary.DatabaseObject = key2.ValuesDictionary.DatabaseObject;
278 key2.InternalSaveEntity(entityData.ValuesDictionary, entityToIdMap);
279 entityDataList.EntitiesData.Add(entityData);
280 }
281 return entityDataList;
282 }
283
284 public virtual ProjectData Save() {
285 ProjectData projectData = new() { ValuesDictionary = [] };
286 projectData.ValuesDictionary.DatabaseObject = ProjectTemplate;
287 foreach (Subsystem subsystem in Subsystems) {
288 ValuesDictionary valuesDictionary = [];
289 subsystem.Save(valuesDictionary);
290 if (valuesDictionary.Count > 0) {
291 projectData.ValuesDictionary.SetValue(subsystem.ValuesDictionary.DatabaseObject.Name, valuesDictionary);
292 }
293 }
294 projectData.NextEntityID = NextEntityID;
295 projectData.EntityDataList = SaveEntities(Entities);
296 return projectData;
297 }
298
299 public virtual void Dispose() {
300 if (m_entities != null) {
301 foreach (Entity entity in m_entities.Keys) {
302 entity.DisposeInternal();
303 }
304 }
305 if (Subsystems != null) {
306 foreach (Subsystem subsystem in Subsystems) {
307 subsystem.DisposeInternal();
308 }
309 }
310 OnProjectLoad = null;
311 EntityRemoved = null;
312 EntityAdded = null;
313 GC.SuppressFinalize(this);
314 }
315
316 public virtual void FireEntityAddedEvents(Entity entity) {
317 foreach (Component component in entity.Components) {
318 component.OnEntityAdded();
319 }
320 foreach (Subsystem subsystem in Subsystems) {
321 subsystem.OnEntityAdded(entity);
322 }
323 EntityAdded?.Invoke(this, new EntityAddRemoveEventArgs(entity));
324 entity.FireEntityAddedEvent();
325 }
326
327 public virtual void FireEntityRemovedEvents(Entity entity) {
328 foreach (Component component in entity.Components) {
329 component.OnEntityRemoved();
330 }
331 foreach (Subsystem subsystem in Subsystems) {
332 subsystem.OnEntityRemoved(entity);
333 }
334 EntityRemoved?.Invoke(this, new EntityAddRemoveEventArgs(entity));
335 entity.FireEntityRemovedEvent();
336 }
337
338 public static Dictionary<Entity, bool> DetermineNotOwnedEntities(IEnumerable<Entity> entities) {
339 Dictionary<Entity, bool> dictionary = [];
340 List<Entity> list = [];
341 foreach (Entity entity in entities) {
342 dictionary.Add(entity, true);
343 List<Entity> list2 = entity.InternalGetOwnedEntities();
344 if (list2 != null) {
345 list.AddRange(list2);
346 }
347 }
348 for (int i = 0; i < list.Count; i++) {
349 List<Entity> list3 = list[i].InternalGetOwnedEntities();
350 if (list3 != null) {
351 list.AddRange(list3);
352 }
353 dictionary.Remove(list[i]);
354 }
355 return dictionary;
356 }
357
358 public virtual void LoadSubsystem(Subsystem subsystem,
359 Dictionary<string, Subsystem> subsystemsByName,
360 Dictionary<Subsystem, bool> loadedSubsystems,
361 int depth) {
362 if (depth > 100) {
363 throw new InvalidOperationException(
364 $"Too deep dependencies recursion while loading subsystem \"{subsystem.ValuesDictionary.DatabaseObject.Name}\"."
365 );
366 }
367 if (loadedSubsystems.ContainsKey(subsystem)) {
368 return;
369 }
370 string value = subsystem.ValuesDictionary.GetValue("Dependencies", string.Empty);
371 if (!string.IsNullOrEmpty(value)) {
372 string[] array = value.Split(',', StringSplitOptions.RemoveEmptyEntries);
373 for (int i = 0; i < array.Length; i++) {
374 string text = array[i].Trim();
375 if (subsystemsByName.TryGetValue(text, out Subsystem value2)) {
376 LoadSubsystem(value2, subsystemsByName, loadedSubsystems, depth + 1);
377 continue;
378 }
379 throw new InvalidOperationException(
380 $"Dependency subsystem \"{text}\" not found when loading subsystem \"{subsystem.ValuesDictionary.DatabaseObject.Name}\"."
381 );
382 }
383 }
384 subsystem.Load(subsystem.ValuesDictionary);
385 loadedSubsystems.Add(subsystem, true);
386 }
387 }
388}
static void Error(object message)
定义 Log.cs:80
static void Warning(object message)
定义 Log.cs:68
static Type FindType(string typeName, bool skipSystemAssemblies, bool throwIfNotFound)
ValuesDictionary ValuesDictionary
List< Entity > InternalGetOwnedEntities()
List< Component > Components
void InternalLoadEntity(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
ValuesDictionary ValuesDictionary
void InternalSaveEntity(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
DatabaseObjectType MemberSubsystemTemplateType
virtual void RemoveEntity(Entity entity, bool disposeEntity)
static EventHandler< EntityAddRemoveEventArgs > EntityAdded
virtual List< Subsystem > Subsystems
virtual List< Entity > InitializeEntities(EntityDataList entityDataList)
virtual ProjectData Save()
virtual IEnumerable< Subsystem > FindSubsystems(Type type)
static Action< Project > BeforeSubsystemsAndEntitiesLoad
virtual void AddEntities(IEnumerable< Entity > entities)
static Dictionary< Entity, bool > DetermineNotOwnedEntities(IEnumerable< Entity > entities)
DatabaseObject m_projectTemplate
virtual Entity FindEntity(int EntityID)
virtual void LoadSubsystem(Subsystem subsystem, Dictionary< string, Subsystem > subsystemsByName, Dictionary< Subsystem, bool > loadedSubsystems, int depth)
virtual Subsystem FindSubsystem(string name, bool throwOnError)
virtual Subsystem FindSubsystem(Type type, string name, bool throwOnError)
virtual void FireEntityAddedEvents(Entity entity)
virtual Entity CreateEntity(ValuesDictionary valuesDictionary, int entityId=0)
virtual EntityDataList SaveEntities(IEnumerable< Entity > entities)
virtual void LoadEntities(EntityDataList entityDataList, List< Entity > entityList)
virtual IEnumerable< T > FindSubsystems< T >()
Project(GameDatabase gameDatabase, ProjectData projectData)
virtual void AddEntity(Entity entity)
List< Subsystem > m_subsystems
virtual void RemoveEntities(IEnumerable< Entity > entities, bool disposeEntities)
virtual GameDatabase GameDatabase
virtual void FireEntityRemovedEvents(Entity entity)
static Action< Project > OnProjectLoad
Dictionary< Entity, bool > m_entities
virtual DatabaseObject ProjectTemplate
static EventHandler< EntityAddRemoveEventArgs > EntityRemoved
virtual Dictionary< Entity, bool >.KeyCollection Entities
virtual void OnEntityAdded(Entity entity)
ValuesDictionary ValuesDictionary
virtual void Load(ValuesDictionary valuesDictionary)
virtual void OnEntityRemoved(Entity entity)
virtual void Save(ValuesDictionary valuesDictionary)
DatabaseObject(DatabaseObjectType databaseObjectType, Guid guid, string name, object value)