private void ApplyInheritance(EntityTemplate template, EntityTemplate parentTemplate) { foreach (var parentComponent in parentTemplate.Components) { //don't override existing components if (template.Components.ContainsKey(parentComponent.Key)) { continue; } template.Components.Add(parentComponent.Key, parentComponent.Value); } foreach (var childrenTemplate in parentTemplate.Children) { if (template.Children.ContainsKey(childrenTemplate.Key)) { continue; } template.Children.Add(childrenTemplate.Key, childrenTemplate.Value); } }
private void LoadTemplate(string filename) { if (!File.Exists(filename)) { throw new FileNotFoundException("Couldn't find template file.", filename); } try { var template = EntityTemplate.Parse(File.ReadAllText(filename)); #if NETSTANDARD2_1 if (!_loadedTemplates.TryAdd(template.Id, template)) { throw new DuplicateTemplateException(template.Id, filename); } #else if (!_loadedTemplates.ContainsKey(template.Id)) { _loadedTemplates.Add(template.Id, template); } else { throw new DuplicateTemplateException(template.Id, filename); } #endif } catch (Exception e) { _parsingFailures.Add(new TemplateParseFailedInfo { Exception = e, TemplateFilePath = filename }); } }
//TODO: think of generic interface to build ECS entity from the template-instantiated data private void InstantiateTemplate(EntityTemplate template, Entity entity, Entity?parentEntity) { if (parentEntity.HasValue) { entity.SetAsChildOf(parentEntity.Value); } foreach (var component in template.Components) { if (!_components.TryGetValue(component.Key, out var componentType)) { continue; } object componentInstance; if (componentType.GetInterfaces().Any(@interface => @interface.Name.StartsWith("IValueComponent"))) { componentInstance = FormatterServices.GetUninitializedObject(componentType); var propInfo = componentType.GetProperty("Value"); if (propInfo == null) { throw new InvalidOperationException($"Tried to get Value property from {componentType.Name} but failed. This is not something that is supposed to happen and should be reported in the Github repo as an issue."); } var propertyType = propInfo.PropertyType; if (propertyType.IsClass) { dynamic dest = Activator.CreateInstance(propertyType); if (!(component.Value is Dictionary <string, object> dict)) { throw new InvalidDataException( $"Expected deserialized component to be of type Dictionary<string, object>, but it was of type '{componentType.FullName}' - this is probably a bug."); } _mapper.Map(dict, dest, typeof(Dictionary <string, object>), propertyType); ((dynamic)componentInstance).Value = Convert.ChangeType(dest, propertyType); } else { componentInstance = FormatterServices.GetUninitializedObject(componentType); ((dynamic)componentInstance).Value = Convert.ChangeType(component.Value, ((dynamic)componentInstance).Value.GetType()); } } else if (component.Value is Dictionary <string, object> dict) { componentInstance = FormatterServices.GetUninitializedObject(componentType); _mapper.Map(dict, componentInstance, typeof(Dictionary <string, object>), componentType); } else { throw new InvalidDataException($"Expected deserialized component to be of type Dictionary<string, object>, but it was of type '{componentType.FullName}' - this is probably a bug."); } var entitySetMethod = EntitySetMethodInfo.MakeGenericMethod(componentType); entitySetMethod.Invoke(entity, new[] { componentInstance }); } foreach (var childTemplate in template.Children) { InstantiateTemplate(childTemplate.Value, _world.CreateEntity(), entity); } }