From 678f62dd256bd5778eafbd5dbb731bdb679eadd4 Mon Sep 17 00:00:00 2001 From: Urban Wallasch Date: Sun, 28 Jul 2019 00:33:21 +0200 Subject: [PATCH] * Raised required telemetry API version to 1.01 for gameplay events support. * Added gameplay event handler to plugin. * Added job validity state to telemetry, derived from job termination events. * Some small improvements. --- dash.html | 6 +- telehttpd.c | 1 + telelogger.c | 4 +- telemetry.h | 1 + teleshmem.cpp | 268 +++++++++++++++++++++++++++----------------------- 5 files changed, 154 insertions(+), 126 deletions(-) diff --git a/dash.html b/dash.html index 0af7d3b..d404941 100644 --- a/dash.html +++ b/dash.html @@ -194,9 +194,9 @@ function loadDoc() { var tele = JSON.parse(this.responseText); speed.innerHTML = Math.round(tele.speed * 3.6); - if ( tele.nav_slimit > 0 && tele.speed > tele.nav_slimit * 1.075 ) + if ( tele.nav_slimit > 0 && Math.floor(tele.speed) > tele.nav_slimit * 1.075 ) warn( speed, 2 ); - else if ( tele.nav_slimit > 0 && tele.speed > tele.nav_slimit * 1.005 ) + else if ( tele.nav_slimit > 0 && Math.floor(tele.speed) > tele.nav_slimit * 1.005 ) warn( speed, 1 ); else warn( speed, 0 ); @@ -226,7 +226,7 @@ function loadDoc() { next_rest.innerHTML = m2hm(tele.next_rest); warn( next_rest, tele.next_rest < 1 ? 2 : tele.next_rest < 97 ? 1 : 0 ); - job_ttd.innerHTML = m2hm(tele.job_deltime - tele.game_time); + job_ttd.innerHTML = tele.job_isvalid ? m2hm(tele.job_deltime - tele.game_time) : "--:--"; if ( tele.nav_slimit > 0 ) { nav_slimit.innerHTML = Math.round(tele.nav_slimit * 3.6); diff --git a/telehttpd.c b/telehttpd.c index 69f9454..35d3b15 100644 --- a/telehttpd.c +++ b/telehttpd.c @@ -93,6 +93,7 @@ static void write_telejson( int fd ) { write(fd, buf, sprintf( buf, " \"nav_slimit\": %f,\n", telemetry->nav_slimit ) ); write(fd, buf, sprintf( buf, " \"next_rest\": %d,\n", telemetry->next_rest ) ); + write(fd, buf, sprintf( buf, " \"job_isvalid\": %d,\n", (int)telemetry->job_isvalid ) ); write(fd, buf, sprintf( buf, " \"job_deltime\": %u,\n", telemetry->job_deltime ) ); // add more here diff --git a/telelogger.c b/telelogger.c index b744572..3bb6620 100644 --- a/telelogger.c +++ b/telelogger.c @@ -72,7 +72,9 @@ static int log_console(void) { printf( "nav eta: %s\n", s2hms( telemetry->nav_eta ) ); printf( "nav limit: %.1f km/h\n", telemetry->nav_slimit * 3.6 ); printf( "next rest: %s\n", m2hm( telemetry->next_rest ) ); - printf( "time till delivery: %s\n", m2hm( telemetry->job_deltime - telemetry->game_time ) ); + + printf( "time till delivery: %s\n", + telemetry->job_isvalid ? m2hm( telemetry->job_deltime - telemetry->game_time ) : "--:--" ); puts(""); diff --git a/telemetry.h b/telemetry.h index ea6a12a..6e8613c 100644 --- a/telemetry.h +++ b/telemetry.h @@ -45,6 +45,7 @@ struct telemetry_state_t { float nav_slimit; // navigation speed limit in m/s int next_rest; // time to next rest stop in minutes + bool job_isvalid; // job info is current, i.e. job is in progress unsigned job_deltime; // job deadline in minutes (see game_time) }; diff --git a/teleshmem.cpp b/teleshmem.cpp index df1c0ff..d55a905 100644 --- a/teleshmem.cpp +++ b/teleshmem.cpp @@ -103,10 +103,103 @@ static void log_print(const char *const fmt, ...) fflush( logfp ); } } + +static void log_named_value( const scs_named_value_t *nv ) { + switch (nv->value.type) { + case SCS_VALUE_TYPE_INVALID: { + log_print("none\n"); + break; + } + case SCS_VALUE_TYPE_bool: { + log_print("bool = %s\n", nv->value.value_bool.value ? "true" : "false"); + break; + } + case SCS_VALUE_TYPE_s32: { + log_print("s32 = %d\n", static_cast(nv->value.value_s32.value)); + break; + } + case SCS_VALUE_TYPE_u32: { + log_print("u32 = %u\n", static_cast(nv->value.value_u32.value)); + break; + } + case SCS_VALUE_TYPE_u64: { + log_print("u64 = %" SCS_PF_U64 "\n", nv->value.value_u64.value); + break; + } + case SCS_VALUE_TYPE_float: { + log_print("float = %f\n", nv->value.value_float.value); + break; + } + case SCS_VALUE_TYPE_double: { + log_print("double = %f\n", nv->value.value_double.value); + break; + } + case SCS_VALUE_TYPE_fvector: { + log_print( + "fvector = (%f,%f,%f)\n", + nv->value.value_fvector.x, + nv->value.value_fvector.y, + nv->value.value_fvector.z + ); + break; + } + case SCS_VALUE_TYPE_dvector: { + log_print( + "dvector = (%f,%f,%f)\n", + nv->value.value_dvector.x, + nv->value.value_dvector.y, + nv->value.value_dvector.z + ); + break; + } + case SCS_VALUE_TYPE_euler: { + log_print( + "euler = h:%f p:%f r:%f\n", + nv->value.value_euler.heading * 360.0f, + nv->value.value_euler.pitch * 360.0f, + nv->value.value_euler.roll * 360.0f + ); + break; + } + case SCS_VALUE_TYPE_fplacement: { + log_print( + "fplacement = (%f,%f,%f) h:%f p:%f r:%f\n", + nv->value.value_fplacement.position.x, + nv->value.value_fplacement.position.y, + nv->value.value_fplacement.position.z, + nv->value.value_fplacement.orientation.heading * 360.0f, + nv->value.value_fplacement.orientation.pitch * 360.0f, + nv->value.value_fplacement.orientation.roll * 360.0f + ); + break; + } + case SCS_VALUE_TYPE_dplacement: { + log_print( + "dplacement = (%f,%f,%f) h:%f p:%f r:%f\n", + nv->value.value_dplacement.position.x, + nv->value.value_dplacement.position.y, + nv->value.value_dplacement.position.z, + nv->value.value_dplacement.orientation.heading * 360.0f, + nv->value.value_dplacement.orientation.pitch * 360.0f, + nv->value.value_dplacement.orientation.roll * 360.0f + ); + break; + } + case SCS_VALUE_TYPE_string: { + log_print("string = %s\n", nv->value.value_string.value); + break; + } + default: { + log_print("unknown\n"); + break; + } + } +} #else #define log_open() #define log_close() #define log_print(...) +#define log_named_value(...) #endif // def LOGGING @@ -156,122 +249,61 @@ SCSAPI_VOID telemetry_pause(const scs_event_t event, const void *const UNUSED(ev telemetry->paused = (event == SCS_TELEMETRY_EVENT_paused); } -SCSAPI_VOID telemetry_configuration(const scs_event_t event, const void *const event_info, const scs_context_t UNUSED(context)) +SCSAPI_VOID telemetry_gameplay(const scs_event_t event, const void *const event_info, const scs_context_t UNUSED(context)) { - // Here we just print the configuration info. + const struct scs_telemetry_gameplay_event_t *const info = static_cast(event_info); - const struct scs_telemetry_configuration_t *const info = static_cast(event_info); - log_print("Configuration: %s\n", info->id); + if ( 0 == strcmp( info->id, SCS_TELEMETRY_GAMEPLAY_EVENT_job_cancelled ) + || 0 == strcmp( info->id, SCS_TELEMETRY_GAMEPLAY_EVENT_job_delivered ) ) { + telemetry->job_isvalid = false; + } + // Log the gameplay event. + log_print("Gameplay: %s\n", info->id); for (const scs_named_value_t *current = info->attributes; current->name; ++current) { + log_print(" %s", current->name); + if (current->index != SCS_U32_NIL) { + log_print("[%u]", static_cast(current->index)); + } + log_print(" : "); + log_named_value( current ); + } +} - if ( 0 == strcmp( current->name, SCS_TELEMETRY_CONFIG_ATTRIBUTE_shifter_type ) ) { - // SCS_SHIFTER_TYPE_arcade - // SCS_SHIFTER_TYPE_automatic - // SCS_SHIFTER_TYPE_manual - // SCS_SHIFTER_TYPE_hshifter - telemetry->shifter = !strcmp( current->value.value_string.value, SCS_SHIFTER_TYPE_manual ) - || !strcmp( current->value.value_string.value, SCS_SHIFTER_TYPE_hshifter ); +SCSAPI_VOID telemetry_configuration(const scs_event_t event, const void *const event_info, const scs_context_t UNUSED(context)) +{ + const struct scs_telemetry_configuration_t *const info = static_cast(event_info); + + if ( 0 == strcmp( info->id, SCS_TELEMETRY_CONFIG_controls ) ) { + for (const scs_named_value_t *current = info->attributes; current->name; ++current) { + if ( 0 == strcmp( current->name, SCS_TELEMETRY_CONFIG_ATTRIBUTE_shifter_type ) ) { + // SCS_SHIFTER_TYPE_arcade + // SCS_SHIFTER_TYPE_automatic + // SCS_SHIFTER_TYPE_manual + // SCS_SHIFTER_TYPE_hshifter + telemetry->shifter = !strcmp( current->value.value_string.value, SCS_SHIFTER_TYPE_manual ) + || !strcmp( current->value.value_string.value, SCS_SHIFTER_TYPE_hshifter ); + } } - else if ( 0 == strcmp( current->name, SCS_TELEMETRY_CONFIG_ATTRIBUTE_delivery_time ) ) { - telemetry->job_deltime = current->value.value_u32.value; + } + else if ( 0 == strcmp( info->id, SCS_TELEMETRY_CONFIG_job ) ) { + for (const scs_named_value_t *current = info->attributes; current->name; ++current) { + if ( 0 == strcmp( current->name, SCS_TELEMETRY_CONFIG_ATTRIBUTE_delivery_time ) ) { + telemetry->job_deltime = current->value.value_u32.value; + telemetry->job_isvalid = true; + } } + } - // log configuration + // Log the configuration info. + log_print("Configuration: %s\n", info->id); + for (const scs_named_value_t *current = info->attributes; current->name; ++current) { log_print(" %s", current->name); if (current->index != SCS_U32_NIL) { log_print("[%u]", static_cast(current->index)); } log_print(" : "); - switch (current->value.type) { - case SCS_VALUE_TYPE_INVALID: { - log_print("none\n"); - break; - } - case SCS_VALUE_TYPE_bool: { - log_print("bool = %s\n", current->value.value_bool.value ? "true" : "false"); - break; - } - case SCS_VALUE_TYPE_s32: { - log_print("s32 = %d\n", static_cast(current->value.value_s32.value)); - break; - } - case SCS_VALUE_TYPE_u32: { - log_print("u32 = %u\n", static_cast(current->value.value_u32.value)); - break; - } - case SCS_VALUE_TYPE_u64: { - log_print("u64 = %" SCS_PF_U64 "\n", current->value.value_u64.value); - break; - } - case SCS_VALUE_TYPE_float: { - log_print("float = %f\n", current->value.value_float.value); - break; - } - case SCS_VALUE_TYPE_double: { - log_print("double = %f\n", current->value.value_double.value); - break; - } - case SCS_VALUE_TYPE_fvector: { - log_print( - "fvector = (%f,%f,%f)\n", - current->value.value_fvector.x, - current->value.value_fvector.y, - current->value.value_fvector.z - ); - break; - } - case SCS_VALUE_TYPE_dvector: { - log_print( - "dvector = (%f,%f,%f)\n", - current->value.value_dvector.x, - current->value.value_dvector.y, - current->value.value_dvector.z - ); - break; - } - case SCS_VALUE_TYPE_euler: { - log_print( - "euler = h:%f p:%f r:%f\n", - current->value.value_euler.heading * 360.0f, - current->value.value_euler.pitch * 360.0f, - current->value.value_euler.roll * 360.0f - ); - break; - } - case SCS_VALUE_TYPE_fplacement: { - log_print( - "fplacement = (%f,%f,%f) h:%f p:%f r:%f\n", - current->value.value_fplacement.position.x, - current->value.value_fplacement.position.y, - current->value.value_fplacement.position.z, - current->value.value_fplacement.orientation.heading * 360.0f, - current->value.value_fplacement.orientation.pitch * 360.0f, - current->value.value_fplacement.orientation.roll * 360.0f - ); - break; - } - case SCS_VALUE_TYPE_dplacement: { - log_print( - "dplacement = (%f,%f,%f) h:%f p:%f r:%f\n", - current->value.value_dplacement.position.x, - current->value.value_dplacement.position.y, - current->value.value_dplacement.position.z, - current->value.value_dplacement.orientation.heading * 360.0f, - current->value.value_dplacement.orientation.pitch * 360.0f, - current->value.value_dplacement.orientation.roll * 360.0f - ); - break; - } - case SCS_VALUE_TYPE_string: { - log_print("string = %s\n", current->value.value_string.value); - break; - } - default: { - log_print("unknown\n"); - break; - } - } + log_named_value( current ); } } @@ -366,7 +398,7 @@ SCSAPI_RESULT scs_telemetry_init(const scs_u32_t version, const scs_telemetry_in // We currently support only one version. - if (version != SCS_TELEMETRY_VERSION_1_00) { + if (version != SCS_TELEMETRY_VERSION_1_01) { return SCS_RESULT_unsupported; } @@ -389,7 +421,7 @@ SCSAPI_RESULT scs_telemetry_init(const scs_u32_t version, const scs_telemetry_in // Below the minimum version there might be some missing features (only minor change) or // incompatible values (major change). - const scs_u32_t MINIMAL_VERSION = SCS_TELEMETRY_EUT2_GAME_VERSION_1_00; + const scs_u32_t MINIMAL_VERSION = SCS_TELEMETRY_EUT2_GAME_VERSION_1_01; if (version_params->common.game_version < MINIMAL_VERSION) { log_print("WARNING: Too old version of the game, some features might behave incorrectly\n"); telemetry->game_ver_warn = true; @@ -408,7 +440,7 @@ SCSAPI_RESULT scs_telemetry_init(const scs_u32_t version, const scs_telemetry_in // Bellow the minimum version there might be some missing features (only minor change) or // incompatible values (major change). - const scs_u32_t MINIMAL_VERSION = SCS_TELEMETRY_ATS_GAME_VERSION_1_00; + const scs_u32_t MINIMAL_VERSION = SCS_TELEMETRY_ATS_GAME_VERSION_1_01; if (version_params->common.game_version < MINIMAL_VERSION) { log_print("WARNING: Too old version of the game, some features might behave incorrectly\n"); telemetry->game_ver_warn = true; @@ -430,27 +462,22 @@ SCSAPI_RESULT scs_telemetry_init(const scs_u32_t version, const scs_telemetry_in // Register for events. Note that failure to register those basic events // likely indicates invalid usage of the api or some critical problem. As the // example requires all of them, we can not continue if the registration fails. - const bool events_registered = - (version_params->register_for_event(SCS_TELEMETRY_EVENT_frame_start, telemetry_frame_start, NULL) == SCS_RESULT_ok) && - (version_params->register_for_event(SCS_TELEMETRY_EVENT_frame_end, telemetry_frame_end, NULL) == SCS_RESULT_ok) && - (version_params->register_for_event(SCS_TELEMETRY_EVENT_paused, telemetry_pause, NULL) == SCS_RESULT_ok) && - (version_params->register_for_event(SCS_TELEMETRY_EVENT_started, telemetry_pause, NULL) == SCS_RESULT_ok) - ; + (version_params->register_for_event(SCS_TELEMETRY_EVENT_frame_start, telemetry_frame_start, NULL) == SCS_RESULT_ok) + && (version_params->register_for_event(SCS_TELEMETRY_EVENT_frame_end, telemetry_frame_end, NULL) == SCS_RESULT_ok) + && (version_params->register_for_event(SCS_TELEMETRY_EVENT_paused, telemetry_pause, NULL) == SCS_RESULT_ok) + && (version_params->register_for_event(SCS_TELEMETRY_EVENT_started, telemetry_pause, NULL) == SCS_RESULT_ok) + && (version_params->register_for_event(SCS_TELEMETRY_EVENT_configuration, telemetry_configuration, NULL) == SCS_RESULT_ok) + && (version_params->register_for_event(SCS_TELEMETRY_EVENT_gameplay, telemetry_gameplay, NULL) == SCS_RESULT_ok ) + ; if (! events_registered) { - // Registrations created by unsuccessfull initialization are // cleared automatically so we can simply exit. - + log_print("FATAL: Unable to register event callbacks\n"); version_params->common.log(SCS_LOG_TYPE_error, "Unable to register event callbacks"); return SCS_RESULT_generic_error; } - // Register for the configuration info. As this example only prints the retrieved - // data, it can operate even if that fails. - - version_params->register_for_event(SCS_TELEMETRY_EVENT_configuration, telemetry_configuration, NULL); - // Register for channels. The channel might be missing if the game does not support // it (SCS_RESULT_not_found) or if does not support the requested type // (SCS_RESULT_unsupported_type). For purpose of this example we ignore the failues @@ -479,11 +506,8 @@ SCSAPI_RESULT scs_telemetry_init(const scs_u32_t version, const scs_telemetry_in version_params->register_for_channel(SCS_TELEMETRY_CHANNEL_next_rest_stop, SCS_U32_NIL, SCS_VALUE_TYPE_s32, SCS_TELEMETRY_CHANNEL_FLAG_none, telemetry_store_s32, &telemetry->next_rest); // Set the structure with defaults. - last_timestamp = static_cast(-1); - // Initially the game is paused. - telemetry->paused = true; return SCS_RESULT_ok; } -- 2.30.2