Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Porting & PC-specific issues #333

Open
emoose opened this issue Sep 15, 2022 · 80 comments
Open

Porting & PC-specific issues #333

emoose opened this issue Sep 15, 2022 · 80 comments

Comments

@emoose
Copy link
Collaborator

emoose commented Sep 15, 2022

Since the issues page has got a bit large and it's a little difficult to find the UHD issues that still need work, I figured a separate page indexing them all would be useful.

This page mostly deals with three kinds of problems: issues that appeared during the porting process (GC/PS2->Wii->X360->PC), PC specific issues, and problems caused by 60FPS+ framerate - issues with/caused by re4_tweaks & feature requests aren't covered.

This is by no means complete and mostly just which issues I can recall right now, probably missing a lot from here.. please feel free to mention any that are missing and I'll update this list.

Issues without a linked issue page are either very well-known already, or uncertain/rumoured, if anyone finds an example to prove the issue exists feel free to make a reply or new issue page for it.

Port issues/changes

  • Filter03 (glare) is broken, currently applies extra color to whole scene, should just be adding some extra color to edges of models that are close to light/fire sources - Filter03 has some code removed compared to GC version, but restoring the GC code doesn't seem to help (tested this recently too, still no luck with it...) (Post-processing issues #5)
  • Water texture is changed from GC, seems to have broken reflections in some spots (Water animation speed too fast at 60FPS #175 (comment))
  • (semi-fixed) The item pickup from Saddler appears before end cutscene starts, making pickup glow appear throughout cutscene (even covering whole screen at one point) (Saddler Treasure appears before the cutscene ends #331)
  • (fixed) Main menu background can no longer be scrolled around, code for it seems to have been removed (which port removed it first? Wii 360/PS3?) (Restore Gamecube's main menu stick behavior  #290)
  • Audio effects (echo/reverb) are missing, probably relied on GC/Wii's AX audio processing/effect library (does PS2 still have them though?) ([Feature request] Restore Echo effects and enable true Stereo Audio (maybe restore Dolby Pro Logic II too) #300)
  • Enemy spawns changed in PS2 port onwards? (heard this mentioned but haven't confirmed it - might not be something we can fix in the code though) - confirmed that certain enemies were removed after the initial GC release (see below), but I'm sure I heard spawn locations changed too...
  • Merchant death animation was changed from GC version ([Feature Request] Gamecube merchant deaths #238)
  • Shadows are drawn on top of fog effect, making it clear where enemies might be hiding in the fog... probably an issue with how they emulate GC/Wii GX graphics, seems fog is drawn with a shader, can we make that shader draw after the shadows?
  • UHD ports removed blood texture on U3, could be related to Leon face texture not changing when in pain too, something about model texture changes maybe broken?
  • Not really an issue, but the Wii version added support for Wiimote aiming, which many prefer over controller/mouse - the code for it is still mostly included intact in the UHD release, would be awesome to expose that to players (either with something that could support Wiimotes directly, if there is any library for that, or maybe just allowing the aim crosshair to be controlled by mouse pointer position would be enough, IIRC there's already tons of software that can translate Wiimote -> mouse position...)
  • Being attacked with chainsaw now has a small chance of being survivable, seems to be something framerate related (only appeared in the game after QLOC port added 60FPS changes?), and happens more often when playing at higher than 60FPS - seems there is something in the chainsaw attack code that can leave you with 1HP but unsure if it's actually related or not, some guess this could be normally-unused beta code which the framerate changes are now somehow letting get activated, but there's still no definite answer why it happens (Restore Survivable Chainsaw attack #468)

PC-specific issues

  • Framerate is a lot worse compared to the older PC port, using dxvk can help improve it, but that could bring it's own issues too. Could be caused by overhead from the GameCube/Wii GX-API -> DX9 layer that it uses (dxvk wouldn't really affect that though...), or maybe the D3D9 MULTITHREADED flag slowing things down? (D3DCREATE_MULTITHREADED flag removal #44, MultithreadFix: slight FPS boost via multithread improvements #255)
  • Game-speed is tied to FPS, if framerate goes lower than the chosen FPS cap (30/60) then game will start to slow down - UseDynamicFrametime setting added by re4_tweaks can help with this, but also causes a lot of issues too, game isn't designed to work well with varying frametimes... (eg [Hang] Non-60/30 framelimit causes game hang #328)
  • Framerate cap can't be changed during gameplay - editing the value in memory does work to change it though, but maybe there's a reason they disallow it during gameplay (certain timer values for things like cEm routines do make use of deltaTime/gamespeed when they're inited...)
  • XAudio related code will cause game crash if no speakers/headphones are connected
  • XAudio related code randomly causes crash when loading a stage, even with speakers/headphones connected (crash seems to happen around something like 1 in 10 runs for me - might be caused by having VS debugger attached though...)
  • Audio crack/pops when some enemies talk
  • Del Lago spear-throwing section seems to still be based around analog sticks, with a mouse it feels really floaty, sometimes just ignores mouse movements altogether, code for it is only using AnalogXX values, could use some improvement (De Lago Boat Mouse Fix #160)

60FPS issues

  • Water animation speed is doubled at 60FPS (Water animation speed too fast at 60FPS #175)
  • Some animated texture speeds usually aren't correct, also seems there's no interpolation happening with them, so 30FPS texture animations look very obviously 30FPS (eg. waterfalls)
  • Certain animations (rifle reload) use a mode that locks the animation to 30FPS, other game anims are able to play at 60FPS+ fine, seems to maybe be disabling interpolation - re-enabling it brings a huge amount of issues though, likely an issue with the animation data itself? (maybe format it's stored in can't be interpolated easily...) (Framerate slowdown & 60FPS issues #23)
  • Damage from enemies & weapons may be doubled at 60FPS
  • (mostly fixed) Certain falling item & object animations (chest opening, cabinet opening...) still have speed issues at 60FPS, seems some were fixed while others were left out.
@linkthehylian
Copy link

linkthehylian commented Sep 15, 2022

Main menu background can no longer be scrolled around, code for it seems to have been removed (which port removed it first? Wii?)

This actually still exists in the Wii edition and I've made sure to test it as well. Idk which port removed it first unfortunately, but it's definitely there on Wii.

No emulation was done to test this, btw. I still own my Wii and copy of the game for it haha.

@albertre4HD
Copy link

Thanks for compiling all these issues in one single post!!
I have some clarifications/additions in case you want to update the first post:

-"Animated textures also run at doubled speed": The fire effects still run at 30fps, maybe some other animated sprites effects runs at double speed, but I'd say most of them don't.

And that's it XDDD phewww!

@emoose
Copy link
Collaborator Author

emoose commented Sep 17, 2022

Many thanks for the list, was hoping you might see this post and add to it 😄

Cabinet doors wrong position when reenter room r315

Had a quick look at this, might be caused by a small coding error, comparing the function in r315 to r515 it seems r315 is adding to the cabinet door position while is r515 taking away from it instead, very subtle issue since the only change is - instead of +...

Surprised they didn't fix r315 too since they obviously fixed the issue themselves in r515... guess they maybe didn't want to touch any of the older main-game code in case something broke? idk.. should be safe to change it though.

Changing it in CE seemed to fix it, you can hex edit EXE to change it too, search for D8 45 08 83 C4 04 and change it to D8 65 08 83 C4 04 (just change 45 to 65), will see about adding it to re4_tweaks soon too.

@albertre4HD
Copy link

Ha! Great. When I think I tried porting all files from room r515 to r315 ...

Don't mention it!

Maybe it wasn't broken in Separate Ways by default... I can't see them fixing this small bug, really XD

@emoose
Copy link
Collaborator Author

emoose commented Sep 17, 2022

Novistadors in room r20a: Originally, in the North America first release of the game, there were 2 Novistadors in the small room (the one with the lock).

This one is a little trickier, the GC debug does also spawn them too, so it's easier to test, but you do have to go through the bar shooting section & ashley segment first for game to count her as "rescued", then returning thru r20c -> r20a will have new enemies spawned, and the 2 enemies will show up on r20a.

On UHD though doing the same will let r20c enemies spawn, but none on r20a...

Doesn't seem r20a has code for spawning those enemies in either version, so they must be done some other way. Seems the game has at least 3 different ways of making enemies show on earlier maps:

  • EmListSetAlive takes an ESL index and sets it in memory to be alive/spawnable
  • cEmWrap::setEm takes an ESL index and uses EmListSetAlive on it
  • and it looks like checkEmListNo can actually change what ESL the map will use based on flags

The enemies on r20c seem to get spawned by checkEmListNo, by changing the ESL it loads when the SCF_R206_ASHLEY_RESCUE_IDX flag is set, unfortunately there doesn't seem to be any difference between GC/UHD in the flag checks in checkEmListNo that I could see, so it could be either a call to EmListSetAlive / cEmWrap was changed, or maybe the ESL that it changes to once SCF_R206_ASHLEY_RESCUE_IDX is set was changed (emleon04)

Could be that the Novistadors show up in the normal non-ashley-flag ESL (emleon03? unsure), but without the alive flag, while emleon04 would have a copy of them with the alive flag set, but maybe UHD removed the duplicate entry with alive flag entirely - just a guess though, it's also likely something could be calling the EmListSetAlive on them sometime after the Ashley rescue instead... will try looking more into it soon.

@albertre4HD
Copy link

albertre4HD commented Sep 17, 2022

Ahhhhh. You gave me an idea.
Since all the r20a enemies were stored in emleon03.esl, I only edited that file and forced the game to spawn the Novistadors since you enter the room the first time. In fact there was the data for 2 Novistadors in that room, but they were a different variant and their spawn position and bahaviour was different from the one in the USA GC version. And now I understand why: These were not the lost Novistadors.

But I never thought emleon04.esl also contained 2 r20a entries... ONLY 2!! and guess what?: They are the 2 missing Novistadors :D
image

In the emleon04.esl of the PC port the enemy ID is "zeroed" So they simply didn't appear... So I simply changed the initial "01 00" of both lines to "01 2D" and they magically appeared only after rescuing Ashley and go back through room r20c.

So, it's fixed! You just need to replace this file
https://mega.nz/file/kGJnwL6B#IWw0EykvKE50mWewGb74uiWWhG9smpu5krVkYebZA78
(and don't load a savegame in the castle, because I think the game stores the enemies data inside the savegame, and if you saved the game when the wrong file was in the game folder, it won't contain the 2 Novistadors)

So, we can conclude this issue only needs a 2 bytes file edit.
EDIT: Can this edit be performed by re4_tweaks? Or I simply include the edited file in the future HD project 1.2?
Just asking. The file is already done ;)

Is there any other missing enemy compared to the first USA GameCube version? Because the solution is probably the same.

@emoose
Copy link
Collaborator Author

emoose commented Sep 17, 2022

Aha nice, thought it might be something in there, was going to start comparing entries in GC to UHD to look for it, but didn't think of trying to look for the ones with 20a room ID heh.

I did notice some of the earlier entries in the emleon04 also had the enemy ID zeroed compared to GC as well though (eg. the ones at 0xE0 - 0x1E0 use ID 0x14/0x25 on GC debug, but zeroed on UHD) so guess there's a good chance other enemies might have been removed the same way, wonder if a quick GC->UHD ESL converter tool could be useful for those, would make it easier to compare at least.

Think it might be better for HD project to include that, could be other mods that also edit that ESL that we wouldn't want re4_tweaks to override.

@albertre4HD
Copy link

Oh, you are right!
I don't know any tool that does that, but it shouldn't take too much time to compare the lines and see the zeroed entries
Haha Oh yeah! let's make the game harder!

@albertre4HD
Copy link

albertre4HD commented Sep 17, 2022

Ok, here go the differences in the ESL files:

emleon03.esl
I don't know what's the difference of 00 and 01.
image

emleon04.esl As you mentioned:
REMOVED ENEMIES!!
image
REMOVED ENEMIES!!
image

emleon05.esl
I don't know what's the difference of 00 and 01.
image

emleon06.esl
I don't know what's the difference of 00 and 01.
image

And that's it! These are the main differences in Enemies Spawn Lists
In brief, the removed enemies are:

  • 2 Novistadors in the broken butterfly area when you come back to these areas after rescuing Ashley
  • 8 zealots in the blue columns room when you come back to these areas after rescuing Ashley

@emoose
Copy link
Collaborator Author

emoose commented Sep 17, 2022

Thanks for looking into it! Pretty strange choice to remove those enemies, pretty sure those are all optional right? You have to choose to backtrack to run into them, so not like players are ever forced to defeat them to continue the story, odd. Maybe they figured adding enemies there could be a waste of ammo or something.

I think the difference between 00 and 01 in that column is setting the ALIVE flag, so being set to 00 would pretty much remove them, except game does have ability to bring those ones alive later on in code with EmListSetAlive (game can't do that with enemies that have ID 00 like Novistadors though afaik), it uses that with a bunch of enemies, no idea if it's used with the changed ones you found though.

@albertre4HD
Copy link

albertre4HD commented Sep 17, 2022

I haven't noticed any difference playing in normal and professional and entering those areas several times after killing them all... So, I have no idea what the 00 01 do in those cases XD

And yes, those enemies are optional 100% It's the price you have to pay to backtrack and obtain the broken butterfly for free, and you can dodge them anyway. Specially the ones in room r20f (blue columns). You just need to run and that's it. So... no idea why did they remove them... ¿?

Ohh! I almost forget these other 2 bugs:

  • UHD: When U3 "It" transforms, a blood texture covers him (the texture is gone during the "second round"). But the texture is missing in UHD and later ports. It was present up to the PS3 port:
    PS3: https://youtu.be/WnL-BsKiwnI?t=40483
    PS4: https://youtu.be/m-bzZo_sRzY?t=23396
    image

  • UHD 60fps: During the first Saddler cutscene in the church, the chandelier Leon uses to jump from one side to another flickers. This only happens during an actual gameplay, not in the Movie Browser. My guess is something gets activated when Leon uses the chandelier, or maybe the final 2 animation frames in 60fps mode are fighting each other. It looks ok at 30 fps
    https://youtu.be/m-bzZo_sRzY?t=6155
    image

@nipkownix
Copy link
Owner

Interesting discoveries here, specially about those enemies being probably intentionally removed, hmm 🤔

@albertre4HD
Copy link

Another clarification about this point:

"UHD ports removed blood texture on U3, could be related to Leon face texture not changing when in pain too, something about model texture changes maybe broken?"

They are 2 different things. And this leads me to another bug and some notes about it.

  • UHD: Missing facial expressions
    Leon's and other player facial expressions in pain and death are stored inside the plxx.udas files as morphing data. These are Leon's model data converted to obj using the bin converter tool:
    image

So it's not a texture, but a morphing animation. Exactly the same method used during cutscenes to animate faces.
Cutscene morphing faces reach up to 30 different meshes, unlike the ingame characters which only have 1 or 2.

It's strange Ashley face is properly animated. She has exactly the same morphing method that makes her to look worried during the idle animation when she's with Leon.

So, let's analyze characters face morphing data:

  • Leon (pl00, pl08, pl09, pl10): 2 morphing meshes
  • Ashley (pl01, pl11, pl05, pl15): 2 morphing meshes
  • Ada (pl0b, pl0c, pl16): 1 morphing mesh: Unused even on the Gamecube... Her facial expression never changes. but it's incorrectly used in the debug build when she jumps through a window. So it can be triggered:
    image

And some Leon facial expression images in the Gamecube:
image
image

  • HUNK and Wesker have no morphing data, so their faces never changes
  • Krauser face animation works with bones instead of morphing meshes, just like the enemies. So, he has no problems

And that's it!

@emoose
Copy link
Collaborator Author

emoose commented Sep 19, 2022

Ah interesting, thanks for the breakdown. I noticed the game does have a PlSetFace function that's gets called by a ton of places, and some character classes also have a setFace function too (which PlSetFace calls into), for some characters that function does nothing, but seems these classes do try loading in data at least:

  • cPlLeon
  • cSubAshley
  • cPlWesker
  • cPlAda

while these classes have no code and don't try loading anything:

  • cPlAshley (ashley segment version I guess)
  • cPlKlauser
  • cPlHunk

I also found in the PS2 version a enum for the kinds of faces those functions set:

  • FACE_NORMAL = 0
  • FACE_SURPRISE = 1
  • FACE_SHOUT = 2

Doesn't seem to have anything pain/death related, unless they just reused the enum values without renaming them maybe - or it's possible this setFace stuff I'm looking at isn't actually related to how they apply the pain/death ones, will try checking GC version soon, maybe something is different there.

E: btw, could you tell me which file in the pl00.udas has the morph data? Are they both stored inside pl00_004?
If they are, then I guess this setFace code must be for something different, since this seems to be reading from _094 / _095...

@albertre4HD
Copy link

Ahh, that makes sense, Ashley as player (pl01) has the morphing data, but her face never changes in the Gamecube.

About Wesker, there is no morphing data. Maybe they had the intention to include it but they forgot XD

@emoose
Copy link
Collaborator Author

emoose commented Sep 20, 2022

Hm, tried forcing the setFace functions to the surprise/shout ones, didn't notice any difference in Leon's face with it though, maybe there is something broken with that function there, will have to try testing it on GC too.

Looks like the pl00_094/pl00_095 data used for those might also be referencing data from the main model too (_004?), maybe the morph data you found in there.

Unfortunately the Shape code it uses to apply the face CalculateShape_new is pretty similar to the main MOTION_INFO animation stuff, using Hermite curves and weird stuff like that, so not very easy to understand... AFAIK hand shapes are also using the same function though, and maybe faces during cutscenes too, so I guess it's not completely broken at least, maybe just an issue with the _094/_095 data.

@albertre4HD
Copy link

albertre4HD commented Sep 20, 2022

I see...
_004 is the face model
for Leon, for example, it's pl00_004.bin
Faces are usually number 004
Leon's with jacket extracted models:
image

@emoose
Copy link
Collaborator Author

emoose commented Sep 20, 2022

Looks like changing setFace does have an effect on GC, here it is forced to 1 / FACE_SURPRISE:

Dolphin_22-09-20_13-31-23-870

and with 2 / FACE_SHOUT:

Dolphin_22-09-20_13-32-32-358

and finally for comparison, the default 0 / FACE_NORMAL:

Dolphin_22-09-20_13-30-14-605

FACE_SHOUT seems very similar to FACE_NORMAL, but I think there might be some slight difference around the mouth there.

So I guess the issue is probably with the setFace stuff then, will have to double-check that forcing it on UHD definitely doesn't work, then will maybe try seeing if I can replace the _094/_095 data with something from cutscenes instead to see if that affects anything.

E: yep, still no effect forcing it on UHD. Looks like cutscenes are making use of the same Shape stuff for lip sync though, maybe they changed something to fix 60FPS lip sync and broke the setFace stuff in the process. Going to try forcing one of the cutscene shapes during gameplay to see if it still animates in-game at least.

@albertre4HD
Copy link

Haha it's funny to see these images
The second one it's about the eyes' expression. He looks more serious/focussed. I have no idea when he uses this face...
The first one is for both damage and death
Great you fount it on the GC!

@emoose
Copy link
Collaborator Author

emoose commented Sep 20, 2022

Added a button to test setting the shape data directly (wasted like 30 minutes debugging because I was making it apply to m_pHead_24 instead of m_pFace_10 >.>)
With shape data from cutscene the button did move the face around, it was all polygons shooting out of his face though (forgot to take pic), I guess cutscene face model is different somehow? but at least it showed the data from cutscene did change stuff.
Edited it to use the FACE_SURPRISE data and got this, blink and you might miss it:

bio4_22-09-20_18-23-14-159-1.webm.mp4

Weird thing is with the cutscene shape data the changed polygons stayed after the animation, but I guess something in FACE_SURPRISE is making it reset straight after it (SURPRISE does only has 1 frame defined, while the cutscene shape had ~100 or so), will need to look into it more...

E: seems ShapeMove is what resets the face, looks like they might have bugged something in there with the 60FPS changes.
It does seem to accept a flag that stops it from resetting though, if I set that then the face stays fine when I force it:
image

If you search for 8B 48 10 6A 02 56 in the EXE (should be 3 matches for leon/wesker/ada) and change the 02 to 03 that should set the flag for the setFace func, can't really tell if it's letting the pain face show when attacked or not though, looked like he did have closed eyes when dying but maybe that happened anyway?

@emoose
Copy link
Collaborator Author

emoose commented Sep 20, 2022

Here's a build with a slightly better patch to ShapeMove instead of setting that flag (undo the flag if you tried it), should help with the other chars like Ashley too, but might need to make sure it didn't affect any cutscene faces:
dinput8.zip

Still not sure if it's working properly though, I did get a bug while making it which made his jaw pop out when attacked which was visible for a few seconds, fixed that now, but hopefully means the actual pain face shows too.

@albertre4HD
Copy link

Oh wow! What an exhaustive research! As always!
I'm going to test it in a few minutes :D

@albertre4HD
Copy link

Oh yeah! I've only tested this and there are no problems during the first cutscene. I'll do more checks later (I have to go now)
image

@qingsheng8848
Copy link

wonderful!

@albertre4HD
Copy link

Ashley (when she's with Leon) also changes her facial expression now!
image

Wesker doesn't, but he has no alt.face expressions, so even if there is the code, there's nothing to load.

Ashley as main player and Ada don't change their expressions never, but it was already like that in the Gamecube

@emoose emoose pinned this issue Sep 24, 2022
@emoose
Copy link
Collaborator Author

emoose commented Sep 24, 2022

UHD 60fps: During the first Saddler cutscene in the church, the chandelier Leon uses to jump from one side to another flickers. This only happens during an actual gameplay, not in the Movie Browser. My guess is something gets activated when Leon uses the chandelier

Confirmed this happening too, went back and made two saves, one before jumping on it (where I'd need to jump on it to start the cutscene), and one after - issue only seems to happen on the save that's before jump, so I guess something related to chandelier gets changed after jumping, and game doesn't reset it properly afterward, but saving/reloading after jumping on it lets the data be set back to normal, so the cutscene (and movie browser) doesn't have the issue.

Maybe something related to the position of it, I'd guess if it was off even a tiny bit it might cause the cutscene to act up, will try giving a closer look soon.

E: huh, position of it doesn't get changed at all by jumping on it, looks like they use the MOTION_INFO stuff to handle the animation of it swinging though, seems a flag is set after jumping that stops the MOTION stuff, maybe during event cutscenes it ignores that flag or handles it different somehow, will have to see if I can find where it's setup.

@albertre4HD
Copy link

Thanks for confirming the issue!
Damn 60fps... XD

@emoose
Copy link
Collaborator Author

emoose commented Sep 24, 2022

Ahh think I've got it, it's to do with the deltaTime variable, seems the chandelier animation keeps running after you've jumped from it, just with a neutral animation, which is fine when deltaTime is static (0.5 for 60FPS / 1 for 30FPS), but the framelimiter code in the game actually has a strange check to see if an event is running, and if it is then it allows deltaTime to be based on the actual time the previous frame took (I never understood why it's doing that, maybe it's something to try and improve the sync of the cutscenes or something, or to reduce slowdown during cutscenes)

So since it's based on the actual time of last frame, the deltaTime starts changing to something like 0.5000039935 or 0.5000010133 each frame, and I guess the animation system doesn't like deltaTime changing so much, resulting in it shaking/flickering around.

Our replacement framelimiter code copied the same weird event check & making deltaTime use actual frame time, if I remove that weird code then the chandelier seems to be fixed (and if I force that code, the chandelier starts flickering in gameplay too :p), so pretty sure that's the culprit.

Not really sure how to fix the animation code to work with frametimes like that, so I guess for now I can probably just add a check to see if it's playing chandelier event and make it skip the frametime code if it is, if any other cutscenes have weird flickering like that maybe they could be fixed the same way too.

@nipkownix
Copy link
Owner

nipkownix commented Dec 1, 2022

Functions that still probably have speed-related issue:

r20d_moveWall  <---- DONE
r20d_moveArmorStatue   <---- DONE

r20e_moveCrestDoor  <---- DONE

r21b_DoorOpen  <---- DONE
r21b_GetDragonBall  <---- DONE

R31bExecFallRoom  <---- DONE

cR31CDoor::close  <---- DONE

r327_DoorOpen  <---- DONE

r501_openCover_mb  <---- DONE

cR305Shutter::open/close

cR209Door::open/close <--- Not affected?

cR50fDoor::open <---- DONE (p̶r̶e̶t̶t̶y̶ ̶m̶e̶s̶s̶y̶ ̶d̶e̶c̶o̶m̶p̶ ̶r̶i̶g̶h̶t̶ ̶n̶o̶w̶,̶ ̶h̶o̶p̶e̶f̶u̶l̶l̶y̶ ̶e̶m̶o̶o̶s̶e̶ ̶c̶a̶n̶ ̶w̶o̶r̶k̶ ̶s̶o̶m̶e̶ ̶o̶f̶ ̶h̶i̶s̶ ̶m̶a̶g̶i̶c̶ ̶h̶e̶r̶e̶)
R50fExecCageMain  <---- DONE
(Unsure where r50f's "secret lid" code is atm) Edit: It is sub_7B49E0.   <---- DONE

stuff I wasn't able to find just by reading the code:

  • r326/r51b's code, haven't seen anything related to drawers there <--- Not affected?

  • r405's opening door (might be shared with the original room, gotta check that) - Edit: found: r405_em_set <---- DONE

  • r502's closing/opening gate, opening puzzle (might also be shared with the original room) Edit: Found. <---- DONE

@albertre4HD
Copy link

albertre4HD commented Dec 1, 2022

Wow!! Thanks! Going to test it now that I have a few minutes :DDD
Ahh yeah I remember room 20e (Ashley's second room) everything was double speed: cabinets, the door with Salazar family emblem, the rotating armor bust at the end of the room, the big blue chest opening... that room was a complete mess XD

EDIT1
Things I'm finding:
r20e, as you mentioned, some things are still double speed: door and rotating armor bust are still double speed.
r105, the crystal ball rotating and its door opening double speed.
r501, the trapdoor to the cave is double speed (it's Separate Ways r102 equivalent. In r102 the speed was right).

EDIT2
r326/r51b. Hey! It's already fixed! It probably uses another room name haha
r405's opening door. The equivalent room is r300
r502's closing/opening gate, opening puzzle. Equivalent is r108.

Wait... r21b_GetDragonBall... Dragon Ball? really?? XDD

Oh! I see! r315 cabinets's lids wrong position is already corrected. Cool!!

@nipkownix
Copy link
Owner

Ah yeah, the last build I posted (with the FixCompartmentsOpeningSpeed option) should only cover opening chests/cabinets/shelves/etc. The other stuff you mentioned will be hopefully fixed in the next build I'll post.

@albertre4HD
Copy link

Ah, I've edited the post again :P

@nipkownix
Copy link
Owner

nipkownix commented Dec 1, 2022

While analyzing r31c, I noticed the final door there (the one you use all 3 crests on) also enables a camera shaking effect (cEsp4a) while the door is opening. This camera shake gets weaker on higher fps. It is weak at 60 fps, and nonexistent at 240 fps. Gotta have a proper look at that later. Seems to be controlled by QuakeMain, QuakeScheduler, etc.

Edit: Wtf? While working on room r50f, I noticed one of the weirdest things ever:

This is the room, loaded when playing at 30 fps:

image

And this is the same exact save file, loaded when playing at 240 fps:

image

The position of the box' lid is multiplied by the delta time?! Shouldn't the delta time be applied only when the lid is in the process of opening? OpenBoxMain has an if statement to differentiate the process of opening a box when it is supposed to be seen (openedFlag == false), and when it has already been opened (openedFlag == true), so I imagine when (openedFlag == true), no delta time should be applied, yet it is ._.

Edit2: Instead of hooking every single incorrect deltaTime multiplication in this func, I just worked around the issue by overwriting deltaTime to 1 at the start of the function if openedFlag == true. I thought about restoring deltaTime at the end, but I think we should be fine letting the game itself restore it in the next frame? (@emoose ?)

Crazy how QLOC messed this one up. They consciously added all these wrong deltaTime multiplications:
image

I imagine they thought this function only handled opening boxes, not boxes that should already be open too. Still odd.

@emoose
Copy link
Collaborator Author

emoose commented Dec 2, 2022

I thought about restoring deltaTime at the end, but I think we should be fine letting the game itself restore it in the next frame? (@emoose ?)

Hmm, is that function only being ran once at room init (maybe with a loop inside to increase the rotation, like the openbox stuff has), or does it get ran across multiple frames?

If it's only ran once then I think it'd be safe to just edit it like you mentioned, otherwise if it's called in multiple frames I guess it could maybe break something, eg. if anything else is also using dt across multiple frames at the same time...

If needed maybe we could just hook the thunk for it and "wrap" the function with stuff to override deltaTime/call the func/restore deltaTime, if that func actually has a thunk anyway.

Good stuff with all these deltaTime fixes too btw, was actually thinking of trying to tackle those this week as well, looks like you've beaten me to them now though :p
Will try looking into fixing up that cR50fDoor decomp shortly too.

Seems r104_openKiln, r104_openedKiln & r104_openKiln_main are actually used by r107, not r104. Was it named like that on GC too? Should we rename those in the .idb? Edit: r20d_moveArmorStatue is also used by r20e instead.

Seems GC has them the same way, named as r104 but used in r107, maybe those were originally on r104 and got moved over or something. (ditto with the r20d_moveArmorStatue too, and r20d_getSalazarCrest)

I've noticed a few things like that around, maybe those should be renamed to make it easier to find all the funcs for a certain room... maybe with a comment to mention the orig name.

sub_997390(r129_openBox_main_mb) <---- DONE

added that too, ty!

E: added cR50fDoor stuff here: https://www.mediafire.com/file/4xym01wj49xf3df/bio4-221202-tmp.zip/file
Looks like most of the funcs for it got inlined into the other R50f funcs, updated the R50F_WORK_mb struct to use cR50fDoor tho, so that inlined code should be more obvious when it tries accessing the door stuff.

@nipkownix
Copy link
Owner

nipkownix commented Dec 2, 2022

If it's only ran once then I think it'd be safe to just edit it like you mentioned, otherwise if it's called in multiple frames I guess it could maybe break something

Hmm, I'm pretty sure it was only being run during the room's init (on r50f at least), but I went ahead and switched to the wrapping method using the thunk as you mentioned. Makes it easier to restore deltaTime afterwards.

Good stuff with all these deltaTime fixes too btw, was actually thinking of trying to tackle those this week as well, looks like you've beaten me to them now though :p

Ah, thanks 😅
Been also testing all of these up to 240 fps, so everything should be fine with those if we do end up adding more fps options to the game.

Seems GC has them the same way, named as r104 but used in r107, maybe those were originally on r104 and got moved over or something.

Hmm, interesting. Maaaybe they had larger rooms originally and had to split them up due to limitations on regular consoles? Meh, who knows.

E: added cR50fDoor stuff here:

Many thanks!

Edit: sub_7B49E0 is the func that controls the secret compartment in r50f's box.

@albertre4HD
Copy link

albertre4HD commented Dec 2, 2022

Hey!!! I've just noticed you've fixed the speed of hats and helmets falling twice fast when you shoot the enemies on the head (same with Krauser's hat)!
So this
image
actually fixed other things as well! haha
The names maybe are the ways they can lose their hats/helmets ¿?¿? (headshot, kick, heel hit...)

After all, it's all the same: a falling model after receiving damage

Guys, you are doing magic! Now that I'm doing the animation course and a part of it is Unity and all the C# code behind it, I almost can understand what you are writing XD

@nipkownix
Copy link
Owner

Hey!!! I've just noticed you've fixed the speed of hats and helmets falling twice fast when you shoot the enemies on the head (same with Krauser's hat)!

Ah, nice! Seems emoose was right about this being related to hats and stuff.

Ah, @albertre4HD, I've finally implemented the rest of the fixes I had in mind:
dinput8.zip

This build has our two new options: FixCompartmentsOpeningSpeed and FixMovingGeometrySpeed. This should cover almost every screenshot from 60fps_AnimationIssuesCompendium.zip.

Would appreciate some testing when you have the time.

The only issues not covered yet (as far as I can tell) are these:
image

And there's also one not featured in the screenshots, which is cR305Shutter::open/close.
This func controls this shutter:
image

Not only the shutter itself opens and closes too fast, but the time it stays closed is also smaller the higher the FPS. Couldn't figure this one out, maybe @emoose could have better luck here?

@albertre4HD
Copy link

Thanks a lot!!
I've checked most of them and everything is perfect!!

I only found this (room 50f)
the door closing still runs faster at 60fps. The rest of the camera movements/animations before and after the door is blocked runs at the perfect speed ;D

Resident.Evil.4.Biohazard.4.2022.12.03.-.23.38.33.02_1.mp4

@nipkownix
Copy link
Owner

Oh yeah, you're right, I totally forgot about cR50fDoor::close :p
This should fix it:
dinput8.zip

@emoose
Copy link
Collaborator Author

emoose commented Dec 4, 2022

Not only the shutter itself opens and closes too fast, but the time it stays closed is also smaller the higher the FPS. Couldn't figure this one out, maybe @emoose could have better luck here?

Hm, looks like some of the cR305Shutter funcs got inlined into the rest of the r305 code there, eg r305_ShutterCtrl seems to have the cR305Shutter::setOpen func inlined at the top of it (the if ( g_R305_work->shutter_B4.field_1C ) block seems to match that func at least)

Looks like the blocks where it sets [..].r_no_0 = 1; were actually setOpen, while [..].r_no_0 = 2; is setClose

The v18 = j_Rnd() % 30 + 180; part after the first setClose block looks like it's setting some kind of timer, v18 then gets decremented (each frame?) and once it hits 0 also sets v19 to 0, which then lets it run the EmWrap block under that (setting up enemies just before it opens maybe)

That shutterCtrl func does seem to use deltaTime for some things too, but not really sure how that works (v20 = 1.0 - pG->deltaTime_70 + 40.0;, seen things like that a few times in the code too, but no idea what difference that actually makes...)

@nipkownix
Copy link
Owner

I think v20 is their loop count in float, like I did for mine. But.. v20 = 1.0 - pG->deltaTime_70 + 40.0 makes no sense? Hmm.

@nipkownix
Copy link
Owner

nipkownix commented Dec 4, 2022

Figured out the opening and closing speed:

		// cR305Shutter::open 
		pattern = hook::pattern("DC 05 ? ? ? ? D9 98 ? ? ? ? 8B 4E 04 D9 46 14");
		struct cR305Shutter__open_hook
		{
			void operator()(injector::reg_pack& regs)
			{
				double vanillaAdd = 200.0;

				if (re4t::cfg->bFixMovingGeometrySpeed)
				{
					double newAdd = GlobalPtr()->deltaTime_70 * vanillaAdd;

					_asm {fadd newAdd}
				}
				else
				{
					_asm {fadd vanillaAdd}
				}
			}
		}; injector::MakeInline<cR305Shutter__open_hook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(6));

		// cR305Shutter::close
		pattern = hook::pattern("D9 05 ? ? ? ? 8B 46 30");
		struct cR305Shutter__close_hook_1
		{
			void operator()(injector::reg_pack& regs)
			{
				double vanillaNum = -40.0;

				if (re4t::cfg->bFixMovingGeometrySpeed)
				{
					double newNum = GlobalPtr()->deltaTime_70 * vanillaNum;

					_asm {fld newNum}
				}
				else
				{
					_asm {fld vanillaNum}
				}
			}
		}; injector::MakeInline<cR305Shutter__close_hook_1>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(6));

		pattern = hook::pattern("DC 25 ? ? ? ? D9 5E 18 D9 81 ? ? ? ? D9 46 0C DE D9 DF E0 F6 C4 41 0F 85 ? ? ? ? D9 46 0C D9 99 ? ? ? ?");
		struct cR305Shutter__close_hook_2
		{
			void operator()(injector::reg_pack& regs)
			{
				double vanillaSub = 40.0;

				if (re4t::cfg->bFixMovingGeometrySpeed)
				{
					double newSub = GlobalPtr()->deltaTime_70 * vanillaSub;

					int interval = (int)std::round(CurrentFrameRate() / 30);

					// Interval must be at least 1
					if (interval < 1)
						interval = 1;

					// Only apply the speed changes if the frame interval has passed
					if (GlobalPtr()->frameCounter_530C % interval == 0)
					{
						_asm {fsub newSub}
					}
				}
				else
				{
					_asm {fsub vanillaSub}
				}
			}
		}; injector::MakeInline<cR305Shutter__close_hook_2>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(6));

Still no luck with the interval between closing -> opening again.

Edit: Ah, right, it is v18 = j_Rnd() % 30 + 180;. I was weirded out by the 30+180 there, pff.

@albertre4HD
Copy link

Oh yeah, you're right, I totally forgot about cR50fDoor::close :p This should fix it: dinput8.zip

Oh I forgot to mention that it's fixed now, thanks! ;D

@nipkownix
Copy link
Owner

@emoose Been trying to get the original demo movie to play again (in the "press any key" menu screen). That was removed on the X360 (i think?).

titleMain is supposed to play it when Rno1_1 is 7, apparently. It doesn't look like anything currently makes routine 1_1 reach this value, though.
Doing it manually works, but you can't skip the video after they begin. You can disable SPF_KEY to be able to skip the video, but even if you do so, something about the menu routine gets messed up later.

Other .sfd videos skip just fine with SPF_KEY enabled, though, so that's weird. cSofdec::appMain even has a btn_trg_20 check to skip the videos, but I'm not sure how that is doing anything with SPF_KEY enabled, unless all other videos in the game are using another method to skip.

Not sure how GC originally gets into Rno1_1 7, but we could just set up our own timer. Not sure about these issue though.

@pas-de-2
Copy link
Contributor

pas-de-2 commented Dec 7, 2022

I messed around a bit with restoring demo playback earlier. This lets you press the back button at the main menu to start demo playback, just like in the Wii version. Only problem is you have to press Select(?) to skip out of it as though it were a normal cutscene, should be able to press Circle/Back as well. EDIT: Well, that might just be a Wii-mote mapping thing, because you can skip all cutscenes with the 2 button on the Wii port, but it's still probably a good idea to add just for the demo scenes.

	// Restore TitleMenu Demo playback
	{
		// play demo when pressing the back button
		auto pattern_begin = hook::pattern("A1 ? ? ? ? F7 40 04 00 00 00 80 88"); // titleMenuSelect
		auto pattern_end = hook::pattern("83 C4 2C 8B 4B 2C 8B");
		struct CancelToDemoPlayback
		{
			void operator()(injector::reg_pack& regs)
			{
				TitleWorkPtr()->SetRoutine(TITLE_WORK::Routine0::Main, 7, 1, 0);
				return;
			}
		}; injector::MakeInline<CancelToDemoPlayback>(pattern_begin.count(1).get(0).get<uint32_t>(0), pattern_end.count(1).get(0).get<uint32_t>(3));
	}

UHD only includes the PS2 version of demo0eng.sfd. It would be cool if we added checks for the existence of demo1.sfd and demo2.sfd, and looped through all three like in the Wii version. I'm sure @albertre4HD would have fun remastering these for the next HD project release.

@nipkownix
Copy link
Owner

Only problem is you have to press Select(?) to skip out of it

Ah, so you can skip it using a controller? Haven't been able to do it using KB/M for some reason. Huh.

@pas-de-2
Copy link
Contributor

pas-de-2 commented Dec 7, 2022

Ah, so you can skip it using a controller? Haven't been able to do it using KB/M for some reason. Huh.

It lets me skip it when pressing Escape on the keyboard as well.

@nipkownix
Copy link
Owner

Figured out it does the same here, but only if I play a video in the movie browser first. Pretty strange.

@pas-de-2
Copy link
Contributor

pas-de-2 commented Dec 7, 2022

Oh hey you're right, I'm getting the same thing. I just so happened to watch the intro video before I tested it with keyboard. The controller skip always works right away, though.

@nipkownix
Copy link
Owner

nipkownix commented Dec 7, 2022

Seems like the problem is Key.btn_trg_20. Controller works because it is also checking for Joy[0].trg_18. Meh. Probably something weird in PadRead not writing to btn_trg_20 for some reason.

@nipkownix
Copy link
Owner

This seems to work to have the videos play if you wait a bit in the "press start" screen:

	pattern = hook::pattern("D9 05 ? ? ? ? 53 D9 5D ? 57 8B 7D ? 85 C0 75 ? 68");
	struct titleStart_hook
	{
		void operator()(injector::reg_pack& regs)
		{
			// Code we replaced
			float v55 = 560.0f;
			__asm {fld v55}

			// Set up new timer
			static float timer = 480.0f;

			timer -= GlobalPtr()->deltaTime_70;

			if (timer <= 0.0f)
			{
				timer = 480.0f; // Reset timer

				TitleWorkPtr()->SetRoutine(TITLE_WORK::Routine0::Main, 7, 1, 0);
			}
		}
	}; injector::MakeInline<titleStart_hook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(6));


	pattern = hook::pattern("F7 05 ? ? ? ? ? ? ? ? 75 ? 8B 0D ? ? ? ? 81 E1");
	struct cSofdec__appMain_hook
	{
		void operator()(injector::reg_pack& regs)
		{
			// Unset SPF_KEY to let cSofdec::appMain check if the movie should be skipped. This only seems to be a problem during the demo
			// videos in titleMain for some reason.
			// TODO: Check if this messes something up during playback of other videos?
			FlagSet(GlobalPtr()->flags_STOP_0_170, uint32_t(Flags_STOP::SPF_KEY), false);

			// Our key check replacements. Only checking Key.btn_trg_20, but the original code also used Joy[0].trg_18 for gamepads. 
			// btn_trg_20 seems to work fine for gamepads, though.
			// TODO: Check Dinput gamepads.
			bool PressedEV_CANCEL = ((Key_btn_trg() & (uint64_t)KEY_BTN::KEY_EV_CANCEL) == (uint64_t)KEY_BTN::KEY_EV_CANCEL); // Xinput Back, Keyboard Esc
			bool PressedCANCEL = ((Key_btn_trg() & (uint64_t)KEY_BTN::KEY_CANCEL) == (uint64_t)KEY_BTN::KEY_CANCEL); // Xinput B, Keyboard Esc

			if (PressedEV_CANCEL || PressedCANCEL)
				regs.ef &= ~(1 << regs.zero_flag);
			else
				regs.ef |= (1 << regs.zero_flag);
		}
	}; injector::MakeInline<cSofdec__appMain_hook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(28));

	// The end of routine 7 puts the menu into routine 1, which is the main menu (after the "press start" screen).
	// We change it to 17 here, to go back to the "press start" screen instead.
	pattern = hook::pattern("C6 46 ? ? E9 ? ? ? ? 53 E8 ? ? ? ? 83 C4 ? 3C ? 0F 85");
	injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(3), uint8_t(0x11), true); // Rno1_1 = 1 -> Rno1_1 = 17

Also makes it possible to skip the videos using B on the gamepad :p

@nipkownix
Copy link
Owner

Cleaned it up and added RestoreDemoVideos.

This option will play demo videos if the game is left idle at the main menu or "press any key" screen for 20 seconds.
It also supports playing the original GC videos like @pas-de-2 mentioned.
It will play any of these in order, if they exist in BIO4/movie:

demo0_gc.sfd
demo1_gc.sfd
demo0.sfd/demo0eng.sfd (called demo2.sfd on the Wii version, but I've kept the original name here)

Seems to be working nicely, but some more testing would be nice.
@albertre4HD, I think your amazing video editing skills are required once more :p

Test build:
dinput8-demovideos.zip

@albertre4HD
Copy link

Wow!!
It works haha

I let the video play and then I went to the movie browser and play a Separate Ways video. Then I went back to the press any button screen and wait again to watch the video, and after that I started a new game and the intro video also played with no problem.

So, I guess there are no side effects ;D
Another great success!!

@pas-de-2
Copy link
Contributor

pas-de-2 commented Dec 8, 2022

I spent way too long hunting down the keyboard issue. The game stores an un_stop_mask_453 global that allows certain keys to pass through the SPF_KEY check at the bottom of PadRead. Watching a video in the movie browser or watching the intro video fixes the issue because they both call KeyStop via SceEventStart, which sets the mask.

If you add a call to KeyStop(0xF12000EFCF1000ui64); in your cSofdec__Initialize_hook, it'll work without having to remove the SPF_KEY flag and potentially causing issues.


I was slightly mistaken about the Wii version. It let you cancel demo playback with the 'Back' button because the Wii-mote's 2 button is mapped to let you skip all cutscenes that way. In the other console versions you still press start/select to skip them like a normal cutscene. You could just get rid of the appMain hook altogether, or maybe come up with a way to let that cancellation only work for demo videos and not eg. the intro cinematic.

I do like that the Wii version lets you press Back to cycle through the demos on demand, but I guess that would mean replacing the ability to back out to the 'any key' screen.

@nipkownix
Copy link
Owner

Oh cool, so that's what un_stop_mask_453 does. Nice job figuring that out, you got more patience than me :p
I'll take a look at calling KeyStop instead of unsetting SPF_KEY soon. Thanks!

In the other console versions you still press start/select to skip them like a normal cutscene. You could just get rid of the appMain hook altogether, or maybe come up with a way to let that cancellation only work for demo videos and not eg. the intro cinematic.

Meh, if that's the case, I'll just remove it. Thanks for the heads-up, I hadn't actually checked what button the console versions use to skip.

@nipkownix
Copy link
Owner

nipkownix commented Dec 9, 2022

f609fb9 makes use of KeyStop now. Seems to work fine here.
I've also added FADE_WORK and FadeWorkPtr() so we can use that instead of using the hacks I was using before. Hopefully I haven't messed anything up, though. (@emoose is the mastermind behind the SDK, I never really added much there).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants