모종의 음모/force feedback
forza horizon 4 telemetry 수정
구차니
2024. 12. 7. 22:58
빌드하려고 vs2022 부터 다시 깔고 쑈하긴 했는데
아무튼 기어가 올라오긴 한다.
서버는 자기 자신의 아이피를 넣고(0.0.0.0을 넣으면 되려나?) 포트를 게임에서 설정한대로 하면 끝
이 녀석의 구조체를 뜯어 봐야 겠구만?
[링크 : https://github.com/geeooff/forza-data-web]
다시 원점으로 돌아가서 하나하나 길이 맞추면서 보니까 먼가 12바이트가 추가되어 있었다.
01 00 00 00 // S32 IsRaceOn; 87 65 A8 14 // U32 TimestampMS; FB 6F 14 46 // F32 EngineMaxRpm; F8 FF 47 44 // F32 EngineIdleRpm; D9 18 0A 45 // F32 CurrentEngineRpm; C0 FC 1B BD // F32 AccelerationX; 90 AB 60 3D 6C 00 D9 40 88 EA A9 BD // F32 VelocityX; E8 EF 9D BC 83 62 9B 40 5D F5 9C 3B // F32 AngularVelocityX; 16 7C 65 BC E9 09 D0 BC 7E D0 B0 BF // F32 Yaw; F2 E8 B1 BE AA F7 69 3E FA 31 DB 3E // F32 NormalizedSuspensionTravelFrontLeft CE 72 B3 3E A4 DD F8 3E 3F 6E 03 3F FB 1B 71 3F // F32 TireSlipRatioFrontLeft 07 85 59 3F A2 BE 10 3F 4F 86 29 3F 39 74 A3 41 // F32 WheelRotationSpeedFrontLeft CC 09 8C 41 BC CC 81 41 C2 F8 85 41 00 00 00 00 // S32 WheelOnRumbleStripFrontLeft 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // F32 WheelInPuddleDepthFrontLeft 00 00 00 00 00 00 00 00 00 00 00 00 99 99 19 3F // F32 SurfaceRumbleFrontLeft 99 99 19 3F 99 99 19 3F 99 99 19 3F 34 3F DD 3D // F32 TireSlipAngleFrontLeft 34 C6 E3 3D 0F 9A 97 3D 35 FA 99 3D B2 B0 72 3F // F32 TireCombinedSlipFrontLeft 06 60 5B 3F DA FA 11 3F 20 9D 2A 3F 1E A2 B0 BB // F32 SuspensionTravelMetersFrontLeft 5C 44 3D BC 00 E9 9A 3A 80 C3 54 3B 89 0D 00 00 // S32 CarOrdinal 04 00 00 00 // S32 CarClass 84 03 00 00 // S32 CarPerformanceIndex 02 00 00 00 // S32 DrivetrainType - // 0 = FWD, 1 = RWD, 2 = AWD 0C 00 00 00 // S32 NumCylinders 0D 00 00 00 // ?? 00 00 00 00 // ?? 00 00 00 00 // ?? EC C6 18 C4 // F32 PositionX; 33 08 20 43 // F32 PositionY; 40 A0 1C C5 // F32 PositionZ; A1 68 9B 40 // F32 Speed; F4 5F 03 48 // F32 Power; 23 DF 11 44 // F32 Torque; 20 4C 9C 42 // F32 TireTempFrontLeft; 0D 43 9D 42 // F32 TireTempFrontRight; 9B FD A9 42 // F32 TireTempRearLeft; 9B FD A9 42 // F32 TireTempRearRight; 00 00 00 00 // F32 Boost; 00 00 80 3F // F32 Fuel; 00 00 00 00 // F32 DistanceTraveled; 00 00 00 00 // F32 BestLap; 00 00 00 00 // F32 LastLap; 00 00 00 00 // F32 CurrentLap; C8 AF FB 43 // F32 CurrentRaceTime; 00 00 // U16 LapNumber; 00 // U8 RacePosition; FF // U8 Accel; 00 // U8 Brake; 00 // U8 Clutch; 00 // U8 HandBrake; 01 // U8 Gear; 00 // S8 Steer; 00 // S8 NormalizedDrivingLine; 00 // S8 NormalizedAIBrakeDifference; 00 // ??? |
sled 구조체에서 Steer 이후에 24bit는 원래의 구조체와는 다른 것 같네
아무튼 아래와 같이 값들이 정상적으로 출력되는 것 확인!
소스코드
더보기
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ncurses.h>
#define BUF_SIZE 500
typedef char S8;
typedef unsigned char U8;
typedef unsigned short U16;
typedef int S32;
typedef unsigned int U32;
typedef float F32;
typedef struct _sled_
{
// = 1 when race is on. = 0 when in menus/race stopped …
S32 IsRaceOn;
// Can overflow to 0 eventually
U32 TimestampMS;
F32 EngineMaxRpm;
F32 EngineIdleRpm;
F32 CurrentEngineRpm;
// In the car's local space; X = right, Y = up, Z = forward
F32 AccelerationX;
F32 AccelerationY;
F32 AccelerationZ;
// In the car's local space; X = right, Y = up, Z = forward
F32 VelocityX;
F32 VelocityY;
F32 VelocityZ;
// In the car's local space; X = pitch, Y = yaw, Z = roll
F32 AngularVelocityX;
F32 AngularVelocityY;
F32 AngularVelocityZ;
F32 Yaw;
F32 Pitch;
F32 Roll;
// Suspension travel normalized: 0.0f = max stretch; 1.0 = max compression
F32 NormalizedSuspensionTravelFrontLeft;
F32 NormalizedSuspensionTravelFrontRight;
F32 NormalizedSuspensionTravelRearLeft;
F32 NormalizedSuspensionTravelRearRight;
// Tire normalized slip ratio, = 0 means 100% grip and |ratio| > 1.0 means loss of grip.
F32 TireSlipRatioFrontLeft;
F32 TireSlipRatioFrontRight;
F32 TireSlipRatioRearLeft;
F32 TireSlipRatioRearRight;
// Wheels rotation speed radians/sec.
F32 WheelRotationSpeedFrontLeft;
F32 WheelRotationSpeedFrontRight;
F32 WheelRotationSpeedRearLeft;
F32 WheelRotationSpeedRearRight;
// = 1 when wheel is on rumble strip, = 0 when off.
S32 WheelOnRumbleStripFrontLeft;
S32 WheelOnRumbleStripFrontRight;
S32 WheelOnRumbleStripRearLeft;
S32 heelOnRumbleStripRearRight;
// = from 0 to 1, where 1 is the deepest puddle
F32 WheelInPuddleDepthFrontLeft;
F32 WheelInPuddleDepthFrontRight;
F32 WheelInPuddleDepthRearLeft;
F32 WheelInPuddleDepthRearRight;
// Non-dimensional surface rumble values passed to controller force feedback
F32 SurfaceRumbleFrontLeft;
F32 SurfaceRumbleFrontRight;
F32 SurfaceRumbleRearLeft;
F32 SurfaceRumbleRearRight;
// Tire normalized slip angle, = 0 means 100% grip and |angle| > 1.0 means loss of grip.
F32 TireSlipAngleFrontLeft;
F32 TireSlipAngleFrontRight;
F32 TireSlipAngleRearLeft;
F32 TireSlipAngleRearRight;
// Tire normalized combined slip, = 0 means 100% grip and |slip| > 1.0 means loss of grip.
F32 TireCombinedSlipFrontLeft;
F32 TireCombinedSlipFrontRight;
F32 TireCombinedSlipRearLeft;
F32 TireCombinedSlipRearRight;
// Actual suspension travel in meters
F32 SuspensionTravelMetersFrontLeft;
F32 SuspensionTravelMetersFrontRight;
F32 SuspensionTravelMetersRearLeft;
F32 SuspensionTravelMetersRearRight;
// Unique ID of the car make/model
S32 CarOrdinal;
// Between 0 (D -- worst cars) and 7 (X class -- best cars) inclusive
S32 CarClass;
// Between 100 (worst car) and 999 (best car) inclusive
S32 CarPerformanceIndex;
// 0 = FWD, 1 = RWD, 2 = AWD
S32 DrivetrainType;
// Number of cylinders in the engine
S32 NumCylinders;
} __attribute__((packed)) FORZA_SLED;
typedef struct _dash_
{
// = 1 when race is on. = 0 when in menus/race stopped …
S32 IsRaceOn;
// Can overflow to 0 eventually
U32 TimestampMS;
F32 EngineMaxRpm;
F32 EngineIdleRpm;
F32 CurrentEngineRpm;
// In the car's local space; X = right, Y = up, Z = forward
F32 AccelerationX;
F32 AccelerationY;
F32 AccelerationZ;
// In the car's local space; X = right, Y = up, Z = forward
F32 VelocityX;
F32 VelocityY;
F32 VelocityZ;
// In the car's local space; X = pitch, Y = yaw, Z = roll
F32 AngularVelocityX;
F32 AngularVelocityY;
F32 AngularVelocityZ;
F32 Yaw;
F32 Pitch;
F32 Roll;
// Suspension travel normalized: 0.0f = max stretch; 1.0 = max compression
F32 NormalizedSuspensionTravelFrontLeft;
F32 NormalizedSuspensionTravelFrontRight;
F32 NormalizedSuspensionTravelRearLeft;
F32 NormalizedSuspensionTravelRearRight;
// Tire normalized slip ratio, = 0 means 100% grip and |ratio| > 1.0 means loss of grip.
F32 TireSlipRatioFrontLeft;
F32 TireSlipRatioFrontRight;
F32 TireSlipRatioRearLeft;
F32 TireSlipRatioRearRight;
// Wheels rotation speed radians/sec.
F32 WheelRotationSpeedFrontLeft;
F32 WheelRotationSpeedFrontRight;
F32 WheelRotationSpeedRearLeft;
F32 WheelRotationSpeedRearRight;
// = 1 when wheel is on rumble strip, = 0 when off.
S32 WheelOnRumbleStripFrontLeft;
S32 WheelOnRumbleStripFrontRight;
S32 WheelOnRumbleStripRearLeft;
S32 heelOnRumbleStripRearRight;
// = from 0 to 1, where 1 is the deepest puddle
F32 WheelInPuddleDepthFrontLeft;
F32 WheelInPuddleDepthFrontRight;
F32 WheelInPuddleDepthRearLeft;
F32 WheelInPuddleDepthRearRight;
// Non-dimensional surface rumble values passed to controller force feedback
F32 SurfaceRumbleFrontLeft;
F32 SurfaceRumbleFrontRight;
F32 SurfaceRumbleRearLeft;
F32 SurfaceRumbleRearRight;
// Tire normalized slip angle, = 0 means 100% grip and |angle| > 1.0 means loss of grip.
F32 TireSlipAngleFrontLeft;
F32 TireSlipAngleFrontRight;
F32 TireSlipAngleRearLeft;
F32 TireSlipAngleRearRight;
// Tire normalized combined slip, = 0 means 100% grip and |slip| > 1.0 means loss of grip.
F32 TireCombinedSlipFrontLeft;
F32 TireCombinedSlipFrontRight;
F32 TireCombinedSlipRearLeft;
F32 TireCombinedSlipRearRight;
// Actual suspension travel in meters
F32 SuspensionTravelMetersFrontLeft;
F32 SuspensionTravelMetersFrontRight;
F32 SuspensionTravelMetersRearLeft;
F32 SuspensionTravelMetersRearRight;
// Unique ID of the car make/model
S32 CarOrdinal;
// Between 0 (D -- worst cars) and 7 (X class -- best cars) inclusive
S32 CarClass;
// Between 100 (worst car) and 999 (best car) inclusive
S32 CarPerformanceIndex;
// 0 = FWD, 1 = RWD, 2 = AWD
S32 DrivetrainType;
// Number of cylinders in the engine
S32 NumCylinders;
S32 reserved1;
S32 reserved2;
S32 reserved3;
// add for DASH
F32 PositionX;
F32 PositionY;
F32 PositionZ;
F32 Speed;
F32 Power;
F32 Torque;
F32 TireTempFrontLeft;
F32 TireTempFrontRight;
F32 TireTempRearLeft;
F32 TireTempRearRight;
F32 Boost;
F32 Fuel;
F32 DistanceTraveled;
F32 BestLap;
F32 LastLap;
F32 CurrentLap;
F32 CurrentRaceTime;
U16 LapNumber;
U8 RacePosition;
U8 Accel;
U8 Brake;
U8 Clutch;
U8 HandBrake;
U8 Gear;
S8 Steer;
S8 NormalizedDrivingLine;
S8 NormalizedAIBrakeDifference;
F32 TireWearFrontLeft;
F32 TireWearFrontRight;
F32 TireWearRearLeft;
F32 TireWearRearRight;
// ID for track
S32 TrackOrdinal;
} __attribute__((packed)) FORZA_DASH;
int last_raceon = 0;
void parse_forza_dbg(unsigned char *message)
{
int row = 0;
FORZA_DASH forza;
memcpy(&forza, message, sizeof(FORZA_DASH));
for(int i = 0; i < 324; i++)
{
if(i % 16 == 0)
printf("\n");
printf("%02X ",message[i]);
}
printf("\n");
printf("NumCylinders %d\n", forza.NumCylinders);
printf("PositionX %f\n", forza.PositionX);
printf("PositionY %f\n", forza.PositionY);
printf("PositionZ %f\n", forza.PositionZ);
printf("speed %f\n", forza.Speed);
printf("clutch %d\n", forza.Clutch);
printf("brake %d\n", forza.Brake);
printf("accel %d\n", forza.Accel);
printf("HandBrake %d\n", forza.HandBrake);
}
void parse_forza(unsigned char *message)
{
int row = 0;
FORZA_DASH forza;
memcpy(&forza, message, sizeof(FORZA_DASH));
static unsigned int pack_cnt = 0;
if(last_raceon != forza.IsRaceOn)
{
clear();
last_raceon = forza.IsRaceOn;
}
if(forza.IsRaceOn)
{
mvprintw(row++, 0, "let's fly %d\n",pack_cnt++);
mvprintw(row++, 0, "RPM %.0f / %.0f", forza.CurrentEngineRpm, forza.EngineMaxRpm);
mvprintw(row++, 0, "acc X %f", forza.AccelerationX);
mvprintw(row++, 0, "acc Y %f", forza.AccelerationY);
mvprintw(row++, 0, "acc Z %f", forza.AccelerationZ);
mvprintw(row++, 0, "vel X %f", forza.VelocityX);
mvprintw(row++, 0, "vel Y %f", forza.VelocityY);
mvprintw(row++, 0, "vel Z %f", forza.VelocityZ);
mvprintw(row++, 0, "ang vel X %f", forza.AngularVelocityX);
mvprintw(row++, 0, "ang vel Y %f", forza.AngularVelocityY);
mvprintw(row++, 0, "ang vel Z %f", forza.AngularVelocityZ);
mvprintw(row++, 0, "yaw %f", forza.Yaw);
mvprintw(row++, 0, "roll %f", forza.Pitch);
mvprintw(row++, 0, "pitch %f", forza.Roll);
mvprintw(row++, 0, "CarOrdinal %5d", forza.CarOrdinal);
mvprintw(row++, 0, "CarClass %5d", forza.CarClass);
mvprintw(row++, 0, "CarPerformanceIndex %5d", forza.CarPerformanceIndex);
mvprintw(row++, 0, "DrivetrainType %5d", forza.DrivetrainType);
mvprintw(row++, 0, "NumCylinders %5d", forza.NumCylinders);
mvprintw(row++, 0, "clutch[%3d] brake[%3d] accel[%3d] handbrake[%3d] gear[%2d] Steer[%3d]"
, forza.Clutch
, forza.Brake
, forza.Accel
, forza.HandBrake
, forza.Gear
, forza.Steer
);
mvprintw(row++, 0, "Speed[%5.0f] Power[%7.0f] Torque[%5.0f] Boost[%5.0f] Fuel[%5.0f]"
, forza.Speed
, forza.Power
, forza.Torque
, forza.Boost
, forza.Fuel
);
mvprintw(row++, 0, "Position %f , %f , %f"
, forza.PositionX
, forza.PositionY
, forza.PositionZ
);
}
else mvprintw(row++, 0, "pause");
refresh();
}
void error_handling(char *message);
int main(int argc, char *argv[]){
int serv_sock;
char message[BUF_SIZE];
int str_len;
socklen_t clnt_adr_sz;
struct sockaddr_in serv_adr, clnt_adr;
printf("%d sizeof(FORZA_SLED)\n", sizeof(FORZA_SLED));
printf("%d sizeof(FORZA_DASH)\n", sizeof(FORZA_DASH));
if(argc!=2){
printf("Usage:%s <port>\n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if(serv_sock == -1)
error_handling("UDP socket creation error");
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error");
initscr();
while(1){
clnt_adr_sz = sizeof(clnt_adr);
str_len = recvfrom(serv_sock, message, BUF_SIZE, 0, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
message[str_len] = 0x00;
// printf("%d received [%s]\n", str_len, message);
// printf("%d received, %d sizeof(FORZA_DASH)\n", str_len, sizeof(FORZA_DASH));
parse_forza(message);
// parse_forza_dbg(message);
sendto(serv_sock, message, str_len, 0, (struct sockaddr*)&clnt_adr, clnt_adr_sz);
}
close(serv_sock);
return 0;
}
void error_handling(char *message){
fputs(message, stderr);
fputc('\n', stderr);
endwin();
exit(1);
}