Jump to content

Prompts - ScriptHookDotNet


Gacsam
 Share

Recommended Posts

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");

 

Link to comment
Share on other sites

  • Replies 26
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Posted Images

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?

Link to comment
Share on other sites

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 by Gacsam
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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).

Link to comment
Share on other sites

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. 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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...

prompts.jpg

Link to comment
Share on other sites

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? 

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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...

Link to comment
Share on other sites

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"
  }
}

 

Link to comment
Share on other sites

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 by Lambda
Link to comment
Share on other sites

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 by Gacsam
mentioning unsafe
Link to comment
Share on other sites

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"
                }
            }

image.png

Link to comment
Share on other sites

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
 

Link to comment
Share on other sites

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 by Lambda
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share




×
×
  • Create New...