Skip to content

feat: async session api #273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7.3.0
7.4.1
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v4
- uses: greut/eclint-action@v0
- uses: jidicula/clang-format-action@v4.11.0
with: { clang-format-version: "18" }
with: { clang-format-version: "19" }

test-windows:
if: >-
Expand Down
109 changes: 90 additions & 19 deletions ecsact/runtime/async.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,28 @@ typedef enum {
ECSACT_ASYNC_ERR_CUSTOM_END = 200,
} ecsact_async_error;

typedef enum {
/**
* The session has stopped
*/
ECSACT_ASYNC_SESSION_STOPPED = 0,

/**
* The session is attempting to start but hasn't yet.
*/
ECSACT_ASYNC_SESSION_PENDING = 1,

/**
* The session has started
*/
ECSACT_ASYNC_SESSION_START = 2,
} ecsact_async_session_event;

/**
* When an error occurs due to an async request this callback is invoked.
*
* @param session_id the session that received the error
*
* @param async_err when there is no async error this will be @ref
* ECSACT_ASYNC_OK otherwise @see ecsact_async_error

Expand All @@ -89,6 +108,7 @@ typedef enum {
* ecsact_async_events_collector::error_callback_user_data
*/
typedef void (*ecsact_async_error_callback)( //
ecsact_async_session_id session_id,
ecsact_async_error async_err,
int request_ids_length,
ecsact_async_request_id* request_ids,
Expand All @@ -98,10 +118,12 @@ typedef void (*ecsact_async_error_callback)( //
/**
* When an occurs from the system execution this callback is invoked.
*
* @param session_id the session that received the error
* @param execute_err when there is no system execution error, this will be
* @ref ECSACT_EXEC_SYS_OK other @see ecsact_execute_systems_error
*/
typedef void (*ecsact_execute_sys_error_callback)( //
ecsact_async_session_id session_id,
ecsact_execute_systems_error execute_err,
void* callback_user_data
);
Expand All @@ -110,11 +132,21 @@ typedef void (*ecsact_execute_sys_error_callback)( //
* Handler for when a request is done (error or success)
*/
typedef void (*ecsact_async_request_done_callback)( //
ecsact_async_session_id session_id,
int request_ids_length,
ecsact_async_request_id* request_ids,
void* callback_user_data
);

/**
* Handler async session events
*/
typedef void (*ecsact_async_session_event_callback)( //
ecsact_async_session_id session_id,
ecsact_async_session_event event,
void* callback_user_data
);

typedef struct ecsact_async_events_collector {
/**
* invoked when an async request failed.
Expand Down Expand Up @@ -151,6 +183,16 @@ typedef struct ecsact_async_events_collector {
* `callback_user_data` passed to `async_request_done_callback`
*/
void* async_request_done_callback_user_data;

/**
* invoked when a session event has occurred. @see ecsact_async_session_event
*/
ecsact_async_session_event_callback async_session_event_callback;

/**
* `callback_user_data` passed to `async_session_event_callback`
*/
void* async_session_event_callback_user_data;
} ecsact_async_events_collector;

/**
Expand All @@ -166,6 +208,7 @@ ECSACT_ASYNC_API_FN(
ecsact_async_enqueue_execution_options
)
( //
ecsact_async_session_id session_id,
const ecsact_execution_options options
);

Expand All @@ -176,34 +219,59 @@ ECSACT_ASYNC_API_FN(
*/
ECSACT_ASYNC_API_FN(void, ecsact_async_flush_events)
( //
ecsact_async_session_id session_id,
const ecsact_execution_events_collector* execution_events,
const ecsact_async_events_collector* async_events
);

/**
* @param connection_string - null-terminated string used to connect to the
* underlying async runtime. This may be a hostname/ip address + port or
* some other string deinfed by the implementation. Please review
* documentation for your ecsact async api provider. May be NULL to
* indicate wanting to connect to the 'default' if available.
* @returns a request ID representing this async request. Later used in @ref
* ecsact_async_error_callback if an error occurs
* @param option_data implementation defined options used to start the async
* session. This usually contains information such as the host/ip, port, and
* authentication for a network connection or various settings that affect the
* simulation. It is recommended that all implementations handle `NULL` as the
* 'default' options. You should refer to the implementations documentation for
* what should be passed here.
*
* @param option_data_size length (in bytes) of @p option_data
*
* @returns an ID that represents the session that all other async functions
* take in
*/
ECSACT_ASYNC_API_FN(ecsact_async_session_id, ecsact_async_start)
( //
const void* option_data,
int32_t option_data_size
);

/**
* Begins stopping the session. May happen in background.
* @param session_id the session that should stop
*/
ECSACT_ASYNC_API_FN(ecsact_async_request_id, ecsact_async_connect)
ECSACT_ASYNC_API_FN(void, ecsact_async_stop)
( //
const char* connection_string
ecsact_async_session_id session_id
);

/**
* Starts a disconnect. May happen in background, but is guaranteed to
* disconnect before any new @ref ecsact_async_connect resolves.
* Begins stopping all active sessions. May happen in background.
*/
ECSACT_ASYNC_API_FN(void, ecsact_async_disconnect)(void);
ECSACT_ASYNC_API_FN(void, ecsact_async_stop_all)();

/**
* Stops all active sessions immediately making all session IDs invalid.
*
* NOTE: `ecsact_async_stop_all` is a more graceful option and should be
* preferred.
*/
ECSACT_ASYNC_API_FN(void, ecsact_async_force_reset)();

/**
* Gets the current tick
*/
ECSACT_ASYNC_API_FN(int32_t, ecsact_async_get_current_tick)(void);
ECSACT_ASYNC_API_FN(int32_t, ecsact_async_get_current_tick)
( //
ecsact_async_session_id session_id
);

/**
* Sends Ecsact stream data to the specified registry. Stream data will be
Expand All @@ -215,10 +283,11 @@ ECSACT_ASYNC_API_FN(int32_t, ecsact_async_get_current_tick)(void);
*/
ECSACT_ASYNC_API_FN(void, ecsact_async_stream)
( //
ecsact_entity_id entity,
ecsact_component_id component_id,
const void* component_data,
const void* indexed_field_values
ecsact_async_session_id session_id,
ecsact_entity_id entity,
ecsact_component_id component_id,
const void* component_data,
const void* indexed_field_values
);

#ifdef ECSACT_MSVC_TRADITIONAL
Expand All @@ -227,8 +296,10 @@ ECSACT_ASYNC_API_FN(void, ecsact_async_stream)
# define FOR_EACH_ECSACT_ASYNC_API_FN(fn, ...) \
fn(ecsact_async_enqueue_execution_options, __VA_ARGS__); \
fn(ecsact_async_flush_events, __VA_ARGS__); \
fn(ecsact_async_connect, __VA_ARGS__); \
fn(ecsact_async_disconnect, __VA_ARGS__); \
fn(ecsact_async_start, __VA_ARGS__); \
fn(ecsact_async_stop, __VA_ARGS__); \
fn(ecsact_async_stop_all, __VA_ARGS__); \
fn(ecsact_async_force_reset, __VA_ARGS__); \
fn(ecsact_async_get_current_tick, __VA_ARGS__); \
fn(ecsact_async_stream, __VA_ARGS__)
#endif
Expand Down
34 changes: 21 additions & 13 deletions ecsact/runtime/async.hh
Original file line number Diff line number Diff line change
Expand Up @@ -139,24 +139,32 @@ private:
}
};

[[nodiscard]] ECSACT_ALWAYS_INLINE auto connect(
const std::string& connection_string
) -> ecsact_async_request_id {
return ecsact_async_connect(connection_string.c_str());
[[nodiscard]] ECSACT_ALWAYS_INLINE auto start() -> ecsact_async_session_id {
return ecsact_async_start(0, nullptr);
}

[[nodiscard]] ECSACT_ALWAYS_INLINE auto start( //
int32_t size,
const void* data
) -> ecsact_async_session_id {
return ecsact_async_start(size, data);
}

ECSACT_ALWAYS_INLINE auto disconnect() -> void {
ecsact_async_disconnect();
ECSACT_ALWAYS_INLINE auto stop(ecsact_async_session_id id) -> void {
ecsact_async_stop(id);
}

[[nodiscard]] ECSACT_ALWAYS_INLINE auto get_current_tick() -> int32_t {
return ecsact_async_get_current_tick();
[[nodiscard]] ECSACT_ALWAYS_INLINE auto get_current_tick(
ecsact_async_session_id id
) -> int32_t {
return ecsact_async_get_current_tick(id);
}

[[nodiscard]] ECSACT_ALWAYS_INLINE auto enqueue_execution_options(
ecsact_async_session_id id,
ecsact::core::execution_options& options
) -> ecsact_async_request_id {
return ecsact_async_enqueue_execution_options(options.c());
return ecsact_async_enqueue_execution_options(id, options.c());
}

ECSACT_ALWAYS_INLINE auto flush_events() -> void {
Expand All @@ -165,8 +173,8 @@ ECSACT_ALWAYS_INLINE auto flush_events() -> void {

template<typename ExecutionEventsCollector>
requires(std::convertible_to<
decltype(std::declval<ExecutionEventsCollector>().c()),
const ecsact_execution_events_collector>)
decltype(std::declval<ExecutionEventsCollector>().c()),
const ecsact_execution_events_collector>)
ECSACT_ALWAYS_INLINE auto flush_events( //
ExecutionEventsCollector&& evc
) -> void {
Expand All @@ -176,8 +184,8 @@ ECSACT_ALWAYS_INLINE auto flush_events( //

template<typename AsyncEventsCollector>
requires(std::convertible_to<
decltype(std::declval<AsyncEventsCollector>().c()),
const ecsact_async_events_collector>)
decltype(std::declval<AsyncEventsCollector>().c()),
const ecsact_async_events_collector>)
ECSACT_ALWAYS_INLINE auto flush_events( //
AsyncEventsCollector&& async_evc
) -> void {
Expand Down
1 change: 1 addition & 0 deletions ecsact/runtime/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ ECSACT_TYPED_ID(ecsact_registry_id);
ECSACT_TYPED_ID(ecsact_entity_id);
ECSACT_TYPED_ID(ecsact_placeholder_entity_id);
ECSACT_TYPED_ID(ecsact_system_generates_id);
ECSACT_TYPED_ID(ecsact_async_session_id);
ECSACT_TYPED_ID(ecsact_async_request_id);

ECSACT_TYPED_ID(ecsact_decl_id);
Expand Down
3 changes: 1 addition & 2 deletions ecsact/runtime/serialize.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ namespace ecsact {
* @returns serialized action or component bytes
*/
template<typename T>
requires(!std::is_same_v<std::remove_cvref_t<T>, ecsact_component> &&
!std::is_same_v<std::remove_cvref_t<T>, ecsact_action>)
requires(!std::is_same_v<std::remove_cvref_t<T>, ecsact_component> && !std::is_same_v<std::remove_cvref_t<T>, ecsact_action>)
ECSACT_ALWAYS_INLINE auto serialize( //
const T& component_or_action
) -> std::vector<std::byte> {
Expand Down
1 change: 1 addition & 0 deletions test/.bazelversion
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7.4.1
Loading