* Raised required telemetry API version to 1.01 for gameplay events support.
authorUrban Wallasch <urban.wallasch@freenet.de>
Sat, 27 Jul 2019 22:33:21 +0000 (00:33 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Sat, 27 Jul 2019 22:33:21 +0000 (00:33 +0200)
* Added gameplay event handler to plugin.
* Added job validity state to telemetry, derived from job termination events.
* Some small improvements.

dash.html
telehttpd.c
telelogger.c
telemetry.h
teleshmem.cpp

index 0af7d3b7d9d71c8ca235382aac9d09d1a897347b..d4049417fa04caa860ed34bbbd7767f6791e4baf 100644 (file)
--- 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);
index 69f9454d8d407a2ff8d9eae750efa4c18464056f..35d3b1591aad9cc6d3367bdbb4e308a7dc62a175 100644 (file)
@@ -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
index b74457248bad5e20df2e1421d78286ec268e3269..3bb66208fa2a5b39129eed0b4b1f19130d7f002b 100644 (file)
@@ -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("");
 
index ea6a12abc84b7b7208ef90067869d169b45d7ab4..6e8613c0fea16488954085b4b3118ab389fdf98b 100644 (file)
@@ -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)
 };
 
index df1c0ff430f98a2d84ef60a9ff48d18787bd70d2..d55a905e08bb9512045eec9a882f16191b97e2d2 100644 (file)
@@ -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<int>(nv->value.value_s32.value));
+            break;
+        }
+        case SCS_VALUE_TYPE_u32: {
+            log_print("u32 = %u\n", static_cast<unsigned>(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<const scs_telemetry_gameplay_event_t *>(event_info);
 
-    const struct scs_telemetry_configuration_t *const info = static_cast<const scs_telemetry_configuration_t *>(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<unsigned>(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<const scs_telemetry_configuration_t *>(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<unsigned>(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<int>(current->value.value_s32.value));
-                break;
-            }
-            case SCS_VALUE_TYPE_u32: {
-                log_print("u32 = %u\n", static_cast<unsigned>(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<scs_timestamp_t>(-1);
-
     // Initially the game is paused.
-
     telemetry->paused = true;
     return SCS_RESULT_ok;
 }