Gacsam 0 Posted January 13, 2021 Share Posted January 13, 2021 Hi, I've been working on a mod and I'm almost there, but I've gotten stuck on prompts and got no clue how to fix it up. I am using the ScriptHookRDRNetAPI. I'd really appreciate if someone could look over and point out where the issue lies. Some notes to narrow down the issue: Function.Call<string>(Hash._CREATE_VAR_STRING is where I think the issue lies but that's just assumption. _CREATE_VAR_STRING in NativeDB is shown as a const char*, but: const char* gives an error: char* cannot be declared as a const (commented out) Function.Call<char*> gives an error: char* cannot be used as an argument (commented out) changing string to any other kind of variable, like a long immediately crashes the game upon reloading script. targetEntity is 100% working, I have used it to check if I'm targeting specific models. Function.Call<Hash>(Hash.GET_HASH_KEY seems to be working exactly the same as Game.GenerateHash( tested by comparing models, so I doubt that's causing any issues. Both ShowSubtitle commands fire off with the current code, but prompt does not appear. RDR2.UI.Screen.ShowSubtitle("Initialising"); Entity targetEntity = outputTarget.GetResult<Entity>(); int groupID = Function.Call<int>(Hash._UIPROMPT_GET_GROUP_ID_FOR_TARGET_ENTITY, targetEntity); int basicPrompt = Function.Call<int>(Hash._UIPROMPT_REGISTER_BEGIN); //const char* promptString = Function.Call<char*>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", "Prompt"); Function.Call(Hash._UIPROMPT_SET_CONTROL_ACTION, basicPrompt, Game.GenerateHash("INPUT_FRONTEND_LS")); Function.Call(Hash._UIPROMPT_SET_TEXT, basicPrompt, Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", "Prompt")); Function.Call(Hash._UIPROMPT_SET_PRIORITY, basicPrompt, 5); Function.Call(Hash._UIPROMPT_SET_ATTRIBUTE, basicPrompt, 18, 1); Function.Call(Hash._UIPROMPT_SET_STANDARDIZED_HOLD_MODE, basicPrompt, 1); Function.Call(Hash._UIPROMPT_SET_GROUP, basicPrompt,groupID, 0); Function.Call(Hash._UIPROMPT_SET_ENABLED, basicPrompt, true); Function.Call(Hash._UIPROMPT_SET_VISIBLE, basicPrompt, true); Function.Call(Hash._UIPROMPT_REGISTER_END, basicPrompt); RDR2.UI.Screen.ShowSubtitle("Initialising finished"); Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 14, 2021 Author Share Posted January 14, 2021 I've narrowed down the issue to the CREATE_VAR_STRING command, I managed to dig around and found a command with an existing prompt, the prompt shows up just fine. Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, "WARDROBE_INSPECT_PROMPT"); Is there somewhere a list of all other prompts such as WARDROBE_INSPECT_PROMPT? Or would anyone have an idea how to get the _CREATE_VAR_STRING working? Quote Link to comment Share on other sites More sharing options...
LMS 673 Posted January 14, 2021 Share Posted January 14, 2021 Casting it to string probably corrupts the return value of _CREATE_VAR_STRING as it is not a .NET string. Try using long or ulong as the return value instead. Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 14, 2021 Author Share Posted January 14, 2021 (edited) Unfortunately neither work, I'm testing my mod with subtitles for now, the prompts are the final bits really. Both lines throw some errors about protected memory, bloody UIs always being an issue hah Edited January 14, 2021 by Gacsam Quote Link to comment Share on other sites More sharing options...
LMS 673 Posted January 15, 2021 Share Posted January 15, 2021 Odd, perhaps something else messes up the return value or the way it is passed. But that is definitely the function to use. Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 15, 2021 Author Share Posted January 15, 2021 I've been testing around and realised that _UIPROMPT_REGISTER_BEGIN outputs a Prompt and I've been using int all this time. Displaying the result of _CREATE_VAR_STRING(string) gives out the same string as the input, is it Trying to get the Prompt via Function.Call<Prompt>(Hash._UIPROMPT_REGISTER_BEGIN); results in an error Unable to cast native value to object of type 'RDR2.UI.Prompt'. Weirdly enough, int worked with the existing prompt text. Do I need to create the prompt first with _UIPROMPT_CREATE? Any idea how I would go about it? The only mention of the method is in the campfire thread which I browsed through many times and it's only mentioned. Quote Link to comment Share on other sites More sharing options...
LMS 673 Posted January 15, 2021 Share Posted January 15, 2021 The type Prompt is just a wrapper around a handle, so int as a type is totally fine. It is the same for peds, you can have your type Ped, but ultimately it is just a wrapper around a handle (uint). Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 15, 2021 Author Share Posted January 15, 2021 So that brings us back to _UIPROMPT_SET_TEXT, hell, this is really confusing since it looks like it should work just fine. What value should _CREATE_VAR_STRING return? It looks like it returns the exact same string when returning a string. Quote Link to comment Share on other sites More sharing options...
LMS 673 Posted January 15, 2021 Share Posted January 15, 2021 I don't personally use it (we use string hooks to achieve the same), but iirc it returns a char pointer in a special managed game memory that can be fed to game functions like you do above. Quote Link to comment Share on other sites More sharing options...
atMee 1 Posted January 16, 2021 Share Posted January 16, 2021 _UIPROMPT_SET_TEXT uses text id/labels from the game, these are stored in the .yldb files. Quote Link to comment Share on other sites More sharing options...
Lambda 23 Posted January 16, 2021 Share Posted January 16, 2021 28 minutes ago, atMee said: _UIPROMPT_SET_TEXT uses text id/labels from the game, these are stored in the .yldb files. Even tho you can use labels theres no issues using your own custom strings using that native like so: UI::_UIPROMPT_SET_TEXT(promptid, GAMEPLAY::CREATE_STRING(10, "LITERAL_STRING", t_text)); Been a while since i played around with C# but you might need unmanaged code to get a char pointer to work. Quote Link to comment Share on other sites More sharing options...
atMee 1 Posted January 16, 2021 Share Posted January 16, 2021 This will not work. Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", t_text)); because using that native is literally no different than just passing the string it self. Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, t_text); _UIPROMPT_SET_TEXT is looking for a valid text label. Which is the reason why this will work. string t_text = "WARDROBE_INSPECT_PROMPT"; Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", t_text)); But this will not work string t_text = "My Custom String"; Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", t_text)); If you are going to pass a literal string, Then you must make sure that the literal string matches a valid text label. Quote Link to comment Share on other sites More sharing options...
Lambda 23 Posted January 16, 2021 Share Posted January 16, 2021 1 hour ago, atMee said: This will not work. Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", t_text)); because using that native is literally no different than just passing the string it self. Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, t_text); _UIPROMPT_SET_TEXT is looking for a valid text label. Which is the reason why this will work. string t_text = "WARDROBE_INSPECT_PROMPT"; Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", t_text)); But this will not work string t_text = "My Custom String"; Function.Call(Hash._UIPROMPT_SET_TEXT, prompt, Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", t_text)); If you are going to pass a literal string, Then you must make sure that the literal string matches a valid text label. It's like magic, almost like if used them before right? I even create them at runtime and the magic still works... Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 16, 2021 Author Share Posted January 16, 2021 So is this a matter of language difference? Is it possible that the C++ version can somehow...bypass the search of a label and takes the string input as the label content, but the C# version doesn't have that functionality? Quote Link to comment Share on other sites More sharing options...
atMee 1 Posted January 16, 2021 Share Posted January 16, 2021 (edited) It may be worth looking into the String Translator script as this script allows you to edit the Text Label strings. https://www.nexusmods.com/reddeadredemption2/mods/364 It's a bit of a workaround solution to the issue, but it's the only alternative I know. Edited January 16, 2021 by atMee Quote Link to comment Share on other sites More sharing options...
HughJanus 244 Posted January 17, 2021 Share Posted January 17, 2021 This is one hell of an enlightening thread! Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 17, 2021 Author Share Posted January 17, 2021 I tried using the _DATABINDING_ADD_DATA_STRING function to see if I can inject the strings myself, but DOES_TEXT_LABEL_EXIST always resulted in False no matter which added variable I used, but all the existing ones (like the WARDROBE ones) came out true. Looks like String Translator will have to do. Is there a way to make the transition from CLEAR_PED_TASKS smooth? Whenever I try it the ped just goes ramrod straight, or would I need an "opposite" of the task - such as making them stand up when they're sitting down? Quote Link to comment Share on other sites More sharing options...
Lambda 23 Posted January 17, 2021 Share Posted January 17, 2021 7 hours ago, Gacsam said: So is this a matter of language difference? Is it possible that the C++ version can somehow...bypass the search of a label and takes the string input as the label content, but the C# version doesn't have that functionality? No, the difference is most likely in the types. The create string both wants a char pointer in and returns a char pointer back. C# is a managed language so the support for pointers is limited thats why i suspect you would need to use unmanaged/unsafe to make it work... Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 17, 2021 Author Share Posted January 17, 2021 2 hours ago, Lambda said: No, the difference is most likely in the types. The create string both wants a char pointer in and returns a char pointer back. C# is a managed language so the support for pointers is limited thats why i suspect you would need to use unmanaged/unsafe to make it work... Well, I tried, now I get an error CS1503: cannot convert char* to Native.InputArgument, (char** if I use &testValue) so I guess that's progress? I tried converting it back to a string with CREATE_VAR_STRING but it gave me the exact same error. The line looks like this: unsafe { fixed (char* promptText = "Prompt") { Function.Call(Hash._UIPROMPT_SET_TEXT, joinPrompt, promptText); // "ACT_HUNTING_PROMPT" } } Quote Link to comment Share on other sites More sharing options...
Lambda 23 Posted January 17, 2021 Share Posted January 17, 2021 (edited) 7 minutes ago, Gacsam said: Well, I tried, now I get an error CS1503: cannot convert char* to Native.InputArgument, (char** if I use &testValue) so I guess that's progress? I tried converting it back to a string with CREATE_VAR_STRING but it gave me the exact same error. The line looks like this: unsafe { fixed (char* promptText = "Prompt") { Function.Call(Hash._UIPROMPT_SET_TEXT, joinPrompt, promptText); // "ACT_HUNTING_PROMPT" } } It needs to be literal dont pass the promptText straight to the SET_TEXT you need to use CREATE_VAR_STRING and pass the return form that into your SET_TEXT Edited January 17, 2021 by Lambda Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 17, 2021 Author Share Posted January 17, 2021 (edited) 22 minutes ago, Lambda said: It needs to be literal dont pass the promptText straight to the SET_TEXT you need to use CREATE_VAR_STRING and pass the return form that into your SET_TEXT Adding this line results in the exact same error on promptText as before, no matter if it's <char*>, <string> or anything else. Yes it's all inside unsafe{ fixed{ Function.Call<char*>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", promptText); Edited January 17, 2021 by Gacsam mentioning unsafe Quote Link to comment Share on other sites More sharing options...
Lambda 23 Posted January 17, 2021 Share Posted January 17, 2021 So what type is the Native.InputArgument? Quote Link to comment Share on other sites More sharing options...
Gacsam 0 Posted January 17, 2021 Author Share Posted January 17, 2021 45 minutes ago, Lambda said: So what type is the Native.InputArgument? I managed to get the code running by creating a new string with it but the new prompt still doesn't appear. I don't really know pointers so probably messed something up. The only information I can see about InputArgument is on the screenshot. unsafe { fixed (char* promptText = "Prompt") { string promptString = Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", new string(promptText)); Function.Call(Hash._UIPROMPT_SET_TEXT, joinPrompt, promptString); // "ACT_HUNTING_PROMPT" } } Quote Link to comment Share on other sites More sharing options...
atMee 1 Posted January 17, 2021 Share Posted January 17, 2021 51 minutes ago, Lambda said: So what type is the Native.InputArgument? This is the Native class, If you want to take a quick look over https://github.com/Saltyq/ScriptHookRDR2DotNet/blob/master/source/scripting_v3/RDR2.Native/Native.cs also, This was already reported as a bug, and quite some time ago, Only text labels seem to work https://github.com/Saltyq/ScriptHookRDR2DotNet/issues/23 Quote Link to comment Share on other sites More sharing options...
Lambda 23 Posted January 17, 2021 Share Posted January 17, 2021 (edited) You are still trying to pass a string when SET_TEXT is expecting a char pointer strings and char pointers are vastly different types, you might need to add it as an Input argument yourself unless you can marshal / use stringbuilder but without knowing the underlaying functions it's mostly guesswork.. string promptString = Function.Call<string>(Hash._CREATE_VAR_STRING, 10, "LITERAL_STRING", new string(promptText)); Edited January 17, 2021 by Lambda Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.