Skip to content

Commit ce1aea6

Browse files
committed
Changed tests, more fail safes and made entity creation asynchronous
1 parent c0012d6 commit ce1aea6

File tree

8 files changed

+296
-372
lines changed

8 files changed

+296
-372
lines changed

ecsact/runtime/async.h

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,13 @@ typedef enum {
5959
ECSACT_ASYNC_ERR_CONNECTION_CLOSED,
6060

6161
/**
62-
* ExecutionOptions failed to merge
62+
* ExecutionOptions failed to merge, and upon failure the connection is closed
6363
*/
6464
ECSACT_ASYNC_ERR_EXECUTION_MERGE_FAILURE,
6565
} ecsact_async_error;
6666

6767
/**
68-
* When an error occurs due to an async request this callback is invoked, only
69-
* either @p async_err or @p execute_err will have a non-ok value.
68+
* When an error occurs due to an async request this callback is invoked.
7069
*
7170
* @param async_err when there is no async error this will be @ref
7271
* ECSACT_ASYNC_OK otherwise @see ecsact_async_error
@@ -95,6 +94,22 @@ typedef void (*ecsact_execute_sys_error_callback)(
9594
void* callback_user_data
9695
);
9796

97+
/**
98+
* When an entity is sucessfully created this callback is
99+
* invoked.
100+
*
101+
* @param entity_id the entity id of the created entity
102+
* @param request_id the request ID returned by the create entity callback
103+
* @param callback_user_data the @ref
104+
* ecsact_async_events_collector::error_callback_user_data
105+
*/
106+
typedef void (*ecsact_async_create_entity_callback)(
107+
//
108+
ecsact_entity_id entity_id,
109+
ecsact_async_request_id request_id,
110+
void* callback_user_data
111+
);
112+
98113
typedef struct ecsact_async_events_collector {
99114
/**
100115
* invoked when an async request failed.
@@ -108,6 +123,19 @@ typedef struct ecsact_async_events_collector {
108123
*/
109124
void* async_error_callback_user_data;
110125

126+
/**
127+
* Invoked when a create entity request succeeds.
128+
* @see ecsact_async_create_entity_callback
129+
* @see ecsact_entity_id
130+
* @see ecsact_async_error
131+
*/
132+
ecsact_async_create_entity_callback async_entity_callback;
133+
134+
/**
135+
* `callback_user_data` passed to `error_callback`
136+
*/
137+
void* async_entity_error_callback_user_data;
138+
111139
/**
112140
* invoked when a system execution error occurred.
113141
* @see ecsact_execute_sys_error_callback
@@ -171,14 +199,14 @@ ECSACT_ASYNC_API_FN(void, ecsact_async_disconnect)(void);
171199
/**
172200
* Returns an entity
173201
*/
174-
ECSACT_ASYNC_API_FN(ecsact_entity_id, ecsact_async_create_entity)(void);
202+
ECSACT_ASYNC_API_FN(ecsact_async_request_id, ecsact_async_request_entity)(void);
175203

176204
#define FOR_EACH_ECSACT_ASYNC_API_FN(fn, ...) \
177205
fn(ecsact_async_enqueue_execution_options, __VA_ARGS__); \
178206
fn(ecsact_async_flush_events, __VA_ARGS__); \
179207
fn(ecsact_async_connect, __VA_ARGS__); \
180208
fn(ecsact_async_disconnect, __VA_ARGS__); \
181-
fn(ecsact_async_create_entity, __VA_ARGS__);
209+
fn(ecsact_async_request_entity, __VA_ARGS__);
182210

183211
#undef ECSACT_ASYNC_API
184212
#undef ECSACT_ASYNC_API_FN

reference/async_reference/BUILD.bazel

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,14 @@ exports_files([
1111

1212
cc_library(
1313
name = "async_reference",
14-
srcs = [
15-
"async_reference.cc",
16-
"util/util.cc",
17-
],
18-
hdrs = [
19-
"async_reference.hh",
20-
"util/util.hh",
21-
],
14+
srcs = ["async_reference.cc"],
15+
hdrs = ["async_reference.hh"],
2216
copts = copts,
2317
visibility = ["//visibility:public"],
2418
deps = [
2519
"//:async",
2620
"//:core",
21+
"//reference/async_reference/util",
2722
"//reference/async_reference/util:types",
2823
],
2924
)

reference/async_reference/async.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ void ecsact_async_flush_events(
2424
async::reference->flush_events(execution_events, async_events);
2525
}
2626

27-
ecsact_entity_id ecsact_async_create_entity() {
28-
return async::reference->create_entity();
27+
ecsact_async_request_id ecsact_async_request_entity() {
28+
return async::reference->create_entity_request();
2929
}
3030

3131
ecsact_async_request_id ecsact_async_enqueue_execution_options(

reference/async_reference/async_reference.cc

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,21 @@ ecsact_async_request_id async_reference::connect(const char* connection_string
3131
ecsact_async_request_id async_reference::enqueue_execution_options(
3232
const ecsact_execution_options& options
3333
) {
34+
if(is_connected == false) {
35+
// Need to return a request ID?
36+
}
37+
3438
if(async_error.error == ECSACT_ASYNC_OK) {
3539
std::unique_lock lk(execute_m, std::defer_lock);
3640

3741
auto cpp_options = util::c_to_cpp_execution_options(options);
3842
async_error.error = util::validate_options(cpp_options);
3943

4044
if(async_error.error != ECSACT_ASYNC_OK) {
45+
increment_request_id();
4146
async_error.request_id = request_id;
4247
disconnect();
43-
return increment_request_id();
48+
return convert_request_id(async_error.request_id);
4449
}
4550

4651
if(lk.try_lock()) {
@@ -53,16 +58,17 @@ ecsact_async_request_id async_reference::enqueue_execution_options(
5358
if(async_error.error == ECSACT_ASYNC_OK) {
5459
merge_tick_options(existing_options, cpp_options);
5560
} else {
61+
increment_request_id();
5662
async_error.request_id = request_id;
57-
return increment_request_id();
63+
return convert_request_id(async_error.request_id);
5864
}
5965
}
6066
} else {
6167
temp_tick_map.insert(std::pair(tick + 1, cpp_options));
6268
}
6369
return increment_request_id();
6470
} else {
65-
return static_cast<ecsact_async_request_id>(async_error.request_id);
71+
return convert_request_id(async_error.request_id);
6672
}
6773
}
6874

@@ -86,9 +92,8 @@ void async_reference::execute_systems() {
8692
collector.update_callback_user_data = nullptr;
8793
collector.remove_callback_user_data = nullptr;
8894

89-
// Make this a unique_ptr
9095
std::unique_ptr<ecsact_execution_options> options = nullptr;
91-
// Make another value type execution_options
96+
9297
if(cpp_options) {
9398
options = std::make_unique<ecsact_execution_options>(
9499
util::cpp_to_c_execution_options(*cpp_options, *registry_id)
@@ -98,19 +103,17 @@ void async_reference::execute_systems() {
98103
auto systems_error =
99104
ecsact_execute_systems(*registry_id, 1, options.get(), &collector);
100105

101-
if(systems_error == ECSACT_EXEC_SYS_ERR_ACTION_ENTITY_INVALID) {
102-
sys_error = systems_error;
103-
}
104-
105-
if(systems_error == ECSACT_EXEC_SYS_ERR_ACTION_ENTITY_CONSTRAINT_BROKEN) {
106+
if(systems_error != ECSACT_EXEC_SYS_OK) {
106107
sys_error = systems_error;
108+
disconnect();
109+
return;
107110
}
108111

109112
lk.lock();
110113
tick_map.erase(tick);
111114
tick++;
112-
lk.unlock();
113115

116+
// NOTE(Kelwan): NOT THREAD SAFE RIGHT NOW
114117
for(auto& [key, val] : temp_tick_map) {
115118
if(tick_map.contains(key)) {
116119
auto& tick_options = tick_map.at(key);
@@ -121,6 +124,21 @@ void async_reference::execute_systems() {
121124
tick_map.insert(std::pair(key, val));
122125
}
123126
}
127+
lk.unlock();
128+
129+
std::unique_lock entity_lk(entity_m);
130+
for(int i = 0; i < pending_entity_requests.size(); i++) {
131+
auto entity_request_id = pending_entity_requests[i];
132+
133+
auto entity = ecsact_create_entity(*registry_id);
134+
135+
types::notified_entities notified_entity{
136+
.request_id = entity_request_id,
137+
.entity_id = entity};
138+
139+
created_entities.insert(created_entities.end(), notified_entity);
140+
}
141+
pending_entity_requests.clear();
124142
}
125143
});
126144
}
@@ -208,17 +226,33 @@ void async_reference::flush_events(
208226
);
209227
}
210228
}
229+
211230
init_callbacks_info.clear();
212231
update_callbacks_info.clear();
213232
remove_callbacks_info.clear();
214233
lk.unlock();
215234

216-
// Only send callback if there's an error except for OK
235+
std::unique_lock entity_lk(entity_m);
236+
for(auto& created_entity : created_entities) {
237+
if(async_events->async_entity_callback != nullptr) {
238+
async_events->async_entity_callback(
239+
created_entity.entity_id,
240+
created_entity.request_id,
241+
async_events->async_entity_error_callback_user_data
242+
);
243+
}
244+
}
245+
created_entities.clear();
217246
}
218247

219-
// NOTE(Kelwan): Remember to make async, give callbacks and flush that shit
220-
ecsact_entity_id async_reference::create_entity() {
221-
return ecsact_create_entity(*registry_id);
248+
ecsact_async_request_id async_reference::create_entity_request() {
249+
increment_request_id();
250+
std::unique_lock lk(entity_m);
251+
pending_entity_requests.insert(
252+
pending_entity_requests.end(),
253+
get_request_id()
254+
);
255+
return get_request_id();
222256
}
223257

224258
void async_reference::init_callback(
@@ -319,3 +353,19 @@ void async_reference::merge_tick_options(
319353
);
320354
}
321355
}
356+
357+
ecsact_async_request_id async_reference::increment_request_id() {
358+
return static_cast<ecsact_async_request_id>(
359+
request_id.fetch_add(1, std::memory_order_relaxed)
360+
);
361+
}
362+
363+
ecsact_async_request_id async_reference::get_request_id() {
364+
return static_cast<ecsact_async_request_id>(
365+
request_id.fetch_add(0, std::memory_order_relaxed)
366+
);
367+
}
368+
369+
ecsact_async_request_id async_reference::convert_request_id(int32_t id) {
370+
return static_cast<ecsact_async_request_id>(id);
371+
}

reference/async_reference/async_reference.hh

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public:
2525
const ecsact_async_events_collector* async_events
2626
);
2727

28-
ecsact_entity_id create_entity();
28+
ecsact_async_request_id create_entity_request();
2929

3030
ecsact_async_request_id connect(const char* connection_string);
3131
void disconnect();
@@ -37,11 +37,27 @@ private:
3737
std::map<int32_t, types::cpp_execution_options> tick_map;
3838
std::map<int32_t, types::cpp_execution_options> temp_tick_map;
3939

40+
std::vector<ecsact_async_request_id> entity_requests;
41+
4042
ecsact_execute_systems_error sys_error = ECSACT_EXEC_SYS_OK;
4143
types::async_error async_error{.error = ECSACT_ASYNC_OK};
4244

45+
// This situation is slightly different
46+
// More than 1 of these can happen per tick (ex: 5 entities created on one
47+
// tick)
48+
// If they don't flush for a while, these entities should have already been
49+
// created while still being able to invoke the successful callbacks
50+
// So let's say 50 entities have been constructed, but the flush hasn't
51+
// occurred. They both need to be created, yet aware that the callback hasn't
52+
// been sent What's the best way to do this?
53+
54+
std::vector<ecsact_async_request_id> pending_entity_requests;
55+
// Do success callbacks for "created" entities
56+
std::vector<types::notified_entities> created_entities;
57+
4358
std::thread execution_thread;
4459
std::mutex execute_m;
60+
std::mutex entity_m;
4561
std::atomic_bool is_connected = false;
4662

4763
static std::vector<types::callback_info> init_callbacks_info;
@@ -77,9 +93,8 @@ private:
7793
types::cpp_execution_options& other_options
7894
);
7995

80-
ecsact_async_request_id increment_request_id() {
81-
return static_cast<ecsact_async_request_id>(
82-
request_id.fetch_add(1, std::memory_order_relaxed)
83-
);
84-
}
96+
ecsact_async_request_id increment_request_id();
97+
ecsact_async_request_id get_request_id();
98+
99+
ecsact_async_request_id convert_request_id(int32_t id);
85100
};

0 commit comments

Comments
 (0)