From 1fabc6c9cc7c43d02a80cf13d10895cc5ba80215 Mon Sep 17 00:00:00 2001 From: kipar Date: Wed, 27 Dec 2023 19:59:28 +0300 Subject: [PATCH] add_yaml --- spec/yaml_spec.cr | 29 +++++++++++++++++++++++++++++ src/myecs.cr | 21 ++++++++++++++++++++- src/yaml.cr | 25 +++++++++++++++++++++---- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/spec/yaml_spec.cr b/spec/yaml_spec.cr index 70f28e3..18b819d 100644 --- a/spec/yaml_spec.cr +++ b/spec/yaml_spec.cr @@ -25,3 +25,32 @@ it "load world from yaml" do world2.query(Supported).first.getSupported.should eq Supported.new(1, 2) world2.query(Unsupported).should be_empty end + +it "add entities from yaml" do + world1 = ECS::World.new + world1.new_entity.add(Supported.new(1, 2)) + world1.new_entity.add(Unsupported.new(3, 4)) + yaml = world1.to_yaml + world2 = ECS::World.new + world2.new_entity.add(Supported.new(10, 20)) + world2.add_yaml(yaml) + world2.query(Supported).to_a.map(&.getSupported).should eq [Supported.new(10, 20), Supported.new(1, 2)] + world2.query(Unsupported).should be_empty +end + +record WithLink < ECS::YAMLComponent, link : ECS::Entity + +it "keep links to entities" do + world1 = ECS::World.new + ent1 = world1.new_entity + ent2 = world1.new_entity + ent3 = world1.new_entity + ent2.add(Supported.new(1, 2)) + ent1.add(WithLink.new(ent3)) + ent3.add(WithLink.new(ent2)) + yaml = world1.to_yaml + world2 = ECS::World.new + world2.new_entity.add(Supported.new(10, 20)) + world2.add_yaml(yaml) + world2.query(WithLink).first.getWithLink.link.getWithLink.link.getSupported.should eq Supported.new(1, 2) +end diff --git a/src/myecs.cr b/src/myecs.cr index 269db19..cab08fb 100644 --- a/src/myecs.cr +++ b/src/myecs.cr @@ -4,6 +4,9 @@ module ECS # :nodoc: COMP_INDICES = {} of Component.class => Int32 + # :nodoc: + WORLD_BEING_LOADED = {} of Fiber => ECS::World + # Component - container for user data without / with small logic inside. # All components should be inherited from `ECS::Component` @[Packed] @@ -116,6 +119,16 @@ module ECS @world.check_gc_entity @id end + def to_cannon_io(io) + io.write_bytes self.id + io + end + + def self.from_cannon_io(io) : self + id = io.read_bytes(EntityID) + self.new(WORLD_BEING_LOADED[Fiber.current], id) + end + macro finished {% for obj in Component.all_subclasses %} {% obj_name = obj.id.split("::").last.id %} @@ -708,7 +721,13 @@ module ECS def decode(io) @free_entities = Cannon.decode(io, typeof(@free_entities)) @count_components = Cannon.decode(io, typeof(@count_components)) - @pools.each &.decode(io) + raise "recurrent deserialization is not supported" if WORLD_BEING_LOADED.has_key?(Fiber.current) + WORLD_BEING_LOADED[Fiber.current] = self + begin + @pools.each &.decode(io) + ensure + WORLD_BEING_LOADED.delete Fiber.current + end end end diff --git a/src/yaml.cr b/src/yaml.cr index 77f5ade..95e6665 100644 --- a/src/yaml.cr +++ b/src/yaml.cr @@ -120,7 +120,9 @@ module ECS struct Entity def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node) name = String.new(ctx, node) - storage = ctx.read_alias(FakeNode.new("_ecs_storage"), EntitiesHash) + # storage = ctx.read_alias(FakeNode.new("_ecs_storage"), EntitiesHash) + object_id, _ = ctx.@anchors["_ecs_storage"] + storage = Pointer(Void).new(object_id).as(EntitiesHash) storage.storage[name] end @@ -157,16 +159,31 @@ module ECS def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node) world = self.new - storage = EntitiesHash.new(world) - ctx.record_anchor(FakeNode.new("_ecs_storage"), storage) + names = EntitiesHash.new(world) + ctx.record_anchor(FakeNode.new("_ecs_storage"), names) stubs = Hash(String, Array(YAMLComponent)).new(ctx, node) stubs.each do |k, v| - ent = storage.storage[k] + ent = names.storage[k] v.each do |comp| ent.add(comp) end end world end + + def add_yaml(io, names : EntitiesHash? = nil) + names = EntitiesHash.new(self) unless names + ctx = YAML::ParseContext.new + node = YAML::Nodes.parse(io).nodes.first + ctx.record_anchor(FakeNode.new("_ecs_storage"), names) + stubs = Hash(String, Array(YAMLComponent)).new(ctx, node) + stubs.each do |k, v| + ent = names.storage[k] + v.each do |comp| + ent.add(comp) + end + end + self + end end end