-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[Bug Fix]: Fixes for Never Wanted "Flickering" in Zancudo/Bolingbroke #3152
Conversation
Could you test whether it's possible to regain wanted stars after unloading the menu with never wanted toggled on? I tested this exact code yesterday, but the game just set the maximum wanted level to 0 when I unloaded the menu, even though the |
I did test toggling the feature on and off (unloading the menu should call on_disable the same way) without issue. When I disabled Never Wanted in Bolingbroke I almost immediately regained the expected wanted level. Most likely you weren't properly calling the command with So your on_enable and on_disable overrides weren't actually executing. |
Thanks. See comment here for some of my results trying this approach: I can continue investigating since I'm interested in what's going on, but for now I think the SET_MAX_WANTED_LEVEL workaround is acceptable. Ideally I'd prefer hooking whatever sets our wanted level without touching SET_MAX_WANTED_LEVEL. |
The game uses the if (!func_159()) // Is player allowed in Fort Zancudo
{
PLAYER::REPORT_CRIME(PLAYER::PLAYER_ID(), 36/*CRIME_TERRORIST_ACTIVITY*/, (PLAYER::GET_WANTED_LEVEL_THRESHOLD(4) - PLAYER::GET_WANTED_LEVEL_THRESHOLD(PLAYER::GET_PLAYER_WANTED_LEVEL(PLAYER::PLAYER_ID()))));
}
else
{
PLAYER::REPORT_CRIME(PLAYER::PLAYER_ID(), 36/*CRIME_TERRORIST_ACTIVITY*/, (PLAYER::GET_WANTED_LEVEL_THRESHOLD(Global_262145.f_22100 /* Tunable: GANGWANTEDLEVELZANCUDO */) - PLAYER::GET_WANTED_LEVEL_THRESHOLD(PLAYER::GET_PLAYER_WANTED_LEVEL(PLAYER::PLAYER_ID()))));
} We can hook it as follows: void REPORT_CRIME(rage::scrNativeCallContext* src)
{
Player player = src->get_arg<Player>(0);
int crime_type = src->get_arg<int>(1);
int wanted_threshold = src->get_arg<int>(2);
if (player == self::id && g.self.never_wanted)
return;
PLAYER::REPORT_CRIME(player, crime_type, wanted_threshold);
} Alternatively, there is a tunable that disables AI in Fort Zancudo, making NPCs ignore the player: int func_3() // Should player get wanted
{
//...
if (Global_262145.f_22094 /* Tunable: DISABLEENEMYAIFORTZANCUDO */)
{
return 0;
}
//...
} But I think this would be a cheap workaround? Also, I don't think we need to save previous maximum wanted level. In most cases, scripts set the maximum wanted level to either 0 or 5. SP scripts, which YimMenu doesn’t generally support, are the primary exceptions. MP scripts usually set the wanted level to 0 or 6, but the native automatically reverts it back to 5 anyway: __int64 __fastcall sub_143291F8C(__int64 a1)
{
__int64 (__fastcall *v1)(__int64); // rbp
__int64 v2; // rcx
__int64 (__fastcall *v4)(__int64); // [rsp+0h] [rbp-8h] BYREF
v2 = **(unsigned int **)(a1 + 16);
if ( (int)v2 >= 5 )
v2 = 5i64;
v4 = v1;
_InterlockedExchange64((volatile __int64 *)&v4, (__int64)sub_14064A204);
return v4(v2);
} Therefore, I suggest setting it directly to 5 in the |
Awesome analysis! I need to start diving into decompiled scripts as well. I should have been able to identify the use of REPORT_CRIME. I assume you're doing this on your fork already but I'll try it this way tomorrow and make updates to this PR. So we'll hook REPORT_CRIME to handle Bolingbroke and Zancudo. Everything else should be handled by the on_tick behavior of setting wanted level to zero. By chance, do you know if REPORT_CRIME also extends to the player gaining a wanted level from shooting peds, police, etc.? SET_PLAYER_WANTED_LEVEL doesn't do this either. The on_tick behavior makes this a non-issue, but if we have an opportunity to change this from a looped command to just a normal command, it would be more optimal to use a one-time native hook instead.
That's fine as well. Though I did have SP in mind as the main reason for the check even though we don't officially support it. Again, checking through scripts would have identified any other corner cases so I trust that your review is complete and we don't need this behavior.
IIRC there were plans at some point in GTA's development to support 6 stars but that got axed. Sounds like instead of updating the scripts they just put in this workaround. |
@rkwapisz give ur discord id. |
It can be used for them, but R* only uses it in The native calls BTW, here's a list of all the crime types from |
Download the artifacts for this pull request: |
The natives are only used by the scripts. Rockstar calls the script runners CTheScripts. The native interfaces are just extensions of what the engine can do. The native usually just does something like:
That code section might be wrapped inside a function that the natives just call with the determination of CPed from CTheScripts. When you shoot a ped, the engine might internally just call that funcition with the aggressor of who shot the ped. |
I hooked the original function that void hooks::report_crime(int64_t a1, int crime_type, rage::fvector3* coords, bool a4, bool a5, uint32_t points, int64_t a7, int a8)
{
static uint32_t total_crime_points{};
if (!g.self.never_wanted)
g_hooking->get_original<report_crime_now>()(a1, crime_type, coords, a4, a5, points, a7, a8);
if (g.self.never_wanted)
points = 0;
total_crime_points += points;
std::string crime_str = (crime_type_names.count(crime_type) > 0) ? crime_type_names.at(crime_type) : "CRIME_UNKNOWN";
LOG(INFO) << crime_str << " (" << crime_type << ")" << ", +" << points << " points " << "(total " << total_crime_points << ")";
}
This function is responsible for reporting all types of crimes in the game. Each crime type requires a different amount of crime points to reach a specific wanted level. For example, So I think the current implementation with |
We want this behaviour. Scripts use it to set the player's wanted level for certian missions. As a test bed, I suggest you use the Casino Heist mission on Aggressive. When you get to the part where everyone leaves the casino, a very janky cutscene starts that sometimes gets stuck. If you interfere with the wanted level at all, you'll get the player stuck in a race condition, where the script is waiting for the player to become wanted, yet you'll be rejecting it, thus Philosopher A is waiting on Philsopher B, who's waiting on Philospher A who's waiting on... You get it. |
@ShinyWasabi @gir489returns, so should I leave this open or merge it and if any changes need to be made merge that in later? Currently it's already in a functioning state and can be merged safely. As well as improve/fix some of the things that are wrong with the Wanted Level modifier. |
If everyone is happy at the moment, we can solve the immediate issue reported in the bug. Potential conflicts with heists will remain a known issue. |
Yeah I'm fine with it. We can make any other improvements later. |
I'd rather we implement the REPORT_CRIME detour now, and fix this now. |
Verified intended behavior in Bolingbroke with the REPORT_CRIME hook. Couldn't verify Zancudo since my GTA:O characters all have access (I was actually testing Zancudo earlier in SP, but then I noticed SP doesn't use REPORT_CRIME apparently?). Other deviant criminal behavior is cleared as before, and since we're not doing anything with SET_WANTED_LEVEL or SET_MAX_WANTED_LEVEL, it shouldn't clash with most scripts. Haven't had a chance to confirm intended behavior with the Casino Heist as I don't have one set up to test with at the moment. |
761d9e7
to
29d0e78
Compare
Zancudo and Bolingbroke in SP are handled by void func_51()//Position - 0x3779
{
if (!PED::IS_PED_INJURED(PLAYER::PLAYER_PED_ID()))
{
if ((ENTITY::IS_ENTITY_IN_ANGLED_AREA(PLAYER::PLAYER_PED_ID(), -1599.593f, 2818.15f, -17.645f, -1612.423f, 2806.997f, 17.645f, 51f, true, false, 0) || ENTITY::IS_ENTITY_IN_ANGLED_AREA(PLAYER::PLAYER_PED_ID(), -2301.089f, 3385.031f, -31.086f, -2305.302f, 3379.441f, 31.086f, 16f, true, false, 0)) || ENTITY::IS_ENTITY_IN_ANGLED_AREA(PLAYER::PLAYER_PED_ID(), -2287.138f, 3385.616f, 31.124f, -2292.554f, 3378.428f, 31.124f, 19.8f, true, false, 0))
{
if (PLAYER::GET_PLAYER_WANTED_LEVEL(PLAYER::PLAYER_ID()) < 5)
{
PLAYER::SET_PLAYER_WANTED_LEVEL(PLAYER::PLAYER_ID(), 4, false);
PLAYER::SET_PLAYER_WANTED_LEVEL_NOW(PLAYER::PLAYER_ID(), false);
}
}
}
} See |
Implemented some final fixes asked for by @ShinyWasabi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this solution, as it leaves open the SET_WANTED_LEVEL to allow the wanted level to be on for at least one frame, thus the scripts SHOULD work. I will test this either today or tomorrow and report back if Casino Heist works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feature needs to be consistent across freemode and heists. The user asked to be "never wanted" not to fail missions randomly. Shutting this feature off during missions isn't acceptable, as that isn't what the user wanted, and we can fix this unlike something like Vehicle Flymode in FPV.
This is the function that sets our wanted level in Casino Heist: void func_12477()//Position - 0x3FE8D7
{
if (!BitTest(uLocal_60051, 6))
{
if (BitTest(uLocal_60051, 5))
{
if (!func_49(&uLocal_60059))
{
if (PLAYER::GET_PLAYER_WANTED_LEVEL(bLocal_3225) != 5)
{
PLAYER::SET_PLAYER_WANTED_LEVEL(bLocal_3225, 5, false);
PLAYER::SET_PLAYER_WANTED_LEVEL_NOW(bLocal_3225, false);
}
PLAYER::SUPPRESS_LOSING_WANTED_LEVEL_IF_HIDDEN_THIS_FRAME(bLocal_3225);
func_324(&uLocal_60059, 0, 0);
}
else if (!func_240(&uLocal_60059, 30000, 0))
{
PLAYER::SUPPRESS_LOSING_WANTED_LEVEL_IF_HIDDEN_THIS_FRAME(bLocal_3225);
}
else
{
MISC::SET_BIT(&uLocal_60051, 6);
}
}
}
} We just check for the 6th bit of the local in the |
Some missions still had issues where your wanted level would continuously be set, and the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks fine. Author says he's tested it.
Added calls to SET_MAX_WANTED_LEVEL to prevent "flickering" of wanted level in areas like Bolingbroke and Zancudo that, in some situations, attempt to persist a wanted level on the player until they leave.
We're also saving the players max wanted level before toggling off the feature to provide a simple return to normal once the feature is disabled. However, this obviously only remembers what the wanted level was before Never Wanted was enabled, and doesn't know what the max wanted level SHOULD be. However this would be an issue in most other implementations.
I like the idea of hooking the natives directly and blocking calls to SET_PLAYER_WANTED_LEVEL (and related natives) as @gir489returns suggested but that's a bit out of my ability at the moment. However I haven't seen any unexpected conflicts with this implementation.
Fixes #3150. Tested it in Zancudo and Bolingbroke and achieved the desired behavior - no more wanted level flickering.