1#include <factory.h>
2#include <iostream>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29using namespace flecs;
30
31
32struct factories {
33
34 static constexpr int MaxInputs = 3;
35
36
37
38
39
40 struct Requirement {
42 int32_t amount;
43 };
44
45
46 struct Requires {
47 Requirement items[MaxInputs];
48 };
49
50
51 struct TimeToProduce {
52 float value;
53 };
54
55
56 struct StackCount {
57 int32_t amount;
58 };
59
60
61
62
63
64 struct Stores {
65 int32_t amount;
66 };
67
68
69 struct Factory {
70
72
73
75
76
78 };
79
80
81 enum class FactoryState {
82
83 Idle,
84
85
86 WaitingForResources,
87
88
89 Producing,
90
91
92 TransferResource
93 };
94
95
96 struct FactorySupply {
97 int32_t required[MaxInputs];
98 int32_t collected[MaxInputs];
99 flecs::ref<Stores> inputs[MaxInputs];
100 flecs::ref<Stores> output;
101 };
102
103
104 struct FactoryProduction {
105 float value;
106 float duration;
107 int32_t max_stack;
108 };
109
110
111 factories(world& world) {
112
113 world.
import<flecs::units>();
114
115
116
117
118
120 .member<int32_t>("amount");
121
123 .member(flecs::Entity, "resource")
124 .member<int32_t>("amount");
125
127 .array<Requirement>(3);
128
130 .member<int32_t>("required", 3)
131 .member<int32_t>("collected", 3);
132
134 .member<float, units::duration::Seconds>("value");
135
137 .member<int32_t>("amount");
138
140 .member<float, units::Percentage>("value")
141 .member<float, units::duration::Seconds>("duration")
142 .member<int32_t>("max_stack");
143
145
146 .on_add([](entity factory, Factory) {
147 factory.add(FactoryState::Idle);
148 })
149
150 .on_set(factory_init)
151 .member(flecs::Entity, "recipe")
152 .member(flecs::Entity, "inputs", 3)
153 .member(flecs::Entity, "output");
154
155
156 world.
system<FactorySupply>(
"Collect")
157 .with(FactoryState::WaitingForResources)
159 .each([](entity factory, FactorySupply& s) {
160 bool satisfied = true;
161
162 for (int i = 0; i < MaxInputs; i ++) {
163 int32_t needed = s.required[i] - s.collected[i];
164 if (needed) {
165 Stores* p = s.inputs[i].get();
166 if (p->amount >= needed) {
167 s.collected[i] += needed;
168 p->amount -= needed;
169 } else {
170 s.collected[i] += p->amount;
171 p->amount = 0;
172 satisfied = false;
173 }
174 }
175 }
176
177
178 if (satisfied) {
179
180 for (int i = 0; i < MaxInputs; i ++) {
181 s.collected[i] = 0;
182 }
183
184 factory.add(FactoryState::Producing);
185 }
186 });
187
188
189 world.
system<FactoryProduction>(
"Produce")
190 .with(FactoryState::Producing)
192 .each([](flecs::iter& it, size_t i, FactoryProduction& p) {
194 if (p.value >= 1) {
195 p.value = 1;
196 it.
entity(i).add(FactoryState::TransferResource);
197 }
198 });
199
200
201 world.
system<FactorySupply, FactoryProduction, Stores>(
"Transfer")
202 .term_at(2).
second(Wildcard)
203 .with(FactoryState::TransferResource)
204 .interval(1.0f)
205 .
each([](entity factory, FactorySupply& s, FactoryProduction& p, Stores& out) {
206
207 p.value = 0;
208
209
210 Stores *depot = s.output.try_get();
211 if (depot) {
212 int32_t available_space = p.max_stack - depot->amount;
213 if (out.amount > available_space) {
214 depot->amount += available_space;
215 out.amount -= available_space;
216 } else {
217 depot->amount += out.amount;
218 out.amount = 0;
219 }
220 }
221
222
223
224
225 Stores *store = &out;
226 if (depot) {
227 if (!p.max_stack || (depot->amount < p.max_stack)) {
228 store = depot;
229 }
230 }
231
232 if (store->amount < p.max_stack) {
233
234 store->amount ++;
235 factory.add(FactoryState::WaitingForResources);
236 } else {
237
238 }
239 });
240 }
241
242private:
243
244
245
246 static void factory_init(entity factory, Factory& config) {
247 world world = factory.
world();
249
250 recipe.get([&](const Requires& r) {
252 if (output) {
253 if (!output.has<Stores>(recipe)) {
254 std::cout << factory.
path() <<
": output doesn't provide resource "
255 << recipe.
path() <<
"\n";
256 return;
257 }
258 }
259
260
261 bool satisfied = true;
262 for (int i = 0; i < MaxInputs; i ++) {
265 if (!resource) {
266 if (input) {
267 std::cout << factory.
path() <<
268 ": input connected to empty input slot\n";
269 }
270 continue;
271 }
272
273 if (resource && !input) {
274 satisfied = false;
275 break;
276 }
277
278 if (!input.has<Stores>(resource)) {
279 std::cout << factory.
path() <<
": input doesn't provide resource "
280 << recipe.
path() <<
"\n";
281 satisfied = false;
282 break;
283 }
284 }
285
286
287
288 if (satisfied) {
289 factory.add(FactoryState::WaitingForResources);
290
291
292 factory.
insert([&](FactorySupply& s) {
293 for (int i = 0; i < MaxInputs; i ++) {
296 int32_t amount = r.items[i].amount;
297
298 s.required[i] = amount;
299 s.collected[i] = 0;
300
301 if (!resource) {
302 continue;
303 }
304
305
306
307
308 s.inputs[i] = input.get_ref<Stores>(resource);
309 }
310
311 if (output) {
312
313
314 s.output = output.get_ref<Stores>(recipe);
315 }
316 });
317
318
319 recipe.get([&](const TimeToProduce& ttp, const StackCount& sc) {
320 factory.set<FactoryProduction>({ 0, ttp.value, sc.amount });
321 });
322
323
324 factory.add<Stores>(recipe);
325 }
326 });
327 }
328};
329
330int main(int argc, char *argv[]) {
332
334
337
343}
FLECS_API int ecs_script_run_file(ecs_world_t *world, const char *filename)
Parse script file.
flecs::app_builder app()
Return an app builder.
flecs::entity import()
Import a module.
flecs::system system(flecs::entity e) const
Upcast an entity to a system.
void interval(ecs_ftime_t interval)
Set interval.
flecs::component< T > component(Args &&... args) const
Find or register a component.
flecs::entity entity(Args &&... args) const
Create an entity.
ecs_entity_t entity_t
Entity type.
int run()
Run the application.
app_builder & enable_rest(uint16_t port=0)
Enable the REST API.
app_builder & delta_time(ecs_ftime_t value)
Set the fixed delta time for each frame.
app_builder & target_fps(ecs_ftime_t value)
Set the target frames per second.
const Self & insert(const Func &func) const
Set 1..N components.
flecs::string path(const char *sep="::", const char *init_sep="::") const
Return the entity path.
void each(const Func &func) const
Iterate (component) IDs of an entity.
flecs::world world() const
Get the world.
flecs::entity second() const
Get second element from a pair.
ecs_ftime_t delta_system_time() const
Get the time elapsed since the last system invocation.
flecs::entity entity(size_t row) const
Obtain a mutable handle to the entity being iterated over.
flecs::entity entity(Args &&... args) const
Create an entity.