예제 #1
0
        /// <summary>
        /// Load all entity definitions
        /// </summary>
        private static void LoadEntities()
        {
            // Retrieve asset path and build entity database path
            var path = Path.Combine(Paths.DataDirectory, "json", "entities");

            // Inspect every JSON document and save in cache
            foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories))
            {
                // File is a full path to the particular document
                try
                {
                    // Parse JSON file
                    using (var fileReader = File.OpenText(file))
                        using (var jsonReader = new JsonTextReader(fileReader))
                        {
                            // Since we want to allow multiple entity definitions in a single file, we require
                            // the top level structure to be an array.
                            var dataSource = JArray.ReadFrom(jsonReader) as JArray;

                            // Loop through all entity definitions. They have to be objects.
                            foreach (var entry in dataSource)
                            {
                                if (entry.Type != JTokenType.Object)
                                {
                                    continue;
                                }

                                // Found an object.
                                var currentObject = entry as JObject;

                                // Try to create entity type info object and store in cache
                                var info = new EntityTypeInfo(currentObject);
                                TypeInfos.Add(info.Name, info);

                                // Store JSON object in cache for later use
                                JsonObjectCache.Add(info.Name, currentObject);
                            }
                        }
                }
                catch (Exception e)
                {
                    Logger.PostMessageTagged(SeverityLevel.Fatal, "EntityManager",
                                             String.Format("Failed to load entity definition file \"{0}\": {1}", Path.GetFileName(file), e.Message));

                    throw;
                }
            }

            Logger.PostMessageTagged(SeverityLevel.Debug, "EntityManager",
                                     $"Loaded {TypeInfos.Count} entity types");
        }
예제 #2
0
        /// <summary>
        /// Internal implementation of entity construction. Populates entity components with those
        /// associated with given entity type info object, and then continues recursively for any
        /// base types present in the type.
        /// </summary>
        /// <param name="e">Entity to populate</param>
        /// <param name="type">Entity type info object to retrieve component types from</param>
        /// <exception cref="EntityDependencyException">If a component of a given type already exists in the entity.</exception>
        /// <exception cref="Exception">If component construction fails</exception>
        private static void ConstructInternal(Entity e, EntityTypeInfo type)
        {
            // Retrieve entity type JSON node. This is safe since we checked that
            // the type is actually known to us beforehand.
            var obj = JsonObjectCache[type.Name];

            // Initialize all components
            foreach (var currentComponent in type.Components)
            {
                // Retrieve component type object
                var componentType = ComponentManager.GetComponentType(currentComponent);

                // Check if an instance of that component type already exists in the currently constructed
                // entity. This could indicate a circular dependency
                if (e.HasComponent(componentType))
                {
                    Logger.PostMessageTagged(SeverityLevel.Fatal, "EntityManager",
                                             String.Format("Found duplicate component type while constructing entity of type \"{0}\": \"{1}\"", e.TypeName, currentComponent));

                    Logger.PostMessageTagged(SeverityLevel.Info, "EntityManager", "This could indicate a circular dependency in the entity definition");

                    throw new EntityDependencyException("Multiple components of same type detected");
                }

                // Retrieve JSON subobject corresponding to current component
                var subObject = obj[currentComponent] as JObject;

                // Construct empty component instance
                var component = Activator.CreateInstance(componentType) as IComponent;

                // Check for possible failure
                if (component == null)
                {
                    Logger.PostMessageTagged(SeverityLevel.Fatal, "EntityManager", String.Format("Could not create instance of component \"{0}\"", currentComponent));
                    throw new Exception(String.Format("Could not create instance of component \"{0}\"", currentComponent));
                }

                // Parse JSON subobject
                component.Construct(subObject);

                // Add it to entity
                e.AddComponent(currentComponent, component);
            }

            // Do the same with all registered base entities/templates
            foreach (var baseType in type.Bases)
            {
                // We know that this type exists, since we called CheckDependencies earlier.
                ConstructInternal(e, TypeInfos[baseType]);
            }
        }