Jump to content

Small programming questions - API


LtFlash

Recommended Posts

Ohi,

as a complete amateur in programming I need some help from you guys, more advanced in C#.

I want to have a possibility to set ECalloutProbability of my callout dynamically on basis of GameTime and an area where LocalPlayer.Ped is located. For example: Process() in the Plugin class (just like in the API example) checks if GameTime is between 8 AM and 4 PM (or LocalPlayer is in "Lower Easton"). If yes - it will set  ECalloutProbability.Always, if not - ECalloutProbability.Never (="turned off"). The problem is I have no idea how I can change it outside the target class.

I'll appreciate any help.

 

Adam

Edited by AdamP
Link to comment
Share on other sites

  • Management Team

As the probability is hardcoded in the callout, you can not change this at runtime (you could use some reflection hacks, but that's not what we want). You can however, once OnBeforeCalloutDisplayed is called, execute some additional logic to determine whether you really want the callout to happen. If not, return false so the callout won't be started. For your approach setting the probability to Always and performing a time/place check in OnBeforeCalloutDisplayed is the way to go.

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

I'll keep posting in this thread to not to spam the section.

 

I use ArrowCheckpoint. I can Delete() my arrow in any time but when I want to ensure that it's removed in End() LCPD:FR throws an exception regardless of the check:

 

if (arrApt != null)
            {
                arrApt.Delete();
            }

ArrowCheckpoint can't be checked for Exist() so I'm asking for some tip how to perform a working existence check before removing.

 

Link to comment
Share on other sites

  • Management Team

Hm all it does in Delete is deleting the internal reference, not sure that could become null. Are there any additional information, like the exception message and/or the stack trace?

 

For now, though being a dirty solution, you can wrap it into a try...catch block.

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

LCPDFR.log

[ERROR - 6:19:39 PM] [Script.CalloutManager] Error while processing callout: >>callout_name<<: Object reference not set to an instance of an object.   at LCPD_First_Response.LCPDFR.API.ArrowCheckpoint.Delete()
   at API_Example.Callouts.>>callout_name<<.End()
   at API_Example.Callouts.>>callout_name<<.Process()
   at h0.Process()
[ERROR - 6:19:39 PM] [Script.>>callout_name<<] System.NullReferenceException: Object reference not set to an instance of an object.
   at LCPD_First_Response.LCPDFR.API.ArrowCheckpoint.Delete()
   at API_Example.Callouts.>>callout_name<<.End()
   at API_Example.Callouts.>>callout_name<<.Process()
   at h0.Process()
[ERROR - 6:19:39 PM] [ExceptionHandler]  LCPD_First_Response.LCPDFR.API.ArrowCheckpoint.Delete() L_002e 
 API_Example.Callouts.>>callout_name<<.End() L_012f 
 API_Example.Callouts.>>callout_name<<.Process() L_01cf 
 h0.Process() L_022e 
Error hash: 2C4F9853ACFA1A901D82E1411D1C489462935478
[WARNING - 6:19:39 PM] [Script.CalloutManager] Failed to free callout properly: >>callout_name<<Object reference not set to an instance of an object.   at LCPD_First_Response.LCPDFR.API.ArrowCheckpoint.Delete()
   at API_Example.Callouts.>>callout_name<<.End()
   at h0.c()

My script uses it in a very simple way: just after LPlayer.LocalPlayer enters the ArrowCheckpoint it calls a proper method with callout logic + arrow.Delete(); If it goes as intended there's no problem - it's not needed to check and remove it second time BUT the problem begins when I want to protect my script from GTA/player failures -> eg. when something goes wrong I can catch it and free all resources in End() so there are no arrows left on the map etc. As I checked before try ... catch will prevent bigger fu**ups but will force-end the callout with a big msg about exception which I'd like to avoid.

 

My interpretation with help of your post is: an internal reference is removed once in callout logic and then the second time (failed attempt) in End() because there's no Exist() method for ArrowCheckpoint to ensure whether Delete() is needed;

 

I'm not in a hurry, it would be nice if I could get some resolution at all. I managed to create quite interesting scenarios in my callout(s) that require ArrowCheckpoint and I'd be glad if I could release it in some time fully working and as failure-proof as possible.

 

Edited by AdamP
Link to comment
Share on other sites

  • Management Team

Normally after you have freed a resource, you set the pointer to null. So in your case after the first call to arrow.Delete you'd do this.arrow = null;, to know it has been freed and to get NullReferenceExceptions if you use it again, so you can verify your code. This should automatically solve your problem.

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

Of course I haven't tested the most obvious way, dumb me... Doing it as you advised, LMS, helped me to get rid of my problem. Thanks again!

 

For all of you who encounter the same issue:

 

if (arrow != null)

{

    arrow.Delete();

    arrow = null;

}

Link to comment
Share on other sites

  • Management Team

No problem, great to hear it works now.

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

  • 3 weeks later...

Ohi,

that's me again with two more issues:

 

1) Is there any way to use IsKey(Still)Down() to detect a combination like [Alt]+[E]? When I use it with && operator it gives me an exception System.IndexOutOfRangeException.

2) Can PlaySound() be used to play a couple of files like PlaySoundUsingPosition()? When I use eg. PlaySound("ALL_UNITS AT_SEA", true, true) what I got is a warning that "ALL_UNITS AT_SEA" doesn't exist. With that second function there's no such problem.

Link to comment
Share on other sites

  • Management Team

1.) What did you pass to the function? Note that passing Keys.Menu might cause problems as it is not a real key. Use either LMenu or RMenu instead.

2.) They vary internally a little because the position one is more dynamic, such a behavior should not occur though. I'll try to reproduce it on my end.

 

 

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

1) My tests show that [Alt] causes the problem:

 

a)

if (Functions.IsKeyStillDown(Keys.Alt) && Functions.IsKeyDown(Keys.E))
{
    Functions.AddTextToTextwall("Alt+E");
}

gives an instant ERROR after *.dll is loaded.

 

b)

if (Functions.IsKeyStillDown(Keys.LShiftKey) && Functions.IsKeyDown(Keys.E))
{
    Functions.AddTextToTextwall("LShift+E");
}

works completely fine.

This issue is not a big deal, I can stay with [End] to force-end a callout.

 

2) This would let me use some custom radio traffic (CalloutMsg) I'm able to prepare, thx.

=========================================================================

3) One more thing I forgot about: using ped.DrawTextAboveHead() with DelayedCaller causes an exception: 

[ERROR - 4:19:33 PM] [Main] CRITICAL ERROR DURING MAINLOOP! REPORT THIS ISSUE AT LCPDFR.COM BY INCLUDING THIS LOGFILE.
[ERROR - 4:19:33 PM] [] System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
   at LCPD_First_Response.Engine.Timers.DelayedCaller.a()
   at LCPD_First_Response.Engine.Main.c()
[ERROR - 4:19:33 PM] [ExceptionHandler]  System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) L_0010 
 System.Collections.Generic.Dictionary`2+Enumerator.MoveNext() L_0000 
 LCPD_First_Response.Engine.Timers.DelayedCaller.a() L_0298 
 LCPD_First_Response.Engine.Main.c() L_009e 
Error hash: 79D9B968E4AE2D7C9300F32B3574414311789ACA

here's an example I used to reproduce the error:

LCPD_First_Response.Engine.Timers.DelayedCaller.Call(delegate
{
    ped.DrawTextAboveHead("Hello!", 2000);
}, this, 2000);

I can still use the function with Timer so you can treat it as a report, not a help request  :wink:

 

Link to comment
Share on other sites

  • Management Team

1.) Yeah the issue is as I had suspected, you pass Keys.Alt which is no real key. As the description says, it's the modifier key Menu. The LCPDFR key check implementation only supports real keys.

 

2.) Interesting, I think I saw that before. Looks like it changes the collection in the callback and it doesn't like that. Will have a look.

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

1) It works! Thanks!  :thumbsup:

It's seemed to me a little bit senseless to call Alt a "Menu" key, since it can be mismatched with the context-menu key but I reminded myself that [Alt] is/was used to focus on menu bar in older applications.

Link to comment
Share on other sites

  • 2 weeks later...
  • Management Team

Hey, I just had a look into the audio issue. The function PlaySound would call internally was limited to one action, I modified it to split sounds by " " so you should be able to play more than one sound in the next release.

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

I just had my first time with ScriptManager and gotta ask one thing: is it right that I have to put manager.Process() in Process() function of plugin, even though I set ScriptInfoAttribute. ProcessInScriptManager to true? Let's take a look at the script excerpt:

 

[ScriptInfo("script", true)]
class Script : GameScript {}
(...)
public override void Process()
{
            if (Functions.IsKeyDown(Keys.F10))
            {
                Functions.AddTextToTextwall("Attempt to call script");
                manager.StartScript<GameScript>("script");            
            }
            manager.Process();
}

if I remove the call of Process() it will run the Script only once, I wonder if it shouldn't be controlled by a manager = have it's independent ticks till I stop it.

 

Edited by LtFlash
Link to comment
Share on other sites

  • Management Team

Yes, you have to call ScriptManager.Process from your main tick. This will then tick all scripts registered to that certain manager that have ProcessInScriptManager set to true. But there is nothing that automatically calls ScriptManager.Process only because you created an instance. This is to allow you to control when you want your scripts to be processed. Those scripts that don't have it set, will require an individual call to Process, like script.Process(). This is for cases where you have to make sure scripts are executed in a certain order or you don't want certain scripts to be executed every tick but only under certain circumstances.

Please do not PM me unless really necessary (knowing you helps). If you think you need my attention in a topic, tag me.

Link to comment
Share on other sites

(...)there is nothing that automatically calls ScriptManager.Process only because you created an instance (...)

 

I evidently missed this fact when I tried to understand that. That's how you distinguish a professional from an amateur  :whistling:  Thanks!  :thumbsup:

 

@cp702: thanks, I'll try this out.

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.




×
×
  • Create New...