From 4754eca8b6c97ab57a3c1bec0a081a0783a536e6 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Fri, 13 Jan 2023 06:41:28 +0100 Subject: [PATCH] Implement scoring reader --- rfactor_plugin/InternalsPlugin.hpp | 118 ++++++++++++++--------------- src/additional_rfactor.rs | 8 +- src/lib.rs | 68 ++++++++++++++--- 3 files changed, 121 insertions(+), 73 deletions(-) diff --git a/rfactor_plugin/InternalsPlugin.hpp b/rfactor_plugin/InternalsPlugin.hpp index 1ca21da..3233d55 100644 --- a/rfactor_plugin/InternalsPlugin.hpp +++ b/rfactor_plugin/InternalsPlugin.hpp @@ -37,8 +37,8 @@ struct TelemVect3 void Set( const double a, const double b, const double c ) { x = a; y = b; z = c; } // Allowed to reference as [0], [1], or [2], instead of .x, .y, or .z, respectively - double &operator[]( long i ) { return( ( &x )[ i ] ); } - const double &operator[]( long i ) const { return( ( &x )[ i ] ); } + double &operator[]( int i ) { return( ( &x )[ i ] ); } + const double &operator[]( int i ) const { return( ( &x )[ i ] ); } }; @@ -140,8 +140,8 @@ struct TelemWheelV01 double mWear; // wear (0.0-1.0, fraction of maximum) ... this is not necessarily proportional with grip loss char mTerrainName[16]; // the material prefixes from the TDF file unsigned char mSurfaceType; // 0=dry, 1=wet, 2=grass, 3=dirt, 4=gravel, 5=rumblestrip, 6=special - bool mFlat; // whether tire is flat - bool mDetached; // whether wheel is detached + char mFlat; // whether tire is flat + char mDetached; // whether wheel is detached double mVerticalTireDeflection;// how much is tire deflected from its (speed-sensitive) radius double mWheelYLocation; // wheel's y location relative to vehicle y location @@ -274,15 +274,15 @@ struct TelemInfoV01 struct CameraControlInfoV01 { // Cameras - long mID; // slot ID to view - long mCameraType; // see GraphicsInfoV02 comments for values + int mID; // slot ID to view + int mCameraType; // see GraphicsInfoV02 comments for values // Replays (note that these are asynchronous) - bool mReplayActive; // This variable is an *input* filled with whether the replay is currently active (as opposed to realtime). - bool mReplayUnused; // + char mReplayActive; // This variable is an *input* filled with whether the replay is currently active (as opposed to realtime). + char mReplayUnused; // unsigned char mReplayCommand; // 0=do nothing, 1=begin, 2=end, 3=rewind, 4=fast backwards, 5=backwards, 6=slow backwards, 7=stop, 8=slow play, 9=play, 10=fast play, 11=fast forward - bool mReplaySetTime; // Whether to skip to the following replay time: + char mReplaySetTime; // Whether to skip to the following replay time: float mReplaySeconds; // The replay time in seconds to skip to (note: the current replay maximum ET is passed into this variable in case you need it) // @@ -303,7 +303,7 @@ struct MessageInfoV01 struct VehicleScoringInfoV01 { - long mID; // slot ID (note that it can be re-used in multiplayer after someone leaves) + int mID; // slot ID (note that it can be re-used in multiplayer after someone leaves) char mDriverName[32]; // driver name char mVehicleName[64]; // vehicle name short mTotalLaps; // laps completed @@ -325,18 +325,18 @@ struct VehicleScoringInfoV01 short mNumPitstops; // number of pitstops made short mNumPenalties; // number of outstanding penalties - bool mIsPlayer; // is this the player's vehicle + char mIsPlayer; // is this the player's vehicle signed char mControl; // who's in control: -1=nobody (shouldn't get this), 0=local player, 1=local AI, 2=remote, 3=replay (shouldn't get this) - bool mInPits; // between pit entrance and pit exit (not always accurate for remote vehicles) + char mInPits; // between pit entrance and pit exit (not always accurate for remote vehicles) unsigned char mPlace; // 1-based position char mVehicleClass[32]; // vehicle class // Dash Indicators double mTimeBehindNext; // time behind vehicle in next higher place - long mLapsBehindNext; // laps behind vehicle in next higher place + int mLapsBehindNext; // laps behind vehicle in next higher place double mTimeBehindLeader; // time behind leader - long mLapsBehindLeader; // laps behind leader + int mLapsBehindLeader; // laps behind leader double mLapStartET; // time this lap was started // Position and derivatives @@ -356,16 +356,16 @@ struct VehicleScoringInfoV01 unsigned char mServerScored; // whether this vehicle is being scored by server (could be off in qualifying or racing heats) unsigned char mIndividualPhase;// game phases (described below) plus 9=after formation, 10=under yellow, 11=under blue (not used) - long mQualification; // 1-based, can be -1 when invalid + int mQualification; // 1-based, can be -1 when invalid double mTimeIntoLap; // estimated time into lap double mEstimatedLapTime; // estimated laptime used for 'time behind' and 'time into lap' (note: this may changed based on vehicle and setup!?) char mPitGroup[24]; // pit group (same as team name unless pit is shared) unsigned char mFlag; // primary flag being shown to vehicle (currently only 0=green or 6=blue) - bool mUnderYellow; // whether this car has taken a full-course caution flag at the start/finish line + char mUnderYellow; // whether this car has taken a full-course caution flag at the start/finish line unsigned char mCountLapFlag; // 0 = do not count lap or time, 1 = count lap but not time, 2 = count lap and time - bool mInGarageStall; // appears to be within the correct garage stall + char mInGarageStall; // appears to be within the correct garage stall unsigned char mUpgradePack[16]; // Coded upgrades @@ -378,14 +378,14 @@ struct VehicleScoringInfoV01 struct ScoringInfoV01 { char mTrackName[64]; // current track name - long mSession; // current session (0=testday 1-4=practice 5-8=qual 9=warmup 10-13=race) + int mSession; // current session (0=testday 1-4=practice 5-8=qual 9=warmup 10-13=race) double mCurrentET; // current time double mEndET; // ending time - long mMaxLaps; // maximum laps + int mMaxLaps; // maximum laps double mLapDist; // distance around track char *mResultsStream; // results stream additions since last update (newline-delimited and NULL-terminated) - long mNumVehicles; // current number of vehicles + int mNumVehicles; // current number of vehicles // Game phases: // 0 Before session has begun @@ -414,7 +414,7 @@ struct ScoringInfoV01 signed char mSectorFlag[3]; // whether there are any local yellows at the moment in each sector (not sure if sector 0 is first or last, so test) unsigned char mStartLight; // start light frame (number depends on track) unsigned char mNumRedLights; // number of red lights in start sequence - bool mInRealtime; // in realtime as opposed to at the monitor + char mInRealtime; // in realtime as opposed to at the monitor char mPlayerName[32]; // player name (including possible multiplayer override) char mPlrFileName[64]; // may be encoded to be a legal filename @@ -441,7 +441,7 @@ struct CommentaryRequestInfoV01 double mInput1; // first value to pass in (if any) double mInput2; // first value to pass in (if any) double mInput3; // first value to pass in (if any) - bool mSkipChecks; // ignores commentary detail and random probability of event + char mSkipChecks; // ignores commentary detail and random probability of event // constructor (for noobs, this just helps make sure everything is initialized to something reasonable) CommentaryRequestInfoV01() { mName[0] = 0; mInput1 = 0.0; mInput2 = 0.0; mInput3 = 0.0; mSkipChecks = false; } @@ -508,7 +508,7 @@ struct CustomControlInfoV01 { // The name passed through CheckHWControl() will be the mUntranslatedName prepended with an underscore (e.g. "Track Map Toggle" -> "_Track Map Toggle") char mUntranslatedName[ 64 ]; // name of the control that will show up in UI (but translated if available) - long mRepeat; // 0=registers once per hit, 1=registers once, waits briefly, then starts repeating quickly, 2=registers as long as key is down + int mRepeat; // 0=registers once per hit, 1=registers once, waits briefly, then starts repeating quickly, 2=registers as int as key is down unsigned char mExpansion[ 64 ]; // future use }; @@ -530,10 +530,10 @@ struct WeatherControlInfoV01 double mAmbientTempK; // ambient temperature (Kelvin) double mWindMaxSpeed; // maximum speed of wind (ground speed, but it affects how fast the clouds move, too) - bool mApplyCloudinessInstantly; // preferably we roll the new clouds in, but you can instantly change them now - bool mUnused1; // - bool mUnused2; // - bool mUnused3; // + char mApplyCloudinessInstantly; // preferably we roll the new clouds in, but you can instantly change them now + char mUnused1; // + char mUnused2; // + char mUnused3; // unsigned char mExpansion[ 508 ]; // future use (humidity, pressure, air density, etc.) }; @@ -546,8 +546,8 @@ struct WeatherControlInfoV01 struct CustomVariableV01 { char mCaption[ 128 ]; // Name of variable. This will be used for storage. In the future, this may also be used in the UI (after attempting to translate). - long mNumSettings; // Number of available settings. The special value 0 should be used for types that have limitless possibilities, which will be treated as a string type. - long mCurrentSetting; // Current setting (also the default setting when returned in GetCustomVariable()). This is zero-based, so: ( 0 <= mCurrentSetting < mNumSettings ) + int mNumSettings; // Number of available settings. The special value 0 should be used for types that have limitless possibilities, which will be treated as a string type. + int mCurrentSetting; // Current setting (also the default setting when returned in GetCustomVariable()). This is zero-based, so: ( 0 <= mCurrentSetting < mNumSettings ) // future expansion unsigned char mExpansion[ 256 ]; @@ -561,22 +561,22 @@ struct CustomSettingV01 struct MultiSessionParticipantV01 { // input only - long mID; // slot ID (if loaded) or -1 (if currently disconnected) + int mID; // slot ID (if loaded) or -1 (if currently disconnected) char mDriverName[ 32 ]; // driver name char mVehicleName[ 64 ]; // vehicle name unsigned char mUpgradePack[ 16 ]; // coded upgrades float mBestPracticeTime; // best practice time - long mQualParticipantIndex; // once qualifying begins, this becomes valid and ranks participants according to practice time if possible + int mQualParticipantIndex; // once qualifying begins, this becomes valid and ranks participants according to practice time if possible float mQualificationTime[ 4 ]; // best qualification time in up to 4 qual sessions float mFinalRacePlace[ 4 ]; // final race place in up to 4 race sessions float mFinalRaceTime[ 4 ]; // final race time in up to 4 race sessions // input/output - bool mServerScored; // whether vehicle is allowed to participate in current session - long mGridPosition; // 1-based grid position for current race session (or upcoming race session if it is currently warmup), or -1 if currently disconnected -// long mPitIndex; -// long mGarageIndex; + char mServerScored; // whether vehicle is allowed to participate in current session + int mGridPosition; // 1-based grid position for current race session (or upcoming race session if it is currently warmup), or -1 if currently disconnected +// int mPitIndex; +// int mGarageIndex; // future expansion unsigned char mExpansion[ 128 ]; @@ -585,17 +585,17 @@ struct MultiSessionParticipantV01 struct MultiSessionRulesV01 { // input only - long mSession; // current session (0=testday 1-4=practice 5-8=qual 9=warmup 10-13=race) - long mSpecialSlotID; // slot ID of someone who just joined, or -2 requesting to update qual order, or -1 (default/general) + int mSession; // current session (0=testday 1-4=practice 5-8=qual 9=warmup 10-13=race) + int mSpecialSlotID; // slot ID of someone who just joined, or -2 requesting to update qual order, or -1 (default/general) char mTrackType[ 32 ]; // track type from GDB - long mNumParticipants; // number of participants (vehicles) + int mNumParticipants; // number of participants (vehicles) // input/output MultiSessionParticipantV01 *mParticipant; // array of partipants (vehicles) - long mNumQualSessions; // number of qualifying sessions configured - long mNumRaceSessions; // number of race sessions configured - long mMaxLaps; // maximum laps allowed in current session (LONG_MAX = unlimited) (note: cannot currently edit in *race* sessions) - long mMaxSeconds; // maximum time allowed in current session (LONG_MAX = unlimited) (note: cannot currently edit in *race* sessions) + int mNumQualSessions; // number of qualifying sessions configured + int mNumRaceSessions; // number of race sessions configured + int mMaxLaps; // maximum laps allowed in current session (LONG_MAX = unlimited) (note: cannot currently edit in *race* sessions) + int mMaxSeconds; // maximum time allowed in current session (LONG_MAX = unlimited) (note: cannot currently edit in *race* sessions) char mName[ 32 ]; // untranslated name override for session (please use mixed case here, it should get uppercased if necessary) // future expansion @@ -622,7 +622,7 @@ struct TrackRulesActionV01 { // input only TrackRulesCommandV01 mCommand; // recommended action - long mID; // slot ID if applicable + int mID; // slot ID if applicable double mET; // elapsed time that event occurred, if applicable }; @@ -646,18 +646,18 @@ enum TrackRulesColumnV01 struct TrackRulesParticipantV01 { // input only - long mID; // slot ID + int mID; // slot ID short mFrozenOrder; // 0-based place when caution came out (not valid for formation laps) short mPlace; // 1-based place (typically used for the initialization of the formation lap track order) float mYellowSeverity; // a rating of how much this vehicle is contributing to a yellow flag (the sum of all vehicles is compared to TrackRulesV01::mSafetyCarThreshold) double mCurrentRelativeDistance; // equal to ( ( ScoringInfoV01::mLapDist * this->mRelativeLaps ) + VehicleScoringInfoV01::mLapDist ) // input/output - long mRelativeLaps; // current formation/caution laps relative to safety car (should generally be zero except when safety car crosses s/f line); this can be decremented to implement 'wave around' or 'beneficiary rule' (a.k.a. 'lucky dog' or 'free pass') + int mRelativeLaps; // current formation/caution laps relative to safety car (should generally be zero except when safety car crosses s/f line); this can be decremented to implement 'wave around' or 'beneficiary rule' (a.k.a. 'lucky dog' or 'free pass') TrackRulesColumnV01 mColumnAssignment;// which column (line/lane) that participant is supposed to be in - long mPositionAssignment; // 0-based position within column (line/lane) that participant is supposed to be located at (-1 is invalid) - bool mAllowedToPit; // whether the rules allow this particular vehicle to enter pits right now - bool mUnused[ 3 ]; // + int mPositionAssignment; // 0-based position within column (line/lane) that participant is supposed to be located at (-1 is invalid) + char mAllowedToPit; // whether the rules allow this particular vehicle to enter pits right now + char mUnused[ 3 ]; // double mGoalRelativeDistance; // calculated based on where the leader is, and adjusted by the desired column spacing and the column/position assignments char mMessage[ 96 ]; // a message for this participant to explain what is going on (untranslated; it will get run through translator on client machines) @@ -682,16 +682,16 @@ struct TrackRulesV01 double mCurrentET; // current time TrackRulesStageV01 mStage; // current stage TrackRulesColumnV01 mPoleColumn; // column assignment where pole position seems to be located - long mNumActions; // number of recent actions + int mNumActions; // number of recent actions TrackRulesActionV01 *mAction; // array of recent actions - long mNumParticipants; // number of participants (vehicles) + int mNumParticipants; // number of participants (vehicles) - bool mYellowFlagDetected; // whether yellow flag was requested or sum of participant mYellowSeverity's exceeds mSafetyCarThreshold - bool mYellowFlagLapsWasOverridden; // whether mYellowFlagLaps (below) is an admin request + char mYellowFlagDetected; // whether yellow flag was requested or sum of participant mYellowSeverity's exceeds mSafetyCarThreshold + char mYellowFlagLapsWasOverridden; // whether mYellowFlagLaps (below) is an admin request - bool mSafetyCarExists; // whether safety car even exists - bool mSafetyCarActive; // whether safety car is active - long mSafetyCarLaps; // number of laps + char mSafetyCarExists; // whether safety car even exists + char mSafetyCarActive; // whether safety car is active + int mSafetyCarLaps; // number of laps float mSafetyCarThreshold; // the threshold at which a safety car is called out (compared to the sum of TrackRulesParticipantV01::mYellowSeverity for each vehicle) double mSafetyCarLapDist; // safety car lap distance float mSafetyCarLapDistAtStart; // where the safety car starts from @@ -706,7 +706,7 @@ struct TrackRulesV01 signed char mYellowFlagState; // see ScoringInfoV01 for values short mYellowFlagLaps; // suggested number of laps to run under yellow (may be passed in with admin command) - long mSafetyCarInstruction; // 0=no change, 1=go active, 2=head for pits + int mSafetyCarInstruction; // 0=no change, 1=go active, 2=head for pits float mSafetyCarSpeed; // maximum speed at which to drive float mSafetyCarMinimumSpacing; // minimum spacing behind safety car (-1 to indicate no limit) float mSafetyCarMaximumSpacing; // maximum spacing behind safety car (-1 to indicate no limit) @@ -727,12 +727,12 @@ struct TrackRulesV01 struct PitMenuV01 { - long mCategoryIndex; // index of the current category + int mCategoryIndex; // index of the current category char mCategoryName[ 32 ]; // name of the current category (untranslated) - long mChoiceIndex; // index of the current choice (within the current category) + int mChoiceIndex; // index of the current choice (within the current category) char mChoiceString[ 32 ]; // name of the current choice (may have some translated words) - long mNumChoices; // total number of choices (0 <= mChoiceIndex < mNumChoices) + int mNumChoices; // total number of choices (0 <= mChoiceIndex < mNumChoices) unsigned char mExpansion[ 256 ]; // for future use }; diff --git a/src/additional_rfactor.rs b/src/additional_rfactor.rs index 8a52b1f..84cb9d1 100644 --- a/src/additional_rfactor.rs +++ b/src/additional_rfactor.rs @@ -53,6 +53,10 @@ pub struct rF2Scoring { impl rF2Scoring { pub const SIZE: usize = mem::size_of::(); + + pub fn vehicles(&self) -> &[VehicleScoringInfoV01] { + &self.vehicles[0..self.scoring_info.mNumVehicles as usize] + } } impl From<&[u8]> for rF2Scoring { @@ -194,7 +198,7 @@ pub struct rF2Wheel { pub pressure: f64, pub temperature: [f64; 3], pub wear: f64, - pub terrain_name: [u8; 16usize], + pub terrain_name: [u8; 16], pub surface_type: u8, pub flat: u8, pub detached: u8, @@ -207,5 +211,5 @@ pub struct rF2Wheel { pub tire_carcass_temperature: f64, pub tire_inner_layer_temperature: [f64; 3], - expansion: [::std::os::raw::c_uchar; 24usize], + expansion: [::std::os::raw::c_uchar; 24], } diff --git a/src/lib.rs b/src/lib.rs index 4c98333..87ca947 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,34 +2,78 @@ pub mod additional_rfactor; #[allow(warnings)] mod rfactor_structs; -use std::{fs::File, path::Path}; +use std::{fs::File, marker::PhantomData, path::Path}; use additional_rfactor::*; +pub use additional_rfactor::{rF2Vec3, rF2VehicleTelemetry, rF2Wheel}; use anyhow::Result; use memmap2::Mmap; +pub use rfactor_structs::{ScoringInfoV01, VehicleScoringInfoV01}; const RFACTOR_SHM_FILE: &str = "/dev/shm"; -pub struct TelemetryReader { - _telemetry_file: File, +struct ShMReader { + _file: File, shm: Mmap, + + data: PhantomData, +} + +impl ShMReader { + const SIZE: usize = std::mem::size_of::(); + + fn new(mm_file_name: &str) -> Result { + let file = File::open(Path::new(RFACTOR_SHM_FILE).join(mm_file_name))?; + let mmap = unsafe { Mmap::map(&file)? }; + + Ok(Self { + _file: file, + shm: mmap, + + data: PhantomData, + }) + } +} + +impl<'a, T> ShMReader +where + T: From<&'a [u8]>, +{ + fn read(&'a self) -> T { + T::from(&self.shm[0..Self::SIZE]) + } +} + +pub struct TelemetryReader { + mm_reader: ShMReader, } impl TelemetryReader { pub fn new() -> Result { - let file = File::open(Path::new(RFACTOR_SHM_FILE).join(MM_TELEMETRY_FILE_NAME))?; - let mmap = unsafe { Mmap::map(&file)? }; - Ok(Self { - _telemetry_file: file, - shm: mmap, + mm_reader: ShMReader::new(MM_TELEMETRY_FILE_NAME)?, }) } pub fn query_telemetry(&self) -> Vec { - let telemetry = rF2Telemetry::from(&self.shm[0..rF2Telemetry::SIZE]); - let vehicles = telemetry.vehicles(); - - vehicles.to_vec() + self.mm_reader.read().vehicles().to_vec() + } +} + +pub struct ScoringReader { + mm_reader: ShMReader, +} + +impl ScoringReader { + pub fn new() -> Result { + Ok(Self { + mm_reader: ShMReader::new(MM_SCORING_FILE_NAME)?, + }) + } + + pub fn vehicle_scoring(&self) -> (ScoringInfoV01, Vec) { + let scoring = self.mm_reader.read(); + + (scoring.scoring_info, scoring.vehicles().to_vec()) } }