scripthookvdotnet / scripthookvdotnet

An ASI plugin for Grand Theft Auto V, which allows running scripts written in any .NET language on the .NET Framework runtime in-game.
https://scripthookvdotnet.github.io
zlib License
1.2k stars 631 forks source link

Manipulating other script instances from inside of script. #760

Closed racinmat closed 6 years ago

racinmat commented 6 years ago

Hi, I have a main script, which does many things, some heavy lifting, and has interval 100ms. And I have helper script, with interval=0, which just manages camera and stuff. And I need to get instance of that helper script in the main script, so I couls set som attributes there. Is it possible?

RainerHilmer commented 6 years ago

What you need is a Balking Pattern (see Wikipedia for further information). The original purpose of this pattern is to block a thread until another signals it to continue but it can easily be widened for a greater purpose.

  1. Create a static class, for example
    internal static class Mediator
    {  
    //...
    }
  2. Place internal properties for everything you need to communicate between your scripts. Example
    internal bool ConfigIsLoaded {get; set;}
  3. Now let's say you need to wait in Script2 until Script1 is done with loading the configuration before it can proceed. Code example for Script1
    private void LoadConfig()
    {
    //Code that loads the config...
    Mediator.ConfigIsLoaded = true;
    }

    Code example for Script2

    while (!Mediator.ConfigIsLoaded)
    return;
    // Do stuff which needs to wait until the config is loaded.

The great thing about a static class here is that you don't need an instance. You can call directly into the mediator. CAUTION! You have entered the realm of parallel programming. That needs special attention because it can cause a so called "race condition" and other issues you wouldn't normally think about. Please educate yourself about parallel programming. It would be way too much to explain it all here.

Another example would be the transfer of data like

   internal static class Mediator
   {
      internal static SomeDataContainer MyDataContainer {get; set;}
      // Possibly more properties.
   }

   internal class SomeDataContainer
   {
      // Add any kind of properties.

      internal bool ContentIsValid { get; set; }
   }

   public class Script1 : Script
   {
      internal void SetMyDataContainer()
      {
         Mediator.MyDataContainer.ContentIsValid = false;
         // Modify data in the container...      
         Mediator.MyDataContainer.ContentIsValid = true;
      }
   }

   public class Script2 : Script
   {
      internal void SomeMethodWhichNeedsTheDataFromTheContainer()
      {
         /* Note: Since ContentIsValid is false by default
         there will be no conflicts at initial start. */
         if(!Mediator.MyDataContainer.ContentIsValid)
         {
            // Do whatever needs to be done in this case.        
            return;
         }
         // Do stuff with Mediator.MyDataContainer...
      }
   }
racinmat commented 6 years ago

Thanks much for explaining. I thought something like static class would do. This will do perfectly for my purpose. I just thought scripthook allows me accessing list of loaded scripts, seems like it does not. I think race conditions don't bother me because from one class I will use it only for writing, and from other class, only for reading.

RainerHilmer commented 6 years ago

@racinmat 1. Have you considered if your writing script possibly executes before the values are valid? Also consider the possible extension of your mod in the future. A "Dirty" state is just a little property but can be a great help.

  1. I am glad shvdn does not allow access to other scripts. It could potentially be abused.
racinmat commented 6 years ago
  1. Yeah, I considered it, but thanks for reminder, it will definitely make the script more reusable in the future.
  2. Well, when I am programmer, I don't see any reason why I shouldn't have access to other scripts, because I am already messing with the game, and all possible abuse would be my responsibility as of someone who downloads some mod and runs it on my own PC.
RainerHilmer commented 6 years ago

What I mean is that someone could write a malicious mod which causes other mods to crash. You know trolls. I have already to deal with users who install all kind of crap and then come complaining because allegedly one of my mods doesn't work. However, I was always able to resolve their issue and it showed it was something else causing trouble (forgot a helper dll, conflicting key binding, installation error, etc.).