Accessing non static variables from a static function

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Accessing non static variables from a static function

Postby []Dot » Tue Nov 24, 2020 12:11 pm

From what I could gather around while I tried searching for a solution of my problem I am supposed to use operators (Is this the correct term?) that I need to use things like "invoker", "self" or maybe even "owner" to access variable that is not invoked from the static function itself, however it seems not to be in my case and I just get this cryptic error message that the variable is "unknown identifier", when I create a variable from the static function itself I can access it just fine. I did tried using this forum search function and using a search engine to find this particular problem but I found nothing about it.

So in this case I'm trying to access the integer variable "toggle" that is outside the "HPIc_OpenMenu()" function which as stated previously GZDoom returns it back as "unknown identifier". The Item "MT_HPICube_Item" only purpose is to call a ZScript function and do nothing else, seeing as there is no "pukenamed" equivalent for ZScript, as ideally when this function is fully implemented should open up a crafting menu.
Code: Select allExpand view
Class HPICube_Func : EventHandler
{
   bool picloaded;
   TextureID nicepic;
   bool showpic;
   int toggle;
   
// PLAY scope : collect data
override void WorldTick()   // PLAY scope
{   
   if (!picloaded)
   {
      nicepic = TexMan.CheckForTexture ("ENCEA0", TexMan.Type_Any);
      picloaded = true;
      showpic = false;
   }

   if (toggle == 1)
   {
      showpic = true;
   }
   else
   {
      showpic = false;
   }

}

// UI Scope: you cannot alter data here
override void renderOverlay(RenderEvent e)   // UI scope
{   
   if (picloaded &&showpic)
      Screen.DrawTexture(nicepic, false, 0, 0,
         DTA_KeepRatio, true, DTA_VirtualWidth, 640, DTA_VirtualHeight, 400);
}


static void HPIc_DisplayCubes(Actor self)
{
   int i0, i1;


/*   
   for (i0 = 0; i0 < 10; i0++)
   {
      for(i1 = 0; i1 < 10; i1++)
      {
         self.A_Log("A");
      }
   
   }
*/

}

static int HPIc_GetToggle(Actor self)
{
   self.A_Log("JUST toggle it.");
   
   return 0;
   //return toggle;
}



static void HPIc_OpenMenu(Actor self)
{
   int cubei, togglo;
   cubei = self.CountInv("MT_HPICube_Item");

   if (self.CountInv("MT_HPICube_Item") == 1)
   {
      //toggle = 0;
      self.A_Log("OFF");
      self.SetInventory("MT_HPICube_Item", 2);
   }
   else if (self.CountInv("MT_HPICube_Item") == 2)
   {
      //toggle = 1;
      self.A_Log("ON");
      self.SetInventory("MT_HPICube_Item", 1);   
      
      HPIc_DisplayCubes(self);
   }
   
   togglo = HPIc_GetToggle(self);
   //self.A_LogInt(toggle);
}

}


Class MT_HPICube_Item : CustomInventory
{

Default
{
//  +INVENTORY.INVBAR
  Inventory.Icon "FGRSB0";
  Inventory.PickupMessage "Picked up: HPI Cube";
  Inventory.Amount 1;
  Inventory.MaxAmount 2;
  Inventory.InterHubAmount 2;
  Tag "HPI Cube";
}
States
{
   Use:
      TNT1 A 0;
      TNT1 A 0;
      TNT1 A 0
      {
         //HPICube_Func.HPIc_OpenMenu(invoker.owner);
         CallEm(self);
      }
      Fail;
}


static void CallEm(Actor self)
{
   //self.A_Log("HUUH");
   let playa = playerpawn(self);
   if (playa == null) return;
   
   HPICube_Func.HPIc_OpenMenu(playa);
}


}
User avatar
[]Dot
 
Joined: 05 Nov 2020

Re: Accessing non static variables from a static function

Postby Player701 » Tue Nov 24, 2020 12:51 pm

You cannot use static methods to access non-static class data. Anything not marked static in a class can only be used when you have an instance of that class. However, when you call a static method, you are not using an instance. In your case, you have to remove the static qualifier from HPIc_OpenMenu and use EventHandler.Find to get an instance of your event handler. Then, call the corresponding method on that instance. Do not forget to register your event handler via MAPINFO so that the game adds an instance of it to every map.

Code: Select allExpand view
static void CallEm(Actor self)
{
    let handler = HPICube_Func(EventHandler.Find('HPICube_Func'));

    if (handler == null)
    {
        // The handler is missing for some reason. Throw an error here or simply do nothing.
    }
    else
    {
        let playa = PlayerPawn(self);

        if (playa != null)
        {
            handler.HPIc_OpenMenu(playa);
        }
    }
}

Also see: ZScript global variables: Creating global variables
User avatar
Player701
 
 
 
Joined: 13 May 2009
Location: Russia
Discord: Player701#8214
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia with Vulkan support

Re: Accessing non static variables from a static function

Postby []Dot » Tue Nov 24, 2020 1:36 pm

Player701 wrote:You cannot use static methods to access non-static class data. Anything not marked static in a class can only be used when you have an instance of that class. However, when you call a static method, you are not using an instance. In your case, you have to remove the static qualifier from HPIc_OpenMenu and use EventHandler.Find to get an instance of your event handler. Then, call the corresponding method on that instance.

Thanks for the help, and how does EventHandler.Find work can I just call it as EventHandler.Find("FUNCTION NAME");? Also does it work on class functions that are not inheriting from EventHandler? Because the name implies it only works on classes that inherits from EventHandler.

Player701 wrote:Do not forget to register your event handler via MAPINFO so that the game adds an instance of it to every map.
Also see: ZScript global variables: Creating global variables

How does GZDoom handle on wads that contain for example over 100 maps? Wouldn't it create also 100 global variables? That sounds quite excessive to me when it's only purpose is to toggling on and off the graphics. Also is it possible on ZScript to add a Getter/Setter function instead so that it doesn't rely on global variables? Sorry if I'm asking that many question, I'm quite new to this whole ZScript stuff and I almost often find myself hitting on a brick wall when I try to do something more advanced as it is not as straight forwarded writing states for Decorate and functions via ACS.
User avatar
[]Dot
 
Joined: 05 Nov 2020

Re: Accessing non static variables from a static function

Postby Player701 » Tue Nov 24, 2020 2:06 pm

[]Dot wrote:Thanks for the help, and how does EventHandler.Find work can I just call it as EventHandler.Find("FUNCTION NAME");?

EventHandler.Find takes a class name, which should obviously be a subclass of EventHandler (actually StaticEventHandler, but that's probably due to backwards-compatibility concerns). It will find an instance of the event handler of the provided type in the current map. If such instance doesn't exist (which will most likely happen if you forgot to specify the handler in your MAPINFO), null is returned instead.

Player701 wrote:How does GZDoom handle on wads that contain for example over 100 maps? Wouldn't it create also 100 global variables?

No. GZDoom does not keep every map in memory. Whenever a map is loaded, event handlers are instantiated and remain on the map until either they're destroyed manually (by calling Destroy), or the map itself is unloaded. Event handlers and their internal state is also preserved in save files, so you don't have to implement any special handling to make sure everything works properly when a save file is loaded. However, do note that OnRegister will be called again for all event handlers deserialized from a save file.
User avatar
Player701
 
 
 
Joined: 13 May 2009
Location: Russia
Discord: Player701#8214
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia with Vulkan support

Re: Accessing non static variables from a static function

Postby []Dot » Wed Nov 25, 2020 1:33 pm

Alright, here's how the current code look like, obviously not the best example though I don't know how to do it any better. it displays now a grid of cubes when its toggled on and accepts a keyconf input to move the "selected cube" around by shifting its position. I think I can pretty much work the rest on my own now since it seems it has all the basic necessity to implement a fully working crafting menu. Thanks for the help.

Code: Select allExpand view
Class HPICube_Func : EventHandler
{
   TextureID N_Cube, S_Cube;
   bool showpic;
   int toggle;
   int pos_x, pos_y;
   

override bool InputProcess (InputEvent e)
{
   if (e.Type == InputEvent.Type_KeyDown)
   {
      SendNetworkEvent("MYKEYPRESS", e.KeyScan);
      //selected += 1;
    }
   return false;
}

override void NetworkProcess(ConsoleEvent e)
{               
   HPICube_Func Event;
   Event = HPICube_Func(EventHandler.Find("HPICube_Func"));

   if (e.Name == "MYKEYPRESS")   
   {
      int key1, key2;
      [key1, key2] = Bindings.GetKeysForCommand("ab");
      if ((key1 && key1 == e.Args[0]) || (key2 && key2 == e.Args[0]))
      {   
         Event.pos_x += 2;
         
         if (Event.pos_x > (5 * 2))
         {
            if (Event.pos_y > (5 * 3))
            {
               Event.pos_y = 1;
            }
            Event.pos_x = 1;
            Event.pos_y += 2;
         }
         
         
         Console.Printf("BLINI %d %d", Event.pos_x, Event.pos_y);
      }
   }
}   
   
// PLAY scope : collect data
override void WorldTick()   // PLAY scope
{   
   //double moving = player.cmd.forwardmove;

   if (!showpic)
   {
      N_Cube = TexMan.CheckForTexture ("RURMA0", TexMan.Type_Any); //NOT SELECTED
      S_Cube = TexMan.CheckForTexture ("RUMMA0", TexMan.Type_Any); //SELECTED
      showpic = false;
      pos_x = 1;
      pos_y = 1;
   }

   if (toggle == 1)
   {
      showpic = true;
      //Console.Printf("%d", moving);   
   }
   else
   {
      showpic = false;
      pos_x = 0;
      pos_y = 0;
      //Console.Printf("%d", moving);   
   }

}

// UI Scope: you cannot alter data here
override void renderOverlay(RenderEvent e)   // UI scope
{   
   int i0, i1;
   HPICube_Func Event;
   Event = HPICube_Func(EventHandler.Find("HPICube_Func"));
      
   if (showpic)
   {
   
      for (i0 = 0; i0 < 5; i0++)
      {
         for (i1 = 0; i1 < 5; i1++)
         {
            Screen.DrawTexture(N_Cube, false, 64 * i0, 64 * i1, DTA_KeepRatio, true, DTA_VirtualWidth, 1024, DTA_VirtualHeight, 768);
                     
            
            if (Event.pos_x)
            {
               Screen.DrawTexture(S_Cube, false, 32 * Event.pos_x, 32 * Event.pos_y, DTA_KeepRatio, true, DTA_VirtualWidth, 1024, DTA_VirtualHeight, 768);
            }      
            
            
         }
      }
   }


}

static void HPIc_OpenMenu(Actor self)
{
   int cubei;
   cubei = self.CountInv("MT_HPICube_Item");
   HPICube_Func Event;
   
   Event = HPICube_Func(EventHandler.Find("HPICube_Func"));
   
   

   if (self.CountInv("MT_HPICube_Item") == 1)
   {
      Event.toggle = 0;
      self.A_Log("OFF");
      self.SetInventory("MT_HPICube_Item", 2);
      self.TakeInventory("ImCrafting", 99);
   }
   else if (self.CountInv("MT_HPICube_Item") == 2)
   {
      Event.toggle = 1;
      self.A_Log("ON");
      self.SetInventory("MT_HPICube_Item", 1);
      self.GiveInventory("ImCrafting", 99);
   }
   
   Console.Printf("%d", Event.toggle);   
}

}


Class MT_HPICube_Item : CustomInventory
{

Default
{
//  +INVENTORY.INVBAR
  Inventory.Icon "FGRSB0";
  Inventory.PickupMessage "Picked up: HPI Cube";
  Inventory.Amount 1;
  Inventory.MaxAmount 2;
  Inventory.InterHubAmount 2;
  Tag "HPI Cube";
}
States
{
   Use:
      TNT1 A 0;
      TNT1 A 0;
      TNT1 A 0
      {
         CallEm(self);
      }
      Fail;
}

static void CallEm(Actor self)
{
    let handler = HPICube_Func(EventHandler.Find('HPICube_Func'));

    if (handler == null)
    {
        // The handler is missing for some reason. Throw an error here or simply do nothing.
    }
    else
    {
        let playa = PlayerPawn(self);

        if (playa != null)
        {
            handler.HPIc_OpenMenu(playa);
        }
    }
}

}
User avatar
[]Dot
 
Joined: 05 Nov 2020


Return to Scripting

Who is online

Users browsing this forum: No registered users and 1 guest