Merge branch 'main' of https://github.com/dethrace-labs/dethrace into opponent_matching
This commit is contained in:
commit
66380ea3f6
|
|
@ -6,6 +6,7 @@ To run MSVC 4.20 outside of a non-Windows environment, you can use a Docker imag
|
|||
We are targetting being accurate to CARM95.EXE.
|
||||
- Created date: "16 October 1997"
|
||||
- SHA256 hash: `c6040203856b71e6a22d2a29053a1eadd1a2ab41bce97b6031d745079bc07bdf`
|
||||
- [Download from archive.org](https://archive.org/download/carm-95/CARM95.EXE)
|
||||
|
||||
## Build container image
|
||||
```sh
|
||||
|
|
@ -23,10 +24,21 @@ When running this container, you must define:
|
|||
| `/build` | `/code/dethrace/build-msvc420` | Volume mount. This directory must exist but can start off empty. Note that this build directory _cannot be_ the same as your "regular" build directory. |
|
||||
| `/original` | `/games/carma` | Volume mount. Path to a directory with a copy of the original CARM95.EXE file |
|
||||
|
||||
### Generating an HTML diff
|
||||
|
||||
### Diffing a single function
|
||||
This is the primary flow for making a change to the code and viewing the comparison to the original executable.
|
||||
|
||||
```sh
|
||||
docker run --platform linux/amd64 \
|
||||
-e CMAKE_FLAGS="-G Ninja -DCMAKE_BUILD_TYPE=Debug -DMSVC_42_FOR_RECCMP=on" \
|
||||
-v <PATH_TO_DETHRACE_DIR>:/source \
|
||||
-v <PATH_TO_DETHRACE_BUILD_DIR>:/build \
|
||||
-v <PATH_TO_CARMA_DIR>:/original:ro \
|
||||
msvc420-wine -- \
|
||||
reccmp-reccmp --target CARM95 --verbose FUNCTION_ADDRESS
|
||||
```
|
||||
|
||||
### Generating an HTML diff
|
||||
|
||||
```sh
|
||||
docker run --platform linux/amd64 \
|
||||
-e CMAKE_FLAGS="-G Ninja -DCMAKE_BUILD_TYPE=Debug -DMSVC_42_FOR_RECCMP=on" \
|
||||
|
|
@ -39,8 +51,42 @@ docker run --platform linux/amd64 \
|
|||
|
||||
After running, a `report.html` file will be created in the build-msvc420 directory.
|
||||
|
||||
### Wrapping it up
|
||||
|
||||
I wrapped this logic up into a little `zsh` function, which makes it easy to run from command line.
|
||||
- `dr-reccmp` to generate the overall html report
|
||||
- `dr-reccmp 0x123456` to diff a single function.
|
||||
|
||||
```zsh
|
||||
function dr-reccmp {
|
||||
local arg=()
|
||||
|
||||
if [[ -n "$1" ]]; then
|
||||
arg+=(--verbose "$1")
|
||||
else
|
||||
# only download latest report if changed
|
||||
curl -fsSL --etag-save reccmp-report-etag-new.txt --etag-compare reccmp-report-etag.txt -o reccmp-report-main.json https://raw.githubusercontent.com/dethrace-labs/reccmp-report/main/report.json
|
||||
if [ -s reccmp-report-etag-new.txt ]; then
|
||||
mv -f reccmp-report-etag-new.txt reccmp-report-etag.txt
|
||||
fi
|
||||
arg=()
|
||||
arg+=(--html /source/reccmp-report.html)
|
||||
arg+=(--diff /source/reccmp-report-main.json)
|
||||
arg+=(--svg /source/reccmp.svg)
|
||||
fi
|
||||
|
||||
docker run --platform linux/amd64 \
|
||||
-e CMAKE_FLAGS="-G Ninja -DCMAKE_BUILD_TYPE=Debug -DMSVC_42_FOR_RECCMP=on" \
|
||||
-v .:/source \
|
||||
-v ./build_msvc42:/build \
|
||||
-v /opt/carma/:/original:ro \
|
||||
msvc420-wine -- \
|
||||
reccmp-reccmp --target CARM95 "${arg[@]}"
|
||||
}
|
||||
```
|
||||
|
||||
### Make a pull request change
|
||||
|
||||
reccmp will run against the code in the PR branch. If any functions decrease in accuracy the PR validation will fail.
|
||||
reccmp will run against the code in the PR branch. If any functions decrease in accuracy the PR validation will emit a warning. If the functions which decreased were not changed in the PR, the PR can still be accepted, as the decrease will generally be due to compiler entropy.
|
||||
|
||||
When the PR is merged, the updated report is stored in https://github.com/dethrace-labs/reccmp-report, and this is used to compare the next PR
|
||||
When the PR is merged into `main`, the updated report is stored in https://github.com/dethrace-labs/reccmp-report, and this is used to compare the next PR
|
||||
|
|
|
|||
|
|
@ -472,6 +472,10 @@ void InitialiseCar2(tCar_spec* pCar, int pClear_disabled_flag) {
|
|||
case eDriver_local_human:
|
||||
pCar->car_ID = 0;
|
||||
break;
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
default:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
PossibleService();
|
||||
pCar->box_face_ref = gFace_num__car - 2;
|
||||
|
|
@ -1327,7 +1331,7 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
|
|||
}
|
||||
for (i = 0; i < gNum_active_cars; i++) {
|
||||
car = gActive_car_list[i];
|
||||
car_info = car;
|
||||
car_info = (tCollision_info*)car;
|
||||
car->dt = -1.f;
|
||||
if (car->message.type == NETMSGID_MECHANICS && car->message.time >= gLast_mechanics_time && car->message.time <= gLast_mechanics_time + time_step) {
|
||||
// time between car message and next mechanics
|
||||
|
|
@ -1370,11 +1374,11 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) {
|
|||
if (non_car->collision_info.doing_nothing_flag) {
|
||||
continue;
|
||||
}
|
||||
car_info = non_car;
|
||||
car_info = (tCollision_info*)non_car;
|
||||
car_info->dt = -1.f;
|
||||
if (car_info->message.type == NETMSGID_NONCAR_INFO && car_info->message.time >= gLast_mechanics_time && gLast_mechanics_time + time_step >= car_info->message.time) {
|
||||
car_info->dt = (gLast_mechanics_time + time_step - car_info->message.time) / 1000.0f;
|
||||
GetNetPos(car_info);
|
||||
GetNetPos((tCar_spec*)car_info);
|
||||
}
|
||||
if (car_info->box_face_ref != gFace_num__car
|
||||
&& (car_info->box_face_ref != gFace_num__car - 1
|
||||
|
|
|
|||
|
|
@ -1177,7 +1177,7 @@ int DoCrashEarnings(tCar_spec* pCar1, tCar_spec* pCar2) {
|
|||
credits_squared = sqr(0.7f / victim->car_model_actors[victim->principal_car_actor].crush_data.softness_factor) * gWasted_creds[gProgram_state.skill_level] + 50.0f;
|
||||
credits = 100 * (int)(credits_squared / 100.0f);
|
||||
if (gNet_mode) {
|
||||
message = NetBuildMessage(0x18u, 0);
|
||||
message = NetBuildMessage(NETMSGID_WASTED, 0);
|
||||
message->contents.data.wasted.victim = NetPlayerFromCar(victim)->ID;
|
||||
if (NetPlayerFromCar(culprit)) {
|
||||
message->contents.data.wasted.culprit = NetPlayerFromCar(culprit)->ID;
|
||||
|
|
|
|||
|
|
@ -260,9 +260,9 @@ br_scalar EdgeU(br_angle pSky, br_angle pView, br_angle pPerfect) {
|
|||
br_scalar b;
|
||||
br_scalar c;
|
||||
|
||||
a = cos(BrAngleToRadian(pPerfect)) * cos(BrAngleToRadian(pPerfect));
|
||||
b = sin(BrAngleToRadian(pView));
|
||||
c = cos(BrAngleToRadian(pView) + 1.0f) * BrAngleToRadian(pSky);
|
||||
a = BR_COS(pPerfect) * BR_COS(pPerfect);
|
||||
b = BR_SIN(pView);
|
||||
c = (BR_COS(pView) + 1.0f) * BrAngleToRadian(pSky);
|
||||
return b * a / c;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ void ProcessOilSpills(tU32 pFrame_period) {
|
|||
gOily_spills[i].stop_time = 0;
|
||||
SetInitialOilStuff(&gOily_spills[i], the_model);
|
||||
if (gNet_mode != eNet_mode_none) {
|
||||
message = NetBuildMessage(30, 0);
|
||||
message = NetBuildMessage(NETMSGID_OILSPILL, 0);
|
||||
message->contents.data.oil_spill.player = NetPlayerFromCar(gOily_spills[i].car)->ID;
|
||||
message->contents.data.oil_spill.full_size = gOily_spills[i].full_size;
|
||||
message->contents.data.oil_spill.grow_rate = gOily_spills[i].grow_rate;
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ void LosePowerupX(tPowerup* pThe_powerup, int pTell_net_players) {
|
|||
pThe_powerup->lose_proc(pThe_powerup, pThe_powerup->car);
|
||||
}
|
||||
if (gNet_mode != eNet_mode_none) {
|
||||
the_message = NetBuildMessage(21, 0);
|
||||
the_message = NetBuildMessage(NETMSGID_POWERUP, 0);
|
||||
the_message->contents.data.powerup.event = ePowerup_lost;
|
||||
the_message->contents.data.powerup.player = gLocal_net_ID;
|
||||
the_message->contents.data.powerup.event = GET_POWERUP_INDEX(pThe_powerup);
|
||||
|
|
@ -287,7 +287,7 @@ int GotPowerupX(tCar_spec* pCar, int pIndex, int pTell_net_players, int pDisplay
|
|||
PratcamEvent(the_powerup->prat_cam_event);
|
||||
}
|
||||
if (gNet_mode != eNet_mode_none && pTell_net_players && pIndex == original_index && !ps_power) {
|
||||
the_message = NetBuildMessage(21, 0);
|
||||
the_message = NetBuildMessage(NETMSGID_POWERUP, 0);
|
||||
the_message->contents.data.powerup.event = ePowerup_gained;
|
||||
the_message->contents.data.powerup.player = gLocal_net_ID;
|
||||
the_message->contents.data.powerup.powerup_index = pIndex;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ int gRandom_Rockin_MIDI_tunes[3] = { 9500, 9501, 9502 };
|
|||
// GLOBAL: CARM95 0x00514958
|
||||
int gRandom_CDA_tunes[8] = { 9600, 9601, 9602, 9603, 9604, 9605, 9606, 9607 }; /* dethrace: Changed to size 8 */
|
||||
|
||||
// GLOBAL: CARM95 0x00514978
|
||||
// GLOBAL: CARM95 0x0051498c
|
||||
int gCDA_is_playing;
|
||||
|
||||
// GLOBAL: CARM95 0x0051497c
|
||||
|
|
@ -52,7 +52,7 @@ int gSound_sources_inited;
|
|||
// GLOBAL: CARM95 0x00514988
|
||||
int gMusic_available;
|
||||
|
||||
// GLOBAL: CARM95 0x0051498c
|
||||
// GLOBAL: CARM95 0x00514978
|
||||
tS3_sound_tag gCDA_tag;
|
||||
|
||||
// GLOBAL: CARM95 0x00514990
|
||||
|
|
@ -750,13 +750,13 @@ int DRS3StartCDA(tS3_sound_id pCDA_id) {
|
|||
} while (pCDA_id == gLast_tune);
|
||||
}
|
||||
gLast_tune = pCDA_id;
|
||||
gCDA_is_playing = DRS3StartSoundNoPiping(gMusic_outlet, pCDA_id);
|
||||
gCDA_tag = DRS3StartSoundNoPiping(gMusic_outlet, pCDA_id);
|
||||
#if defined(DETHRACE_FIX_BUGS)
|
||||
// Initial CD music volume was not set correctly
|
||||
DRS3SetOutletVolume(gMusic_outlet, 42 * gProgram_state.music_volume);
|
||||
#endif
|
||||
gCDA_tag = gCDA_is_playing;
|
||||
if (!gCDA_is_playing) {
|
||||
gCDA_is_playing = gCDA_tag != 0;
|
||||
if (gCDA_tag == 0) {
|
||||
gCD_is_disabled = 1;
|
||||
S3DisableCDA();
|
||||
}
|
||||
|
|
@ -765,7 +765,7 @@ int DRS3StartCDA(tS3_sound_id pCDA_id) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return gCDA_tag;
|
||||
return gCDA_is_playing;
|
||||
}
|
||||
|
||||
// IDA: int __cdecl DRS3StopCDA()
|
||||
|
|
@ -777,14 +777,14 @@ int DRS3StopCDA(void) {
|
|||
gCDA_is_playing = 0;
|
||||
gCDA_tag = 0;
|
||||
}
|
||||
return gCDA_tag;
|
||||
return gCDA_is_playing;
|
||||
}
|
||||
|
||||
// IDA: void __cdecl StartMusic()
|
||||
// FUNCTION: CARM95 0x00465899
|
||||
void StartMusic(void) {
|
||||
if (gCD_fully_installed) {
|
||||
gCDA_tag = DRS3StartCDA(9999);
|
||||
gCDA_is_playing = DRS3StartCDA(9999);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1254,7 +1254,8 @@ tS3_channel* S3GetChannelForTag(tS3_sound_tag tag) {
|
|||
if (!tag) {
|
||||
return 0;
|
||||
}
|
||||
for (o = gS3_outlets; o && o->id != tag; o = o->next) {
|
||||
// the first char of tag is the outlet id. See `S3GenerateTag`
|
||||
for (o = gS3_outlets; o && o->id != (tag & 0xff); o = o->next) {
|
||||
;
|
||||
}
|
||||
if (!o) {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ if(MSVC_42_FOR_RECCMP)
|
|||
target_sources(harness PRIVATE os/null.c)
|
||||
elseif(WIN32)
|
||||
target_sources(harness PRIVATE os/windows.c)
|
||||
target_link_libraries(harness PRIVATE dbghelp ws2_32)
|
||||
target_link_libraries(harness PRIVATE dbghelp ws2_32 iphlpapi)
|
||||
elseif(APPLE)
|
||||
target_sources(harness PRIVATE os/macos.c)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
|
|
|||
Loading…
Reference in New Issue