quick save returned; dynamically loading component methods
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 26 Feb 2022 21:54:20 +0000 (15:54 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 26 Feb 2022 21:54:20 +0000 (15:54 -0600)
run_tree/scenes/quick_save.scene
run_tree/scenes/quick_save_new.scene [new file with mode: 0644]
src/entity/manager.onyx
src/entity/player.onyx
src/entity/store.onyx
src/game.onyx

index 8d0cfb42c4ad3d818f2ba732bb7589bfd61e45cb..ff33349245e3fdf4a2ab241481ca07f10bc3f66e 100644 (file)
@@ -1,57 +1,60 @@
 [Wall]
-id = 10
-flags = 2
-pos.x = 168.0000
-pos.y = 320.0000
-size.x = 336.0000
-size.y = 32.0000
+    id = 10
+    flags = 2
+    pos.x = 168.0000
+    pos.y = 320.0000
+    size.x = 336.0000
+    size.y = 32.0000
 
 [Wall]
-id = 11
-flags = 2
-pos.x = 448.0000
-pos.y = 168.0000
-size.x = 32.0000
-size.y = 336.0000
+    id = 11
+    flags = 2
+    pos.x = 448.0000
+    pos.y = 168.0000
+    size.x = 32.0000
+    size.y = 336.0000
 
 [Player]
-id = 12
-flags = 2
-pos.x = 200.0000
-pos.y = 152.0000
-size.x = 48.0000
-size.y = 48.0000
-:PlayerComponent
-holding = 0
-controls.up = 87
-controls.down = 83
-controls.left = 65
-controls.right = 68
-controls.interact = 70
-controls.pick_up = 71
-color.r = 1.0000
-color.g = 1.0000
-color.b = 1.0000
-color.a = 1.0000
-facing = 4
+    id = 12
+    flags = 2
+    pos.x = 200.0000
+    pos.y = 152.0000
+    size.x = 48.0000
+    size.y = 48.0000
+
+    :PlayerComponent
+        holding = 0
+        controls.up = 87
+        controls.down = 83
+        controls.left = 65
+        controls.right = 68
+        controls.interact = 70
+        controls.pick_up = 71
+        color.r = 1.0000
+        color.g = 1.0000
+        color.b = 1.0000
+        color.a = 1.0000
+        facing = 4
 
 [Door]
-id = 13
-flags = 3
-pos.x = 352.0000
-pos.y = 320.0000
-size.x = 160.0000
-size.y = 32.0000
-:DoorComponent
-target_openness = 0.0000
+    id = 13
+    flags = 3
+    pos.x = 352.0000
+    pos.y = 320.0000
+    size.x = 160.0000
+    size.y = 32.0000
+
+    :DoorComponent
+        target_openness = 0.0000
 
 [Item_Entity]
-id = 14
-flags = 4
-pos.x = 272.0000
-pos.y = 144.0000
-size.x = 32.0000
-size.y = 32.0000
-:ItemComponent
-item = "beer"
+    id = 14
+    flags = 4
+    pos.x = 272.0000
+    pos.y = 144.0000
+    size.x = 32.0000
+    size.y = 32.0000
+    
+    :ItemComponent
+        item = "beer"
 
diff --git a/run_tree/scenes/quick_save_new.scene b/run_tree/scenes/quick_save_new.scene
new file mode 100644 (file)
index 0000000..bc595c2
--- /dev/null
@@ -0,0 +1,59 @@
+[Wall]
+id = 10
+flags = 2
+pos.x = 168.0000
+pos.y = 320.0000
+size.x = 336.0000
+size.y = 32.0000
+
+[Wall]
+id = 11
+flags = 2
+pos.x = 448.0000
+pos.y = 168.0000
+size.x = 32.0000
+size.y = 336.0000
+
+[Player]
+id = 12
+flags = 2
+pos.x = 342.9302
+pos.y = 205.3930
+size.x = 48.0000
+size.y = 48.0000
+:PlayerComponent
+color.r = 1.0000
+color.g = 1.0000
+color.b = 1.0000
+color.a = 1.0000
+holding = 0
+controls.up = 87
+controls.down = 83
+controls.left = 65
+controls.right = 68
+controls.interact = 70
+controls.pick_up = 71
+facing = 4
+
+[Door]
+id = 13
+flags = 3
+pos.x = 352.0000
+pos.y = 320.0000
+size.x = 160.0000
+size.y = 32.0000
+:DoorComponent
+max_openness = 0.8000
+target_openness = 0.0000
+openness = 0.0000
+
+[Item_Entity]
+id = 14
+flags = 4
+pos.x = 386.9302
+pos.y = 205.3930
+size.x = 32.0000
+size.y = 32.0000
+:ItemComponent
+item = "beer"
+
index 4448519ad89a5cfde29177fb1f720459f480674b..1f0dd3388b50cb9aeb1e0fcced6c426bd44f8c75 100644 (file)
@@ -15,30 +15,31 @@ Entity_ID :: #distinct u32
     });
 }
 
+#local Component_Vtable :: struct {
+    init  : (^Component) -> void               = null_proc;
+    update: (^Component, ^Entity, f32) -> void = null_proc;
+}
+
 Component :: struct {
-    type: type_expr;
+    [Entity_Store.Skip] use vtable: ^Component_Vtable;
+    [Entity_Store.Skip]     type: type_expr;
 }
 
 IsComponent :: interface (c: $C) {
     { c } -> ^Component;
 }
 
-UpdateComponent :: struct {
-    use base: Component;
-    func : (e: ^Entity, dt: f32) -> void;
-}
-
 RenderComponent :: struct {
     use base: Component;
     func : (e: ^Entity) -> void;
 }
 
-SizeComponent :: struct {
+SizeComponent :: struct [Entity_Store.Skip] {
     use base: Component;
     func : (e: ^Entity) -> Rect;
 }
 
-InteractableComponent :: struct {
+InteractableComponent :: struct [Entity_Store.Skip] {
     use base: Component;
     interact: (e: ^Entity, interactor: ^Entity) -> void;
 }
@@ -46,7 +47,8 @@ InteractableComponent :: struct {
 Entity :: struct {
     id: Entity_ID;
     flags: Entity_Flags;
-    schematic: type_expr;
+
+    [Entity_Store.Skip] schematic: type_expr;
 
     pos:  Vector2;
 
@@ -56,8 +58,9 @@ Entity :: struct {
         if e->has(SizeComponent) do return (e->get(SizeComponent)).func(e);
 
         return Rect.{ pos.x - size.x / 2, pos.y - size.y / 2, size.x, size.y };
-    }
+    };
 
+    [Entity_Store.Skip]
     components: Map(type_expr, ^Component);
     has :: (use this: ^Entity,  component_type: type_expr) => components->has(component_type);
     get :: (use this: ^Entity, $component_type: type_expr) => cast(^component_type) components[component_type];
@@ -87,6 +90,7 @@ Entity_Manager :: struct {
     entity_map: Map(Entity_ID, ^Entity);
 
     schematics: Map(str, ^Entity_Schematic);
+    component_vtables: Map(type_expr, ^Component_Vtable);
 
     next_entity_id: Entity_ID;
 
@@ -181,12 +185,20 @@ entity_manager_create_from_schematic :: (use this: ^Entity_Manager, schematic_na
 entity_manager_create_component :: (use this: ^Entity_Manager, $component_type: type_expr) -> ^component_type where IsComponent(^component_type) {
     comp := new(component_type, allocator=entity_allocator);
     comp.type = component_type;
+
+    if !component_vtables->has(comp.type) {
+        vtable := new(Component_Vtable, allocator=entity_allocator);
+        type_info.populate_struct_vtable(vtable, component_type, safe=false);
+        component_vtables[comp.type] = vtable;
+    }
+
+    comp.vtable = component_vtables->get(comp.type);
+
     return comp;
 }
 
 entity_manager_create_and_add :: macro (this: ^Entity_Manager, entity: ^Entity, $component_type: type_expr, init_block: Code) where IsComponent(^component_type) {
-    comp := new(component_type, allocator=this.entity_allocator);
-    comp.type = component_type;
+    comp := this->create_component(component_type);
 
     #insert init_block;
     entity->add(comp);
@@ -194,9 +206,13 @@ entity_manager_create_and_add :: macro (this: ^Entity_Manager, entity: ^Entity,
 
 entity_manager_update :: (use this: ^Entity_Manager, dt: f32) {
     for entities {
-        update_comp := it->get(UpdateComponent);
-        if update_comp != null {
-            update_comp.func(it, dt);
+        for^ entry: it.components.entries {
+            comp := entry.value;
+
+            @CompilerBug // comp->update(it, dt); should be legal here, but it says 'update' is not a member of '^Component'.
+            if comp.vtable.update != null_proc {
+                comp.vtable.update(comp, it, dt);
+            }
         }
     }
 }
index 64f74f293a4ed6b48129c90edd8a69f0337021c7..873bb4ed85b8d68f06601d6a22d6fb9445c7e3f0 100644 (file)
@@ -61,10 +61,6 @@ player_create :: (scene: ^Entity_Manager, pos: Vector2, controls := player_1_con
         comp.color = .{1,1,1};
     }
 
-    scene->create_and_add(this, UpdateComponent) {
-        comp.func = PlayerComponent.update;
-    }
-
     scene->create_and_add(this, RenderComponent) {
         comp.func = PlayerComponent.render;
     }
@@ -80,11 +76,9 @@ PlayerComponent :: struct {
     controls : Player_Controls;
     facing   := Facing.Up;
 
-    update :: (use this: ^Entity, dt: f32) {
+    update :: (player: ^PlayerComponent, use this: ^Entity, dt: f32) {
         speed :: 128.0f;
 
-        player := this->get(PlayerComponent);
-
         delta: Vector2;
         if is_key_down(player.controls.left)  { delta.x -= speed * dt; player.facing = .Left;  }
         if is_key_down(player.controls.right) { delta.x += speed * dt; player.facing = .Right; }
@@ -219,11 +213,6 @@ player_assets: struct {
 #local Door :: struct [Entity_Schematic.{create}] {
     create :: (scene) => door_create(scene, .{0, 0}, .{0, 0});
 
-    update :: (use this: ^Entity, dt: f32) {
-        door := this->get(DoorComponent);
-        door->update(dt);
-    }
-
     render :: (use this: ^Entity) {
         immediate_set_color(.{0.7, 0.7, 0.1});
 
@@ -253,7 +242,7 @@ DoorComponent :: struct {
     target_openness := 0.0f;
     openness        := 0.0f;
 
-    update :: (use this: ^DoorComponent, dt: f32) {
+    update :: (use this: ^DoorComponent, door: ^Entity, dt: f32) {
         if openness != target_openness {
             move_towards(^openness, target_openness, dt * 2);
         }
@@ -273,7 +262,6 @@ door_create :: (scene: ^Entity_Manager, pos, size: Vector2) -> ^Entity {
     this.flags |= .Solid;
 
     scene->create_and_add(this, DoorComponent)         {}
-    scene->create_and_add(this, UpdateComponent)       { comp.func = Door.update; }
     scene->create_and_add(this, RenderComponent)       { comp.func = Door.render; }
     scene->create_and_add(this, SizeComponent)         { comp.func = Door.get_rect; }
     scene->create_and_add(this, InteractableComponent) { comp.interact = Door.interact; }
index 5c05ceee3a69e460965fa883b614798109efa5ab..10a9c81b089ff87b2b4b6d5f4f4e2a2e73abe509 100644 (file)
@@ -8,7 +8,6 @@ Entity_Store :: enum {
 }
 
 entity_manager_save_to_file :: (use this: ^Entity_Manager, filename: str) {
-    /*
     err, output_file := os.open(filename, .Write);
     defer os.close(^output_file);
     writer_ := io.writer_make(^output_file);
@@ -19,9 +18,20 @@ entity_manager_save_to_file :: (use this: ^Entity_Manager, filename: str) {
     use type_info;
 
     for entities {
-        info := cast(^Type_Info_Struct) get_type_info(it.type);
-        io.write_format(writer, ":{}\n", info.name);
-        emit_struct_fields(any.{~~ it, it.type}, writer, "");
+        info := cast(^Type_Info_Struct) get_type_info(it.schematic);
+        io.write_format(writer, "[{}]\n", info.name);
+        emit_struct_fields(any.{~~ it, Entity}, writer, "");
+
+        for^ it.components.entries {
+            info := cast(^Type_Info_Struct) get_type_info(it.key);
+            for info.tags {
+                if it.type != Entity_Store do continue;
+                if *(cast(^Entity_Store) it.data) == .Skip do continue continue;
+            }
+
+            io.write_format(writer, ":{}\n", info.name);
+            emit_struct_fields(any.{~~ it.value, it.key}, writer, "");
+        }
         io.write(writer, "\n");
     }
 
@@ -71,7 +81,6 @@ entity_manager_save_to_file :: (use this: ^Entity_Manager, filename: str) {
             }
         }
     }
-    */
 }
 
 entity_manager_load_from_file :: (use this: ^Entity_Manager, filename: str) {
index aeab713ce20db1aa8b1fa5f757d953c33bf76e39..d2ca9f52adac53d91c4095123d160dd5876db185 100644 (file)
@@ -17,39 +17,13 @@ game_init :: () {
     load_assets();
 
     scene = entity_manager_create();
-    scene->load_from_file("scenes/quick_save.scene");
-    /*
-    // player := player_create(^scene);
-
-    player := scene.schematics["Player"](^scene);
-    scene->add(player);
-
-    // wall := wall_create(^scene, .{0, 100}, .{300, 40});
-    wall := scene.schematics["Wall"](^scene);
-    wall.pos = .{0, 100};
-    wall.size = .{300, 40};
-    scene->add(wall);
-
-    door := scene.schematics["Door"](^scene);
-    door.pos = .{500, 300};
-    door.size = .{100, 20};
-    scene->add(door);
-
-    item := scene.schematics["Item_Entity"](^scene);
-    item.pos = .{100, 200};
-    item.size = .{32, 32};
-    with (item->get(ItemComponent)) {
-        it.item = "beer";
-    }
-
-    scene->add(item);
-    */
+    scene->load_from_file(quick_save_file);
 
     item_store = item_store_make();
     item_store->load_items_from_file("scenes/default.items");
 }
 
-#local quick_save_file := "scenes/quick_save.scene";
+#local quick_save_file := "scenes/quick_save_new.scene";
 
 game_update :: (dt: f32) {
     if is_key_just_up(GLFW_KEY_F8) {