Allocate rooms in zones started

This commit is contained in:
2024-11-14 06:57:47 +03:00
parent 13fa1e6eef
commit 90bfc54952
8 changed files with 1750 additions and 819 deletions

View File

@@ -1,7 +1,7 @@
[layouts] [layouts]
entries=[ { entries=[ {
"children": [ 3, 4 ], "children": [ 4, 5 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"floor_index": 0, "floor_index": 0,
"index": 0, "index": 0,
@@ -9,7 +9,7 @@ entries=[ {
"order": 0, "order": 0,
"type": "layout" "type": "layout"
}, { }, {
"children": [ 5, 6, 7 ], "children": [ 6, 7, 8 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"floor_index": 0, "floor_index": 0,
"index": 1, "index": 1,
@@ -17,7 +17,7 @@ entries=[ {
"order": 0, "order": 0,
"type": "layout" "type": "layout"
}, { }, {
"children": [ 8, 9, 10, 11, 12 ], "children": [ 9, 10, 11, 12, 13 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"floor_index": 0, "floor_index": 0,
"index": 2, "index": 2,
@@ -25,136 +25,126 @@ entries=[ {
"order": 0, "order": 0,
"type": "layout" "type": "layout"
}, { }, {
"children": [ 13, 14 ], "children": [ 14, 15, 16, 17 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ ],
"floor_index": 0,
"index": 3, "index": 3,
"name": "v4",
"order": 4,
"type": "layout"
}, {
"children": [ 18, 19 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 4,
"name": "zone_0", "name": "zone_0",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
"zone_type": 1 "zone_type": 1
}, { }, {
"children": [ 15, 16, 17 ], "children": [ 20, 21, 22 ],
"commands": [ [ 4, [ ] ] ], "commands": [ [ 4, [ ] ] ],
"index": 4,
"name": "zone_1",
"order": 1,
"type": "zone",
"zone_type": 0
}, {
"children": [ 18, 19, 20, 21 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 5, "index": 5,
"name": "zone_1", "name": "zone_1",
"order": 1,
"type": "zone",
"zone_type": 0
}, {
"children": [ 23, 24, 25, 26 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 6,
"name": "zone_1",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
"zone_type": 1 "zone_type": 1
}, { }, {
"children": [ 22, 23, 24 ], "children": [ 27, 28, 29 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 6, "index": 7,
"name": "zone_0", "name": "zone_0",
"order": 1, "order": 1,
"type": "zone", "type": "zone",
"zone_type": 0 "zone_type": 0
}, { }, {
"children": [ 25, 26 ], "children": [ 30, 31 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 7, "index": 8,
"name": "unit_0", "name": "unit_0",
"order": 3, "order": 3,
"type": "unit" "type": "unit"
}, { }, {
"children": [ 27, 28 ], "children": [ 32, 33 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 8, "index": 9,
"name": "zone_0", "name": "zone_0",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
"zone_type": 1 "zone_type": 1
}, { }, {
"children": [ 29, 30 ], "children": [ 34, 35 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 9, "index": 10,
"name": "unit_0", "name": "unit_0",
"order": 0, "order": 0,
"type": "unit" "type": "unit"
}, { }, {
"children": [ 31, 32 ], "children": [ 36, 37 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 10, "index": 11,
"name": "unit_1", "name": "unit_1",
"order": 0, "order": 0,
"type": "unit" "type": "unit"
}, { }, {
"children": [ 33, 34 ], "children": [ 38, 39 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 11, "index": 12,
"name": "unit_2", "name": "unit_2",
"order": 0, "order": 0,
"type": "unit" "type": "unit"
}, { }, {
"children": [ 35, 36 ], "children": [ 40, 41 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 12, "index": 13,
"name": "unit_3", "name": "unit_3",
"order": 0, "order": 0,
"type": "unit" "type": "unit"
}, { }, {
"children": [ ], "children": [ 42, 43 ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 13,
"name": "living_room_0",
"order": 1,
"room_area": 144.0,
"room_type": 300,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 14, "index": 14,
"name": "kitchen_0", "name": "zone_0",
"order": 2,
"room_area": 16.0,
"room_type": 302,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 15,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ], [ 3, [ ] ] ],
"index": 16,
"name": "bathroom_0",
"order": 1, "order": 1,
"room_area": 16.0, "type": "zone",
"room_type": 201, "zone_type": 0
"type": "room",
"window": false
}, { }, {
"children": [ ], "children": [ 44, 45 ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 17, "index": 15,
"name": "bedroom_0", "name": "zone_1",
"order": 2, "order": 2,
"room_area": 64.0, "type": "zone",
"room_type": 202, "zone_type": 0
"type": "room", }, {
"window": true "children": [ 46, 47, 48 ],
"commands": [ ],
"index": 16,
"name": "zone_2",
"order": 3,
"type": "zone",
"zone_type": 0
}, {
"children": [ 49, 50, 51, 52 ],
"commands": [ ],
"index": 17,
"name": "zone_3",
"order": 4,
"type": "zone",
"zone_type": 1
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 18, "index": 18,
"name": "living_room_0", "name": "living_room_0",
"order": 0, "order": 1,
"room_area": 144.0, "room_area": 144.0,
"room_type": 300, "room_type": 300,
"type": "room", "type": "room",
@@ -164,6 +154,56 @@ entries=[ {
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 19, "index": 19,
"name": "kitchen_0", "name": "kitchen_0",
"order": 2,
"room_area": 16.0,
"room_type": 302,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 20,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ], [ 3, [ ] ] ],
"index": 21,
"name": "bathroom_0",
"order": 1,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 22,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
"room_type": 202,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 23,
"name": "living_room_0",
"order": 0,
"room_area": 144.0,
"room_type": 300,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 24,
"name": "kitchen_0",
"order": 1, "order": 1,
"room_area": 64.0, "room_area": 64.0,
"room_type": 302, "room_type": 302,
@@ -172,7 +212,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 20, "index": 25,
"name": "storage_room_0", "name": "storage_room_0",
"order": 2, "order": 2,
"room_area": 16.0, "room_area": 16.0,
@@ -182,7 +222,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ], [ 4, [ ] ] ], "commands": [ [ 5, [ ] ], [ 4, [ ] ] ],
"index": 21, "index": 26,
"name": "enterance_0", "name": "enterance_0",
"order": 3, "order": 3,
"room_area": 16.0, "room_area": 16.0,
@@ -192,7 +232,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 22, "index": 27,
"name": "wc_0", "name": "wc_0",
"order": 0, "order": 0,
"room_area": 16.0, "room_area": 16.0,
@@ -202,7 +242,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 23, "index": 28,
"name": "bathroom_0", "name": "bathroom_0",
"order": 1, "order": 1,
"room_area": 16.0, "room_area": 16.0,
@@ -212,7 +252,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 24, "index": 29,
"name": "bedroom_0", "name": "bedroom_0",
"order": 2, "order": 2,
"room_area": 64.0, "room_area": 64.0,
@@ -220,17 +260,17 @@ entries=[ {
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ 37, 38, 39 ], "children": [ 53, 54, 55 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 25, "index": 30,
"name": "zone_0", "name": "zone_0",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
"zone_type": 0 "zone_type": 0
}, { }, {
"children": [ 40, 41 ], "children": [ 56, 57 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 26, "index": 31,
"name": "zone_1", "name": "zone_1",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
@@ -238,7 +278,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 27, "index": 32,
"name": "enterance_0", "name": "enterance_0",
"order": 0, "order": 0,
"room_area": 64.0, "room_area": 64.0,
@@ -246,9 +286,9 @@ entries=[ {
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ 42 ], "children": [ 58 ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 28, "index": 33,
"name": "stair_0", "name": "stair_0",
"order": 0, "order": 0,
"room_area": 16.0, "room_area": 16.0,
@@ -256,83 +296,73 @@ entries=[ {
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ 43, 44, 45 ], "children": [ 59, 60, 61 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 29,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 46, 47 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 30,
"name": "zone_1",
"order": 0,
"type": "zone",
"zone_type": 1
}, {
"children": [ 48 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 31,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 49, 50 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 32,
"name": "zone_1",
"order": 0,
"type": "zone",
"zone_type": 1
}, {
"children": [ 51 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 33,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 52 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 34, "index": 34,
"name": "zone_1",
"order": 1,
"type": "zone",
"zone_type": 1
}, {
"children": [ 53 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 35,
"name": "zone_0", "name": "zone_0",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
"zone_type": 0 "zone_type": 0
}, { }, {
"children": [ 54 ], "children": [ 62, 63 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 35,
"name": "zone_1",
"order": 0,
"type": "zone",
"zone_type": 1
}, {
"children": [ 64 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ], "commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 36, "index": 36,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 65, 66 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 37,
"name": "zone_1",
"order": 0,
"type": "zone",
"zone_type": 1
}, {
"children": [ 67 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 38,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 68 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 39,
"name": "zone_1",
"order": 1,
"type": "zone",
"zone_type": 1
}, {
"children": [ 69 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 40,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 70 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 41,
"name": "zone_1", "name": "zone_1",
"order": 1, "order": 1,
"type": "zone", "type": "zone",
"zone_type": 1 "zone_type": 1
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 37, "index": 42,
"name": "bathroom_0",
"order": 0,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 38,
"name": "wc_0", "name": "wc_0",
"order": 1, "order": 1,
"room_area": 16.0, "room_area": 16.0,
@@ -341,65 +371,27 @@ entries=[ {
"window": false "window": false
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 39, "index": 43,
"name": "bedroom_0", "name": "bedroom_0",
"order": 2, "order": 2,
"room_area": 36.0, "room_area": 64.0,
"room_type": 202, "room_type": 202,
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 40,
"name": "living_room_0",
"order": 0,
"room_area": 36.0,
"room_type": 300,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 41,
"name": "kitchen_0",
"order": 1,
"room_area": 16.0,
"room_type": 302,
"type": "room",
"window": true
}, {
"children": [ 55, 56 ],
"commands": [ ], "commands": [ ],
"floor_index": 1, "index": 44,
"index": 42,
"name": "floor_0",
"order": 0,
"type": "floor"
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 43,
"name": "wc_0", "name": "wc_0",
"order": 0, "order": 1,
"room_area": 16.0, "room_area": 16.0,
"room_type": 200, "room_type": 200,
"type": "room", "type": "room",
"window": false "window": false
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 44,
"name": "bathroom_0",
"order": 1,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 45, "index": 45,
"name": "bedroom_0", "name": "bedroom_0",
"order": 2, "order": 2,
@@ -409,18 +401,38 @@ entries=[ {
"window": true "window": true
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 46, "index": 46,
"name": "kitchen_0", "name": "wc_0",
"order": 0, "order": 1,
"room_area": 16.0, "room_area": 16.0,
"room_type": 302, "room_type": 200,
"type": "room", "type": "room",
"window": true "window": false
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 47, "index": 47,
"name": "bathroom_0",
"order": 2,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ ],
"index": 48,
"name": "bathroom_1",
"order": 3,
"room_area": 144.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ ],
"index": 49,
"name": "living_room_0", "name": "living_room_0",
"order": 1, "order": 1,
"room_area": 144.0, "room_area": 144.0,
@@ -429,52 +441,32 @@ entries=[ {
"window": true "window": true
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 48, "index": 50,
"name": "bathroom_0",
"order": 0,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 49,
"name": "kitchen_0", "name": "kitchen_0",
"order": 0, "order": 2,
"room_area": 64.0, "room_area": 64.0,
"room_type": 302, "room_type": 302,
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 50, "index": 51,
"name": "living_room_0", "name": "dining_room_0",
"order": 1, "order": 3,
"room_area": 64.0, "room_area": 144.0,
"room_type": 300, "room_type": 303,
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ ],
"index": 51,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 52, "index": 52,
"name": "living_room_0", "name": "enterance_0",
"order": 0, "order": 4,
"room_area": 64.0, "room_area": 16.0,
"room_type": 300, "room_type": 304,
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
@@ -491,6 +483,144 @@ entries=[ {
"children": [ ], "children": [ ],
"commands": [ [ 5, [ ] ] ], "commands": [ [ 5, [ ] ] ],
"index": 54, "index": 54,
"name": "wc_0",
"order": 1,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 55,
"name": "bedroom_0",
"order": 2,
"room_area": 36.0,
"room_type": 202,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 56,
"name": "living_room_0",
"order": 0,
"room_area": 36.0,
"room_type": 300,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 57,
"name": "kitchen_0",
"order": 1,
"room_area": 16.0,
"room_type": 302,
"type": "room",
"window": true
}, {
"children": [ 71, 72 ],
"commands": [ ],
"floor_index": 1,
"index": 58,
"name": "floor_0",
"order": 0,
"type": "floor"
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 59,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 60,
"name": "bathroom_0",
"order": 1,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 61,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
"room_type": 202,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 62,
"name": "kitchen_0",
"order": 0,
"room_area": 16.0,
"room_type": 302,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 63,
"name": "living_room_0",
"order": 1,
"room_area": 144.0,
"room_type": 300,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 64,
"name": "bathroom_0",
"order": 0,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 65,
"name": "kitchen_0",
"order": 0,
"room_area": 64.0,
"room_type": 302,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 66,
"name": "living_room_0",
"order": 1,
"room_area": 64.0,
"room_type": 300,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 67,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 68,
"name": "living_room_0", "name": "living_room_0",
"order": 0, "order": 0,
"room_area": 64.0, "room_area": 64.0,
@@ -498,24 +628,44 @@ entries=[ {
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ 57 ], "children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 69,
"name": "bathroom_0",
"order": 0,
"room_area": 16.0,
"room_type": 201,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 70,
"name": "living_room_0",
"order": 0,
"room_area": 64.0,
"room_type": 300,
"type": "room",
"window": true
}, {
"children": [ 73 ],
"commands": [ ], "commands": [ ],
"index": 55, "index": 71,
"name": "zone_0", "name": "zone_0",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
"zone_type": 1 "zone_type": 1
}, { }, {
"children": [ 58, 59 ], "children": [ 74, 75 ],
"commands": [ ], "commands": [ ],
"index": 56, "index": 72,
"name": "unit_0", "name": "unit_0",
"order": 0, "order": 0,
"type": "unit" "type": "unit"
}, { }, {
"children": [ ], "children": [ ],
"commands": [ ], "commands": [ ],
"index": 57, "index": 73,
"name": "storage_room_0", "name": "storage_room_0",
"order": 0, "order": 0,
"room_area": 64.0, "room_area": 64.0,
@@ -523,17 +673,17 @@ entries=[ {
"type": "room", "type": "room",
"window": true "window": true
}, { }, {
"children": [ 60 ], "children": [ 76 ],
"commands": [ ], "commands": [ ],
"index": 58, "index": 74,
"name": "zone_0", "name": "zone_0",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
"zone_type": 0 "zone_type": 0
}, { }, {
"children": [ 61 ], "children": [ 77 ],
"commands": [ ], "commands": [ ],
"index": 59, "index": 75,
"name": "zone_1", "name": "zone_1",
"order": 0, "order": 0,
"type": "zone", "type": "zone",
@@ -541,7 +691,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ ], "commands": [ ],
"index": 60, "index": 76,
"name": "wc_0", "name": "wc_0",
"order": 0, "order": 0,
"room_area": 16.0, "room_area": 16.0,
@@ -551,7 +701,7 @@ entries=[ {
}, { }, {
"children": [ ], "children": [ ],
"commands": [ ], "commands": [ ],
"index": 61, "index": 77,
"name": "living_room_0", "name": "living_room_0",
"order": 0, "order": 0,
"room_area": 16.0, "room_area": 16.0,

View File

@@ -57,10 +57,17 @@ public:
void queue_grow_cell(flecs::entity seed_e, int id); void queue_grow_cell(flecs::entity seed_e, int id);
void growth_module(flecs::world &ecs, void growth_module(flecs::world &ecs,
const String &module_name); const String &module_name);
void room_growth_module(flecs::world &ecs,
const String &module_name);
void create_floor_components( void create_floor_components(
flecs::entity floor_e, flecs::entity base_floor_e, flecs::entity floor_e, flecs::entity base_floor_e,
const WorldEditor::components::buildings_layout_grid_size const WorldEditor::components::buildings_layout_grid_size
&size); &size);
void create_region(flecs::entity floor_e, flecs::entity seed_e,
flecs::entity region_e,
const Vector2i &position, float area);
bool check_region(flecs::entity floor_e, int index,
const Rect2i &rect);
graph_module(flecs::world &ecs); graph_module(flecs::world &ecs);
}; };
}; };

View File

@@ -868,7 +868,48 @@ void BuildingLayoutGraphUI::draw_2d_grid_view(Control *draw)
Math::randf(), Math::randf(),
1); 1);
draw->draw_rect(Rect2(dx, dy, dsize, dsize), draw->draw_rect(Rect2(dx, dy, dsize, dsize),
colors[cell.type]); colors[cell.type], true);
draw->draw_rect(Rect2(dx, dy, dsize, dsize),
Color(0.1f, 0.1f, 0.1f, 1.0f),
false);
if (fc.has<WorldEditor::components::
outside_wall>())
draw->draw_circle(
Vector2(dx + 0.5f * dsize,
dy + 0.5f * dsize),
dsize * 0.4f,
Color(0, 0, 1, 1));
if (fc.has<WorldEditor::components::border>())
draw->draw_circle(
Vector2(dx + 0.5f * dsize,
dy + 0.5f * dsize),
dsize * 0.2f,
Color(1, 0.3, 1, 1));
int mcount = 0;
fc.each<WorldEditor::components::
belongs_room>([dx, dy, dsize,
&mcount, &draw,
&colors](
flecs::entity
re) {
assert(mcount == 0);
if (!colors.has(String(re.path()))) {
colors[String(re.path())] =
Color(Math::randf(),
Math::randf(),
Math::randf(),
1.0f);
draw->draw_rect(
Rect2(dx + 0.1f * dsize,
dy + 0.1f * dsize,
0.8f * dsize,
0.8f * dsize),
colors[String(
re.path())],
true);
}
mcount++;
});
print_line( print_line(
"draw cell: (" + itos(x) + ", " + "draw cell: (" + itos(x) + ", " +
itos(y) + ") (" + String::num(dx) + itos(y) + ") (" + String::num(dx) +

View File

@@ -3,6 +3,7 @@
#include "world_editor.h" #include "world_editor.h"
#include "editor_event.h" #include "editor_event.h"
#include "building_layout_graph.h" #include "building_layout_graph.h"
#include "graph_module.h"
#define MIN_ROOM_SIZE 16 /* 4 * 4 tiles */ #define MIN_ROOM_SIZE 16 /* 4 * 4 tiles */
@@ -265,584 +266,73 @@ void BuildingLayoutGraph::graph_module::queue_grow_cell(flecs::entity seed_e,
WorldEditor::components::buildings_layout_grid_queue>(); WorldEditor::components::buildings_layout_grid_queue>();
} }
} }
void BuildingLayoutGraph::graph_module::growth_module(flecs::world &ecs,
const String &module_name)
{
struct growth_regions {
struct region {
Rect2i rect;
bool can_grow_square;
};
HashMap<flecs::entity_t, struct region> regions;
};
ecs.component<growth_regions>();
flecs::entity GraphFilter = ecs.entity("GraphFilter")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphFilter.disable();
struct make_random {
int seed;
int next;
make_random(int seed)
: seed(seed)
, next(seed)
{
}
int get()
{
next = next * 1103515245 + 12345;
return (int)((unsigned)next >> 16) % 32768;
}
};
struct grid_calc {
int grid_size;
int index2x(int index)
{
return index % grid_size;
}
int index2y(int index)
{
return index / grid_size;
}
void get_cadidates(int index, int *candidates)
{
int i, j, idx = 0;
int x = index2x(index);
int y = index2y(index);
for (i = -1; i < 2; i++) {
for (j = -1; j < 2; j++)
if (i != 0 || j != 0) {
int cx = x + i, cy = y + j;
if (cx >= 0 && cx < grid_size &&
cy >= 0 && cy < grid_size) {
int id = cx +
grid_size * cy;
candidates[idx++] = id;
}
}
}
}
grid_calc(flecs::entity layout_e)
: grid_size(
layout_e.get<WorldEditor::components::
buildings_layout_grid_size>()
->grid_size)
{
assert(layout_e.is_valid());
}
grid_calc(int grid_size)
: grid_size(grid_size)
{
assert(grid_size > 0);
}
};
struct grid_misc {
LocalVector<Pair<flecs::entity_t, Vector2i> > positions;
LocalVector<Vector2i> accepted;
struct make_random r;
grid_misc()
: r(100)
{
}
void get_dim_candidates(const Vector2i &base, int dim,
Vector2i *candidates)
{
int i;
std::vector<Vector2i> candidates_data = {
/* clang-format off */
{ base.x + dim, base.y },
{ base.x + dim, base.y + dim },
{ base.x, base.y + dim },
{ base.x - dim, base.y + dim },
{ base.x - dim, base.y },
{ base.x - dim, base.y - dim },
{ base.x, base.y - dim },
{ base.x + dim, base.y - dim },
/* clang-format on */
};
for (i = 0; i < (int)candidates_data.size(); i++)
candidates[i] = candidates_data[i];
}
void setup_floor(
flecs::entity grid_e, flecs::entity_t base_et,
const WorldEditor::components::buildings_layout_grid_size
&size,
BuildingLayoutGraph::graph_module *obj)
{
int i, j;
flecs::entity base_floor_e =
grid_e.world().entity(base_et);
flecs::log::warn("base_floor: %s",
base_floor_e.path().c_str());
int floor_index =
base_floor_e
.get<WorldEditor::components::
buildings_layout_floor_index>()
->index;
String floor_name = "floor_" + itos(floor_index);
flecs::entity floor_e =
grid_e.lookup(floor_name.ascii().ptr());
print_line("grid: " + String(grid_e.path()));
print_line("floor: " + floor_name);
assert(floor_e.is_valid());
assert(grid_e.is_valid());
obj->create_floor_components(floor_e, base_floor_e,
size);
flecs::log::warn("grid floor: %s",
floor_e.path().c_str());
for (i = 0; i < (int)positions.size(); i++)
for (j = 0; j < (int)positions.size(); j++) {
if (i == j)
continue;
if (positions[i].second ==
positions[j].second)
flecs::log::err(
"duplicate positions");
assert(positions[i].second !=
positions[j].second);
}
for (i = 0; i < (int)positions.size(); i++) {
int cell_id =
positions[i].second.x +
size.grid_size * positions[i].second.y;
flecs::entity region_e = grid_e.world().entity(
positions[i].first);
assert(region_e.is_valid());
assert(floor_e.is_valid());
flecs::entity cell_e = obj->create_cell(
floor_e, region_e, cell_id);
assert(cell_e.is_valid());
flecs::log::warn("grid cell: %s",
cell_e.path().c_str());
}
}
float get_entity_area(flecs::entity e) const
{
return e.get<WorldEditor::components::
buildings_layout_area>()
->area;
}
float get_entity_area(flecs::world &&ecs,
flecs::entity_t et) const
{
flecs::entity e = ecs.entity(et);
return e.get<WorldEditor::components::
buildings_layout_area>()
->area;
}
float get_entity_area(flecs::world &ecs,
flecs::entity_t et) const
{
flecs::entity e = ecs.entity(et);
return e.get<WorldEditor::components::
buildings_layout_area>()
->area;
}
int get_base_radius(flecs::world &&ecs,
flecs::entity_t et) const
{
float base_area = get_entity_area(ecs, et);
int base_radius =
(int)((Math::sqrt(base_area) * 1.5f) / 2.0f) /
4; /* grid conversion */
return base_radius;
}
int get_base_radius(flecs::world &ecs, flecs::entity_t et) const
{
float base_area = get_entity_area(ecs, et);
int base_radius =
(int)((Math::sqrt(base_area) * 1.5f) / 2.0f) /
4; /* grid conversion */
return base_radius;
}
int distance_squared(const Vector2i &p1,
const Vector2i &p2) const
{
int lx = p2.x - p1.x;
int ly = p2.y - p1.y;
return lx * lx + ly * ly;
}
bool check_candidates_tolerance(const Vector2i check)
{
int i;
bool ret = true;
for (i = 0; i < (int)positions.size(); i++)
if (distance_squared(check,
positions[i].second) < 1) {
ret = false;
break;
}
return ret;
}
void filter_candidates(
flecs::entity ce, float area,
const WorldEditor::components::buildings_layout_grid_size
&size)
{
int which = which_position();
if (positions.empty()) {
/* starting at grid center */
Vector2i start_pos(size.grid_size / 2,
size.grid_size / 2);
positions.push_back(
Pair<flecs::entity_t, Vector2i>(
ce.id(), start_pos));
return;
}
while (1) {
int j, k;
const Vector2i &base = positions[which].second;
flecs::entity_t base_et =
positions[which].first;
int base_radius =
get_base_radius(ce.world(), base_et);
base_radius = MAX(1, base_radius);
int local_radius =
(int)((Math::sqrt(area) * 1.5f) /
2.0f) /
4; /* grid conversion */
local_radius = MAX(1, local_radius);
int dim = base_radius + local_radius;
dim = MAX(1, dim);
/* grid coordinates */
Vector2i candidates[8];
get_dim_candidates(base, dim, &candidates[0]);
for (j = 0; j < (int)(sizeof(candidates) /
sizeof(candidates[0]));
j++) {
print_line("candidate: " +
itos(candidates[j].x) +
", " +
itos(candidates[j].y));
if (candidates[j].x < 0 ||
candidates[j].x >= size.grid_size)
continue;
if (candidates[j].y < 0 ||
candidates[j].y >= size.grid_size)
continue;
if (!check_candidates_tolerance(
candidates[j]))
continue;
for (k = 0; k < (int)positions.size();
k++) {
assert(k <
(int)positions.size());
flecs::entity_t pbase_et =
positions[k].first;
float parea = get_entity_area(
ce.world(), pbase_et);
int pdim =
(int)((Math::sqrt(
parea) *
1.5f) /
2.0f) /
4; /* radius converted to grid 4x4*/
int radius =
pdim + local_radius;
int radius_sq = radius * radius;
if (distance_squared(
positions[k].second,
candidates[j]) <
radius_sq)
continue;
assert(check_candidates_tolerance(
candidates[j]));
accepted.push_back(
candidates[j]);
}
}
if (accepted.size() == 0) {
which = which_position();
print_line(
"reset choice: " + itos(which) +
" " + itos(positions.size()));
continue;
}
assert(accepted.size() > 0);
const Vector2i &selected =
accepted[which_selected()];
assert(check_candidates_tolerance(selected));
Pair<flecs::entity_t, Vector2i> m(ce.id(),
selected);
positions.push_back(m);
flecs::log::warn("add position: %d, %d",
selected.x, selected.y);
accepted.clear();
break;
}
}
int which_position()
{
int which;
if (positions.size() == 0)
return -1;
which = r.get() % positions.size();
assert(which < (int)positions.size());
return which;
}
int which_selected()
{
int which;
if (accepted.size() == 0)
return -1;
which = r.get() % accepted.size();
assert(which < (int)accepted.size());
return which;
}
};
ecs.system<const WorldEditor::components::buildings_layout_grid_size>(
"CreateGrid")
.kind(GraphSolve)
.write<WorldEditor::components::buildings_layout_grid>()
.each([this](flecs::iter &it, size_t count,
const WorldEditor::components::
buildings_layout_grid_size &size) {
struct grid_misc grid;
flecs::entity graph_e = it.entity(count);
graph_e.world().defer_suspend();
flecs::log::warn("creating grid for: %s",
graph_e.path().c_str());
flecs::entity grid_base_e = get_layout_grid_base();
flecs::entity grid_e =
grid_base_e.lookup(graph_e.name());
assert(grid_e.is_valid());
flecs::log::warn("creating grid for: %s: %s",
graph_e.path().c_str(),
grid_e.path().c_str());
/* starting at grid center */
const List<Pair<int, flecs::entity_t> >::Element *me =
size.floors.front();
while (me) {
flecs::query<const WorldEditor::components::
buildings_layout_area>
q = graph_e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_area>()
.with(flecs::ChildOf,
me->get().second)
.scope_open()
.with<WorldEditor::components::
buildings_layout_zone>()
.or_()
.with<WorldEditor::components::
buildings_layout_unit>()
.scope_close()
.build();
q.each([size,
&grid](flecs::entity ce,
const WorldEditor::components::
buildings_layout_area
&area) {
flecs::log::warn(
"generating positions for: %s",
ce.path().c_str());
grid.filter_candidates(ce, area.area,
size);
});
grid.setup_floor(grid_e, me->get().second, size,
this);
me = me->next();
}
graph_e.world().defer_resume();
});
ecs.system("AssembleSkeletonEnd")
.kind(GraphSolve)
.run([module_name](flecs::iter &it) {
print_line("Assembling skeleton done...");
it.world()
.lookup((module_name + "::GraphSolveZones")
.ascii()
.ptr())
.disable();
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.enable();
EditorEvent::get_singleton()->event.emit(
"update_layout_view", varray());
// assert(false);
});
ecs.system<WorldEditor::components::buildings_layout_grid_floor>(
"GrowFloorRegions")
.kind(0)
.each([this](flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor
&fl) {
/* TODO: limit growth per region too */
struct grid_calc grid(fl.grid_size);
if (fl.size_left <= 0)
return;
flecs::query<const WorldEditor::components::
buildings_layout_grid_cell>
q = floor_e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with(flecs::ChildOf, floor_e)
.without<WorldEditor::components::
final_cell>()
.build();
q.each([this, &floor_e, &fl,
&grid](flecs::entity et,
const WorldEditor::components::
buildings_layout_grid_cell &cell) {
int index = cell.index;
assert(et.is_valid());
int i;
LocalVector<int> candidates;
candidates.resize(8);
grid.get_cadidates(cell.index,
candidates.ptr());
int extended = 0;
for (i = 0; i < (int)candidates.size(); i++) {
if (have_cell(floor_e, candidates[i]))
continue;
queue_grow_cell(et, candidates[i]);
extended++;
}
if (extended == 0)
et.add<WorldEditor::components::
final_cell>();
print_line("size: " + itos(grid.grid_size) +
" index: " + itos(index));
});
});
ecs.system<const WorldEditor::components::buildings_layout_grid_cell>(
"GrowRegions")
.kind(0)
.without<WorldEditor::components::final_cell>()
.read<WorldEditor::components::buildings_layout_grid_size>()
.write<WorldEditor::components::buildings_layout_grid_cell>()
.write<WorldEditor::components::buildings_layout_grid_floor>()
.write<WorldEditor::components::buildings_layout_grid_queue>()
.each([this](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell &cell) {
e.world().defer_suspend();
int index = cell.index;
assert(e.is_valid());
flecs::entity floor_e = e.parent();
assert(floor_e.is_valid());
flecs::entity grid_e = floor_e.parent();
assert(grid_e.is_valid());
String layout_name(grid_e.name());
flecs::entity base_e = get_layout_base();
flecs::entity layout_e =
base_e.lookup(layout_name.ascii().ptr());
assert(layout_e.is_valid());
struct grid_calc grid(layout_e);
int i;
LocalVector<int> candidates;
candidates.resize(8);
grid.get_cadidates(cell.index, candidates.ptr());
int extended = 0;
for (i = 0; i < (int)candidates.size(); i++) {
if (have_cell(floor_e, candidates[i]))
continue;
queue_grow_cell(e, candidates[i]);
#if 0
String c_name = "cell_" + itos(candidates[i]);
flecs::entity c_e =
e.parent().lookup(c_name.ascii().ptr());
#endif
extended++;
}
if (extended == 0)
e.add<WorldEditor::components::final_cell>();
print_line("size: " + itos(grid.grid_size) +
" index: " + itos(index));
e.world().defer_resume();
});
ecs.system<WorldEditor::components::buildings_layout_grid_floor,
WorldEditor::components::buildings_layout_grid_queue>(
"GrowCommitQueue")
.kind(0)
.each([this](flecs::entity e,
WorldEditor::components::buildings_layout_grid_floor
&fl,
WorldEditor::components::buildings_layout_grid_queue
&queue) {
List<Pair<flecs::entity_t, int> >::Element *me =
queue.queue.front();
while (me) {
flecs::entity seed_e =
e.world().entity(me->get().first);
int id = me->get().second;
if (!fl.cells.has(id)) {
grow_cell(seed_e, id);
fl.cells.insert(id);
}
me = me->next();
}
queue.queue.clear();
e.remove<WorldEditor::components::
buildings_layout_grid_queue>();
});
ecs.system("RunGrow").kind(GraphFilter).run([module_name](flecs::iter &it) {
int i;
it.world().defer_suspend();
print_line("Running grow...");
for (i = 0; i < 10; i++) {
it.world()
.system(it.world().lookup(
(module_name + "::GrowFloorRegions")
.ascii()
.ptr()))
.run();
it.world()
.system(it.world().lookup(
(module_name + "::GrowCommitQueue")
.ascii()
.ptr()))
.run();
}
it.world().defer_resume();
flecs::query<const WorldEditor::components::
buildings_layout_grid_floor>
q = it.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_floor>()
.build();
int count_left = 0;
int count_run = 0;
q.each([&count_left,
&count_run](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_floor &fl) {
count_run++;
count_left += MAX(0, fl.size_left);
});
// assert(false);
if (count_run > 0 && count_left <= 0) {
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.disable();
print_line("Grow done");
}
});
}
void BuildingLayoutGraph::graph_module::create_floor_components( void BuildingLayoutGraph::graph_module::create_floor_components(
flecs::entity floor_e, flecs::entity base_floor_e, flecs::entity floor_e, flecs::entity base_floor_e,
const WorldEditor::components::buildings_layout_grid_size &size) const WorldEditor::components::buildings_layout_grid_size &size)
{ {
floor_e.set<WorldEditor::components::buildings_layout_grid_floor>( floor_e.set<WorldEditor::components::buildings_layout_grid_floor>(
{ Set<int>(), size.grid_size, size.growth_size }); { Set<int>(), size.grid_size, size.growth_size });
floor_e.set<growth_regions>(
{ Vector<struct growth_regions::region>() });
floor_e.add<WorldEditor::components::belongs>(base_floor_e); floor_e.add<WorldEditor::components::belongs>(base_floor_e);
} }
void BuildingLayoutGraph::graph_module::create_region(flecs::entity floor_e,
flecs::entity seed_e,
flecs::entity region_e,
const Vector2i &position,
float area)
{
int i;
struct growth_regions::region r;
r.seed_et = seed_e.id();
r.region_et = region_e.id();
r.rect.position = position;
r.rect.size = Vector2i(1, 1);
r.remains_area = MAX((int)(area * 2.0f) / 16 + 1, 16);
r.can_grow_square = true;
bool ok = true;
assert(check_region(floor_e, -1, r.rect));
const struct growth_regions *reg = floor_e.get<growth_regions>();
for (i = 0; i < reg->regions.size(); i++) {
if (reg->regions[i].region_et == r.region_et) {
ok = false;
break;
}
if (reg->regions[i].rect.position == r.rect.position) {
ok = false;
break;
}
}
r.remains_area -= 1;
assert(ok);
if (ok) {
floor_e.get_mut<growth_regions>()->regions.push_back(r);
floor_e.modified<growth_regions>();
flecs::log::warn("region created for %s",
region_e.path().c_str());
}
}
bool BuildingLayoutGraph::graph_module::check_region(flecs::entity floor_e,
int index,
const Rect2i &rect)
{
const Vector<growth_regions::region> &regions =
floor_e.get<growth_regions>()->regions;
int i;
bool ret = true;
for (i = 0; i < regions.size(); i++) {
if (i == index)
continue;
if (rect.intersects(regions[i].rect)) {
ret = false;
break;
}
}
return ret;
}
BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs) BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
{ {
ecs.module<BuildingLayoutGraph::graph_module>(); ecs.module<BuildingLayoutGraph::graph_module>();
@@ -893,6 +383,11 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
GraphSolve = ecs.entity("GraphSolve") GraphSolve = ecs.entity("GraphSolve")
.add(flecs::Phase) .add(flecs::Phase)
.depends_on(GraphSolveFloors); .depends_on(GraphSolveFloors);
flecs::entity GraphAssembleSkeleton =
ecs.entity("GraphAssembleSkeleton")
.add(flecs::Phase)
.depends_on(GraphSolve);
GraphAssembleSkeleton.disable();
flecs::entity GraphPostSolve = ecs.entity("GraphPostSolve") flecs::entity GraphPostSolve = ecs.entity("GraphPostSolve")
.add(flecs::Phase) .add(flecs::Phase)
.depends_on(flecs::PostUpdate); .depends_on(flecs::PostUpdate);
@@ -1060,9 +555,36 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
buildings_layout_area &area) { buildings_layout_area &area) {
if (area.area < MIN_ROOM_SIZE) { if (area.area < MIN_ROOM_SIZE) {
badness++; badness++;
assert(false);
} }
}); });
if (badness == 0) {
it.world()
.lookup((module_name +
"::GraphSolveUnits")
.ascii()
.ptr())
.enable();
it.world()
.lookup((module_name +
"::GraphSolveFloors")
.ascii()
.ptr())
.enable();
} else {
it.world()
.lookup((module_name +
"::GraphSolveUnits")
.ascii()
.ptr())
.disable();
it.world()
.lookup((module_name +
"::GraphSolveFloors")
.ascii()
.ptr())
.disable();
}
print_line("Zones processing done..."); print_line("Zones processing done...");
}); });
ecs.system("UnitsStart") ecs.system("UnitsStart")
@@ -1279,10 +801,19 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
buildings_layout_area &area) { buildings_layout_area &area) {
if (area.area < MIN_ROOM_SIZE) { if (area.area < MIN_ROOM_SIZE) {
badness++; badness++;
assert(false);
} }
}); });
if (badness == 0) {
flecs::world w = it.world();
// create indices
w.lookup((module_name +
"::GraphAssembleSkeleton")
.ascii()
.ptr())
.enable();
print_line("Floor processing done..."); print_line("Floor processing done...");
} else
print_line("Still processing...");
}); });
#if 0 #if 0
ecs.system<const WorldEditor::components::buildings_layout_graph, ecs.system<const WorldEditor::components::buildings_layout_graph,
@@ -1325,14 +856,14 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
}); });
#endif #endif
ecs.system("AssembleSkeletonStart") ecs.system("AssembleSkeletonStart")
.kind(GraphSolve) .kind(GraphAssembleSkeleton)
.run([module_name](flecs::iter &it) { .run([module_name](flecs::iter &it) {
print_line("Assembling skeleton..."); print_line("Assembling skeleton...");
}); });
ecs.system<const WorldEditor::components::buildings_layout_graph>( ecs.system<const WorldEditor::components::buildings_layout_graph>(
"AssembleSkeleton") "AssembleSkeleton")
.kind(GraphSolve) .kind(GraphAssembleSkeleton)
.read<WorldEditor::components::buildings_layout_order>() .read<WorldEditor::components::buildings_layout_order>()
.read<WorldEditor::components::buildings_layout_area>() .read<WorldEditor::components::buildings_layout_area>()
.read<WorldEditor::components::buildings_layout_commands>() .read<WorldEditor::components::buildings_layout_commands>()
@@ -1486,7 +1017,7 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
&area) { &area) {
int grid_size = (int)(Math::sqrt(area.area) * 1.5) + 1; int grid_size = (int)(Math::sqrt(area.area) * 1.5) + 1;
int growth_size = int growth_size =
(int)Math::ceil(area.area * 2.0f / 4.0f) + 1; (int)Math::ceil(area.area * 1.3f / 16.0f) + 1;
flecs::entity graph_e = it.entity(count); flecs::entity graph_e = it.entity(count);
List<flecs::entity> queue; List<flecs::entity> queue;
queue.push_back(graph_e); queue.push_back(graph_e);
@@ -1608,6 +1139,7 @@ BuildingLayoutGraph::graph_module::graph_module(flecs::world &ecs)
it.world().defer_resume(); it.world().defer_resume();
}); });
growth_module(ecs, module_name); growth_module(ecs, module_name);
room_growth_module(ecs, module_name);
#if 0 #if 0
ecs.system<WorldEditor::components::buildings_layout_grid_floor>( ecs.system<WorldEditor::components::buildings_layout_grid_floor>(
"AssignGridSizeToFloor") "AssignGridSizeToFloor")

View File

@@ -0,0 +1,28 @@
#ifndef GRAPH_MODULE_H_
#define GRAPH_MODULE_H_
struct growth_regions {
struct region {
flecs::entity_t seed_et;
flecs::entity_t region_et;
Rect2i rect;
int remains_area;
bool can_grow_square;
};
Vector<struct region> regions;
};
struct make_random {
int seed;
int next;
make_random(int seed)
: seed(seed)
, next(seed)
{
}
int get()
{
next = next * 1103515245 + 12345;
return (int)((unsigned)next >> 16) % 32768;
}
};
#endif

View File

@@ -0,0 +1,790 @@
#include "base_data.h"
#include "editor_event.h"
#include "world_editor.h"
#include "building_layout_graph.h"
#include "graph_module.h"
void BuildingLayoutGraph::graph_module::growth_module(flecs::world &ecs,
const String &module_name)
{
ecs.component<growth_regions>();
flecs::entity GraphFilter = ecs.entity("GraphFilter")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphFilter.disable();
struct grid_calc {
int grid_size;
int index2x(int index)
{
return index % grid_size;
}
int index2y(int index)
{
return index / grid_size;
}
void get_cadidates(int index, int *candidates)
{
int i, j, idx = 0;
int x = index2x(index);
int y = index2y(index);
for (i = -1; i < 2; i++) {
for (j = -1; j < 2; j++)
if (i != 0 || j != 0) {
int cx = x + i, cy = y + j;
if (cx >= 0 && cx < grid_size &&
cy >= 0 && cy < grid_size) {
int id = cx +
grid_size * cy;
candidates[idx++] = id;
}
}
}
}
grid_calc(flecs::entity layout_e)
: grid_size(
layout_e.get<WorldEditor::components::
buildings_layout_grid_size>()
->grid_size)
{
assert(layout_e.is_valid());
}
grid_calc(int grid_size)
: grid_size(grid_size)
{
assert(grid_size > 0);
}
};
struct grid_misc {
LocalVector<Pair<flecs::entity_t, Vector2i> > positions;
LocalVector<Vector2i> accepted;
struct make_random r;
grid_misc()
: r(100)
{
}
void get_dim_candidates(const Vector2i &base, int dim,
Vector2i *candidates)
{
int i;
std::vector<Vector2i> candidates_data = {
/* clang-format off */
{ base.x + dim, base.y },
{ base.x, base.y + dim },
{ base.x - dim, base.y },
{ base.x, base.y - dim },
{ base.x + dim, base.y },
{ base.x, base.y + dim },
{ base.x - dim, base.y },
{ base.x, base.y - dim },
/* clang-format on */
};
for (i = 0; i < (int)candidates_data.size(); i++)
candidates[i] = candidates_data[i];
}
void setup_floor(
flecs::entity grid_e, flecs::entity_t base_et,
const WorldEditor::components::buildings_layout_grid_size
&size,
BuildingLayoutGraph::graph_module *obj)
{
int i, j;
flecs::entity base_floor_e =
grid_e.world().entity(base_et);
flecs::log::warn("base_floor: %s",
base_floor_e.path().c_str());
int floor_index =
base_floor_e
.get<WorldEditor::components::
buildings_layout_floor_index>()
->index;
String floor_name = "floor_" + itos(floor_index);
flecs::entity floor_e =
grid_e.lookup(floor_name.ascii().ptr());
print_line("grid: " + String(grid_e.path()));
print_line("floor: " + floor_name);
assert(floor_e.is_valid());
assert(grid_e.is_valid());
obj->create_floor_components(floor_e, base_floor_e,
size);
flecs::log::warn("grid floor: %s",
floor_e.path().c_str());
for (i = 0; i < (int)positions.size(); i++)
for (j = 0; j < (int)positions.size(); j++) {
if (i == j)
continue;
if (positions[i].second ==
positions[j].second)
flecs::log::err(
"duplicate positions");
assert(positions[i].second !=
positions[j].second);
}
for (i = 0; i < (int)positions.size(); i++) {
int cell_id =
positions[i].second.x +
size.grid_size * positions[i].second.y;
flecs::entity region_e = grid_e.world().entity(
positions[i].first);
float area =
region_e.get<WorldEditor::components::
buildings_layout_area>()
->area;
assert(region_e.is_valid());
assert(floor_e.is_valid());
Rect2i check;
check.position = positions[i].second;
check.size = Vector2i(1, 1);
assert(obj->check_region(floor_e, -1, check));
flecs::entity cell_e = obj->create_cell(
floor_e, region_e, cell_id);
assert(cell_e.is_valid());
obj->create_region(floor_e, cell_e, region_e,
positions[i].second, area);
flecs::log::warn("grid cell: %s",
cell_e.path().c_str());
}
}
float get_entity_area(flecs::entity e) const
{
return e.get<WorldEditor::components::
buildings_layout_area>()
->area;
}
float get_entity_area(flecs::world &&ecs,
flecs::entity_t et) const
{
flecs::entity e = ecs.entity(et);
return e.get<WorldEditor::components::
buildings_layout_area>()
->area;
}
float get_entity_area(flecs::world &ecs,
flecs::entity_t et) const
{
flecs::entity e = ecs.entity(et);
return e.get<WorldEditor::components::
buildings_layout_area>()
->area;
}
int get_base_radius(flecs::world &&ecs,
flecs::entity_t et) const
{
float base_area = get_entity_area(ecs, et);
int base_radius =
(int)((Math::sqrt(base_area) * 1.6f) / 2.0f) /
4; /* grid conversion */
return base_radius;
}
int get_base_radius(flecs::world &ecs, flecs::entity_t et) const
{
float base_area = get_entity_area(ecs, et);
int base_radius =
(int)((Math::sqrt(base_area) * 1.6f) / 2.0f) /
4; /* grid conversion */
return base_radius;
}
int distance_squared(const Vector2i &p1,
const Vector2i &p2) const
{
int lx = p2.x - p1.x;
int ly = p2.y - p1.y;
return lx * lx + ly * ly;
}
bool check_candidates_tolerance(const Vector2i check)
{
int i;
bool ret = true;
for (i = 0; i < (int)positions.size(); i++)
if (distance_squared(check,
positions[i].second) < 1) {
ret = false;
break;
}
return ret;
}
bool check_candidate(const Vector2i &candidate)
{
int m;
bool bad = false;
for (m = 0; m < (int)positions.size(); m++) {
Rect2i check1, check2;
check1.position = positions[m].second;
check1.size = Vector2i(1, 1);
check2.position = candidate;
check2.size = Vector2i(1, 1);
if (check1.intersects(check2)) {
bad = true;
break;
}
}
return !bad;
}
bool accept_candidate(flecs::entity ce,
const Vector2i &candidate, float area)
{
int k;
int local_radius =
(int)((Math::sqrt(area) * 1.6f) / 2.0f) /
4; /* grid conversion */
local_radius = MAX(1, local_radius);
bool ok = false;
for (k = 0; k < (int)positions.size(); k++) {
assert(k < (int)positions.size());
flecs::entity_t pbase_et = positions[k].first;
float parea =
get_entity_area(ce.world(), pbase_et);
int pdim = (int)((Math::sqrt(parea) * 1.5f) /
2.0f) /
4; /* radius converted to grid 4x4*/
int radius = pdim + local_radius;
int radius_sq = radius * radius;
if (distance_squared(positions[k].second,
candidate) < radius_sq)
continue;
assert(check_candidates_tolerance(candidate));
accepted.push_back(candidate);
ok = true;
}
return ok;
}
bool process_candidates(
flecs::entity ce, const Vector2i &base, float area,
const WorldEditor::components::buildings_layout_grid_size
&size,
flecs::entity_t base_et, int dim)
{
int j;
int base_radius = get_base_radius(ce.world(), base_et);
base_radius = MAX(1, base_radius);
int local_radius =
(int)((Math::sqrt(area) * 1.6f) / 2.0f) /
4; /* grid conversion */
local_radius = MAX(1, local_radius);
// int dim = base_radius + local_radius;
// dim = MAX(4, dim);
int md = 1;
if (size.grid_size > 30)
md = 8;
else if (size.grid_size > 20)
md = 6;
else if (size.grid_size > 15)
md = 4;
else if (size.grid_size > 10)
md = 2;
Rect2i clip(md, md, size.grid_size - md * 2,
size.grid_size - md * 2);
Vector2i candidates[8];
get_dim_candidates(base, dim, &candidates[0]);
for (j = 0; j < (int)(sizeof(candidates) /
sizeof(candidates[0]));
j++) {
print_line("base: " + itos(base.x) + ", " +
itos(base.y));
print_line("possible candidate: " +
itos(candidates[j].x) + ", " +
itos(candidates[j].y));
if (!clip.has_point(candidates[j])) {
print_line("clipped by grid field");
print_line(clip.operator String());
continue;
}
if (!check_candidates_tolerance(
candidates[j])) {
print_line(
"too close to existing positions");
continue;
}
if (!check_candidate(candidates[j])) {
print_line(
"too close to existing positions (rect)");
continue;
}
print_line("valid candidate: " +
itos(candidates[j].x) + ", " +
itos(candidates[j].y));
accept_candidate(ce, candidates[j], area);
}
if (accepted.size() > 0)
return true;
else
return false;
}
void filter_candidates(
flecs::entity ce, float area,
const WorldEditor::components::buildings_layout_grid_size
&size)
{
if (positions.empty()) {
/* starting at grid center */
Vector2i start_pos(size.grid_size / 2,
size.grid_size / 2);
positions.push_back(
Pair<flecs::entity_t, Vector2i>(
ce.id(), start_pos));
return;
}
while (1) {
int which = which_position();
const Vector2i &base = positions[which].second;
flecs::entity_t base_et =
positions[which].first;
int base_radius =
get_base_radius(ce.world(), base_et);
base_radius = MAX(1, base_radius);
int local_radius =
(int)((Math::sqrt(area) * 1.6f) /
2.0f) /
4; /* grid conversion */
local_radius = MAX(1, local_radius);
int dim = base_radius + local_radius;
dim = MAX(1, dim);
process_candidates(ce, base, area, size,
base_et, dim);
if (accepted.size() == 0) {
assert(positions.size() > 0);
continue;
}
assert(accepted.size() > 0);
const Vector2i &selected =
accepted[which_selected()];
assert(check_candidates_tolerance(selected));
Pair<flecs::entity_t, Vector2i> m(ce.id(),
selected);
check_candidate(selected);
positions.push_back(m);
flecs::log::warn("add position: %d, %d",
selected.x, selected.y);
accepted.clear();
break;
}
}
int which_position()
{
int which;
if (positions.size() == 0)
return -1;
which = r.get() % positions.size();
assert(which < (int)positions.size());
return which;
}
int which_selected()
{
int which;
if (accepted.size() == 0)
return -1;
which = r.get() % accepted.size();
assert(which < (int)accepted.size());
return which;
}
};
ecs.system<const WorldEditor::components::buildings_layout_grid_size>(
"CreateGrid")
.kind(GraphSolve)
.write<WorldEditor::components::buildings_layout_grid>()
.each([this](flecs::iter &it, size_t count,
const WorldEditor::components::
buildings_layout_grid_size &size) {
struct grid_misc grid;
flecs::entity graph_e = it.entity(count);
graph_e.world().defer_suspend();
flecs::log::warn("creating grid for: %s",
graph_e.path().c_str());
flecs::entity grid_base_e = get_layout_grid_base();
flecs::entity grid_e =
grid_base_e.lookup(graph_e.name());
assert(grid_e.is_valid());
flecs::log::warn("creating grid for: %s: %s",
graph_e.path().c_str(),
grid_e.path().c_str());
/* starting at grid center */
const List<Pair<int, flecs::entity_t> >::Element *me =
size.floors.front();
while (me) {
flecs::query<const WorldEditor::components::
buildings_layout_area>
q = graph_e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_area>()
.with(flecs::ChildOf,
me->get().second)
.scope_open()
.with<WorldEditor::components::
buildings_layout_zone>()
.or_()
.with<WorldEditor::components::
buildings_layout_unit>()
.scope_close()
.build();
q.each([size,
&grid](flecs::entity ce,
const WorldEditor::components::
buildings_layout_area
&area) {
flecs::log::warn(
"generating positions for: %s",
ce.path().c_str());
grid.filter_candidates(ce, area.area,
size);
});
grid.setup_floor(grid_e, me->get().second, size,
this);
me = me->next();
}
graph_e.world().defer_resume();
});
ecs.system("AssembleSkeletonEnd")
.kind(GraphSolve)
.run([module_name](flecs::iter &it) {
print_line("Assembling skeleton done...");
it.world()
.lookup((module_name + "::GraphSolveZones")
.ascii()
.ptr())
.disable();
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.enable();
EditorEvent::get_singleton()->event.emit(
"update_layout_view", varray());
// assert(false);
});
ecs.system<WorldEditor::components::buildings_layout_grid_floor,
growth_regions>("GrowFloorRectRegions")
.kind(0)
.each([this](flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor
&fl,
growth_regions &g) {
int i;
bool grown = true;
int state = 0;
while (1) {
while (grown) {
grown = false;
for (i = 0; i < g.regions.size(); i++) {
Rect2i mrect =
g.regions[i].rect;
if (state == 0) {
if (!g.regions[i]
.can_grow_square)
continue;
if (g.regions[i]
.remains_area <=
0) {
g.regions
.write[i]
.can_grow_square =
false;
continue;
}
}
mrect = g.regions[i].rect;
int old_area = mrect.get_area();
if (state == 0) {
mrect = g.regions[i]
.rect;
assert(check_region(
floor_e, i,
mrect));
mrect = mrect.grow(1);
Rect2i clip(
0, 0,
fl.grid_size,
fl.grid_size);
if (!clip.encloses(
mrect))
continue;
bool ok = check_region(
floor_e, i,
mrect);
if (!ok)
continue;
int new_area =
mrect.get_area();
int area_diff =
new_area -
old_area;
if (area_diff > 0) {
g.regions
.write[i]
.rect =
mrect;
g.regions
.write[i]
.remains_area -=
area_diff;
grown = true;
}
} else if (state == 1) {
int d;
mrect = g.regions[i]
.rect;
if (g.regions[i]
.remains_area <=
0)
break;
bool ok = true;
for (d = 0; d < 4;
d++) {
mrect = g.regions[i]
.rect;
assert(check_region(
floor_e,
i,
mrect));
switch (d) {
case 0:
mrect.position
.y -=
1;
mrect.size
.y +=
1;
break;
case 1:
mrect.size
.y +=
1;
break;
case 2:
mrect.position
.x -=
1;
mrect.size
.x +=
1;
break;
case 3:
mrect.size
.x +=
1;
break;
}
Rect2i clip(
0, 0,
fl.grid_size,
fl.grid_size);
if (!clip.encloses(
mrect)) {
ok = false;
continue;
}
ok = check_region(
floor_e,
i,
mrect);
if (ok) {
int new_area =
mrect.get_area();
int area_diff =
new_area -
old_area;
if (area_diff >
0) {
g.regions
.write[i]
.rect =
mrect;
g.regions
.write[i]
.remains_area -=
area_diff;
grown = true;
}
}
}
}
}
}
state++;
grown = true;
if (state == 2)
break;
}
for (i = 0; i < g.regions.size(); i++) {
int x, y;
Rect2i rect = g.regions[i].rect;
for (x = rect.position.x;
x <= rect.position.x + rect.size.x; x++)
for (y = rect.position.y;
y <= rect.position.y + rect.size.y;
y++) {
int id = x + fl.grid_size * y;
if (!fl.cells.has(id)) {
flecs::entity seed_e =
floor_e.world().entity(
g.regions[i]
.seed_et);
assert(seed_e.is_valid());
queue_grow_cell(seed_e,
id);
}
}
}
});
ecs.system<WorldEditor::components::buildings_layout_grid_floor>(
"GrowFloorRegions")
.kind(0)
.each([this](flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor
&fl) {
/* TODO: limit growth per region too */
struct grid_calc grid(fl.grid_size);
if (fl.size_left <= 0)
return;
flecs::query<const WorldEditor::components::
buildings_layout_grid_cell>
q = floor_e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with(flecs::ChildOf, floor_e)
.without<WorldEditor::components::
final_cell>()
.build();
q.each([this, &floor_e, &fl,
&grid](flecs::entity et,
const WorldEditor::components::
buildings_layout_grid_cell &cell) {
int index = cell.index;
assert(et.is_valid());
int i;
LocalVector<int> candidates;
candidates.resize(8);
grid.get_cadidates(cell.index,
candidates.ptr());
int extended = 0;
for (i = 0; i < (int)candidates.size(); i++) {
if (have_cell(floor_e, candidates[i]))
continue;
queue_grow_cell(et, candidates[i]);
extended++;
}
if (extended == 0)
et.add<WorldEditor::components::
final_cell>();
print_line("size: " + itos(grid.grid_size) +
" index: " + itos(index));
});
});
ecs.system<const WorldEditor::components::buildings_layout_grid_cell>(
"GrowRegions")
.kind(0)
.without<WorldEditor::components::final_cell>()
.read<WorldEditor::components::buildings_layout_grid_size>()
.write<WorldEditor::components::buildings_layout_grid_cell>()
.write<WorldEditor::components::buildings_layout_grid_floor>()
.write<WorldEditor::components::buildings_layout_grid_queue>()
.each([this](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell &cell) {
e.world().defer_suspend();
int index = cell.index;
assert(e.is_valid());
flecs::entity floor_e = e.parent();
assert(floor_e.is_valid());
flecs::entity grid_e = floor_e.parent();
assert(grid_e.is_valid());
String layout_name(grid_e.name());
flecs::entity base_e = get_layout_base();
flecs::entity layout_e =
base_e.lookup(layout_name.ascii().ptr());
assert(layout_e.is_valid());
struct grid_calc grid(layout_e);
int i;
LocalVector<int> candidates;
candidates.resize(8);
grid.get_cadidates(cell.index, candidates.ptr());
int extended = 0;
for (i = 0; i < (int)candidates.size(); i++) {
if (have_cell(floor_e, candidates[i]))
continue;
queue_grow_cell(e, candidates[i]);
#if 0
String c_name = "cell_" + itos(candidates[i]);
flecs::entity c_e =
e.parent().lookup(c_name.ascii().ptr());
#endif
extended++;
}
if (extended == 0)
e.add<WorldEditor::components::final_cell>();
print_line("size: " + itos(grid.grid_size) +
" index: " + itos(index));
e.world().defer_resume();
});
ecs.system<WorldEditor::components::buildings_layout_grid_floor,
WorldEditor::components::buildings_layout_grid_queue>(
"GrowCommitQueue")
.kind(0)
.each([this](flecs::entity e,
WorldEditor::components::buildings_layout_grid_floor
&fl,
WorldEditor::components::buildings_layout_grid_queue
&queue) {
List<Pair<flecs::entity_t, int> >::Element *me =
queue.queue.front();
while (me) {
flecs::entity seed_e =
e.world().entity(me->get().first);
int id = me->get().second;
if (!fl.cells.has(id)) {
grow_cell(seed_e, id);
fl.cells.insert(id);
}
me = me->next();
}
queue.queue.clear();
e.remove<WorldEditor::components::
buildings_layout_grid_queue>();
});
ecs.system("RunGrow")
.kind(GraphFilter)
.run([module_name](flecs::iter &it) {
int i;
it.world().defer_suspend();
print_line("Running grow...");
for (i = 0; i < 100; i++) {
it.world()
.system(it.world().lookup(
(module_name +
"::GrowFloorRectRegions")
.ascii()
.ptr()))
.run();
it.world()
.system(it.world().lookup(
(module_name +
"::GrowCommitQueue")
.ascii()
.ptr()))
.run();
}
#if 0
it.world()
.system(it.world().lookup(
(module_name + "::GrowFloorRegions")
.ascii()
.ptr()))
.run();
it.world()
.system(it.world().lookup(
(module_name + "::GrowCommitQueue")
.ascii()
.ptr()))
.run();
#endif
it.world().defer_resume();
});
}

View File

@@ -0,0 +1,380 @@
#include "base_data.h"
#include "world_editor.h"
#include "building_layout_graph.h"
#include "graph_module.h"
void BuildingLayoutGraph::graph_module::room_growth_module(
flecs::world &ecs, const String &module_name)
{
flecs::entity GraphFilter = ecs.entity("GraphFilter");
assert(GraphFilter.is_valid());
flecs::entity GraphMarkData = ecs.entity("GraphMarkData")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphMarkData.disable();
flecs::entity GraphProcessRooms = ecs.entity("GraphProcessRooms")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphProcessRooms.disable();
ecs.system("CheckGrow").kind(GraphFilter).run([module_name](flecs::iter &it) {
flecs::query<const WorldEditor::components::
buildings_layout_grid_floor>
q = it.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_floor>()
.build();
int count_left = 0;
int count_run = 0;
q.each([&count_left,
&count_run](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_floor &fl) {
count_run++;
count_left += MAX(0, fl.size_left);
});
// assert(false);
if (count_run > 0 && count_left <= 0) {
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.disable();
print_line("Grow done");
it.world()
.lookup((module_name + "::GraphMarkData")
.ascii()
.ptr())
.enable();
print_line("Mark started...");
}
});
ecs.system<const WorldEditor::components::buildings_layout_grid_cell>(
"MarkExternalWall")
.kind(GraphMarkData)
.without<WorldEditor::components::outside_wall>()
.read<WorldEditor::components::buildings_layout_grid_floor>()
.write<WorldEditor::components::outside_wall>()
.write<WorldEditor::components::final_cell>()
.each([](flecs::entity e,
const WorldEditor::components::buildings_layout_grid_cell
&cell) {
int grid_size =
e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
int i;
Vector2i position(cell.index % grid_size,
cell.index / grid_size);
Vector2 west(position.x - 1, position.y);
Vector2 north(position.x, position.y - 1);
Vector2 east(position.x + 1, position.y);
Vector2 south(position.x, position.y + 1);
int west_id = west.x + grid_size * west.y;
int north_id = north.x + grid_size * north.y;
int east_id = east.x + grid_size * east.y;
int south_id = south.x + grid_size * south.y;
std::vector<int> neighbors = { west_id, north_id,
east_id, south_id };
bool outside = false;
bool border = false;
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
if (!e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->cells.has(id)) {
outside = true;
break;
}
}
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_name = "cell_" + itos(id);
flecs::entity neighbor_e = e.parent().lookup(
neighbor_name.ascii().ptr());
if (!neighbor_e.is_valid())
continue;
const WorldEditor::components::buildings_layout_grid_cell
*neighbor_cell = neighbor_e.get<
WorldEditor::components::
buildings_layout_grid_cell>();
if (cell.type != neighbor_cell->type) {
border = true;
break;
}
}
if (outside)
e.add<WorldEditor::components::outside_wall>();
else
e.add<WorldEditor::components::final_cell>();
if (border)
e.add<WorldEditor::components::border>();
print_line("outside: " + itos(outside));
print_line("position: " + (position.operator String()));
print_line("grid size: " + itos(grid_size));
print_line("tile index: " + itos(cell.index));
});
ecs.system("CheckMark")
.kind(GraphMarkData)
.run([module_name](flecs::iter &it) {
int tile_count = 0, inside_count = 0, wall_count = 0;
it.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.build()
.each([&tile_count, &inside_count, &wall_count](
flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
tile_count++;
if (e.has<WorldEditor::components::
outside_wall>())
wall_count++;
if (e.has<WorldEditor::components::
final_cell>())
inside_count++;
});
if (tile_count > 0 && wall_count > 0 &&
inside_count > 0 &&
tile_count == wall_count + inside_count) {
it.world()
.lookup((module_name +
"::GraphMarkData")
.ascii()
.ptr())
.disable();
it.world()
.lookup((module_name +
"::GraphProcessRooms")
.ascii()
.ptr())
.enable();
}
});
struct prio_queue {
HashMap<int, flecs::entity> entities;
Set<int> tile_selection[4];
Vector<int> tile_selection_array[4];
struct make_random r;
bool dirty;
prio_queue()
: r(make_random(100))
, dirty(true)
{
}
void add_tile(int prio, int id, flecs::entity ec)
{
if (!tile_selection[prio].has(id))
tile_selection[prio].insert(id);
if (!entities.has(id))
entities[id] = ec;
dirty = true;
}
void update()
{
int i, j;
for (i = 0; i < 4; i++) {
tile_selection_array[i].resize(
tile_selection[i].size());
j = 0;
Set<int>::Element *m =
tile_selection[i].front();
while (m) {
tile_selection_array[i].write[j++] =
m->get();
m = m->next();
}
}
}
void dump()
{
if (dirty) {
update();
dirty = false;
}
print_line("0: " +
itos(tile_selection_array[0].size()));
print_line("1: " +
itos(tile_selection_array[1].size()));
print_line("2: " +
itos(tile_selection_array[2].size()));
}
int get_random_tile(int prio)
{
assert(tile_selection[prio].size() > 0);
int sel = r.get() % tile_selection[prio].size();
int id = tile_selection_array[prio][sel];
assert(entities.has(id));
tile_selection_array[prio].erase(id);
tile_selection[prio].erase(id);
return id;
}
void delete_neighbors(int id)
{
int i, j;
flecs::entity selected_e = entities[id];
int grid_size =
selected_e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
Vector2i base(id % grid_size, id / grid_size);
for (i = -1; i < 2; i++)
for (j = -1; j < 2; j++) {
if (i == 0 && j == 0)
continue;
Vector2i neighbor =
base + Vector2i(i, j);
int neighbor_id =
neighbor.x +
grid_size * neighbor.y;
tile_selection_array[0].erase(
neighbor_id);
tile_selection[0].erase(neighbor_id);
if (!tile_selection[3].has(
neighbor_id)) {
tile_selection_array[3]
.push_back(neighbor_id);
tile_selection[3].insert(
neighbor_id);
}
}
}
int take_tile()
{
if (dirty) {
update();
dirty = false;
}
if (tile_selection[0].size() > 0) {
int id = get_random_tile(0);
delete_neighbors(id);
return id;
} else {
int prio;
flecs::log::warn(
"out of normal tiles, using outside wall and zone borders");
for (prio = 1; prio < 4; prio++) {
if (tile_selection[prio].size() > 0) {
int id = get_random_tile(prio);
return id;
}
}
}
flecs::log::err("failed to allocate room initial tile");
return -1;
}
flecs::entity get_entity(int id)
{
assert(entities.has(id));
return entities[id];
}
int get_total_size()
{
int ret = 0, i;
for (i = 0; i < 4; i++)
ret += tile_selection[i].size();
return ret;
}
};
ecs.system<const WorldEditor::components::buildings_layout_zone,
const WorldEditor::components::buildings_layout_floor_index>(
"ProcessFloor0Rooms")
.kind(GraphProcessRooms)
.read<WorldEditor::components::belongs>()
.read<WorldEditor::components::outside_wall>()
.read<WorldEditor::components::border>()
.each([](flecs::entity e,
const WorldEditor::components::buildings_layout_zone
&zone,
const WorldEditor::components::
buildings_layout_floor_index &idx) {
if (idx.index != 0)
return;
// make_random r(1001);
struct prio_queue prio;
e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with<WorldEditor::components::belongs>(e)
.without<WorldEditor::components::outside_wall>()
.without<WorldEditor::components::border>()
.build()
.each([&prio](flecs::entity ec,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
prio.add_tile(0, cell.index, ec);
});
e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with<WorldEditor::components::belongs>(e)
.without<WorldEditor::components::outside_wall>()
.with<WorldEditor::components::border>()
.build()
.each([&prio](flecs::entity ec,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
prio.add_tile(1, cell.index, ec);
});
e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with<WorldEditor::components::belongs>(e)
.with<WorldEditor::components::outside_wall>()
.build()
.each([&prio](flecs::entity ec,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
prio.add_tile(2, cell.index, ec);
});
prio.update();
prio.dump();
if (prio.get_total_size() == 0) {
flecs::log::err(
"no tiles allocated for zone: %s",
e.path().c_str());
return;
}
int count = 0, assigned_count = 0;
e.world()
.query_builder<const WorldEditor::components::
buildings_layout_room>()
.with(flecs::ChildOf, e)
.build()
.each([&prio, &count, &assigned_count](
flecs::entity ec,
const WorldEditor::components::
buildings_layout_room
&room) {
int id = prio.take_tile();
if (id >= 0) {
flecs::entity selected_e =
prio.get_entity(id);
selected_e.add<
WorldEditor::components::
belongs_room>(
ec);
assigned_count++;
}
count++;
});
if (assigned_count < count)
flecs::log::err(
"not all rooms were assigned: %d < %d",
assigned_count, count);
});
}

View File

@@ -120,6 +120,9 @@ public:
int growth_size; int growth_size;
}; };
struct belongs {}; struct belongs {};
struct border {};
struct belongs_room {};
struct outside_wall {};
struct buildings_layout_grid_floor { struct buildings_layout_grid_floor {
Set<int> cells; Set<int> cells;
int grid_size; int grid_size;