[Fixed] Weird Crash with ZForms

Bugs that have been investigated and resolved somehow.

Moderator: GZDoom Developers

Weird Crash with ZForms

Postby IvanDobrovski » Thu Aug 27, 2020 12:20 pm

I wanted to add a simple menu to my mod using ZForms and I based it off of PDA Starter Kit by Nash to understand how the library worked a bit. I somehow seem to get crashes when I spam click a bunch of buttons on my list populated by player's weapons. For some reason my condensed version where it just has the menu doesn't crash at all, but when the same code is ran with my mod it does and I really can't figure it out. I'm putting the crash report in hopes of someone making some sense of why the crash is happening, as me simply commenting parts of mod didn't get much information. I only know that once there are no buttons or labels to click on it no longer crashes.

Relevant piece of menu code:

Code: Select allExpand view
class Trinity_UpgradeMenu : Trinity_ZFGenericMenu {
   const BASE_WIDTH = 800;
   const BASE_HEIGHT = 600;

   Color UIColor;
   int menuFontColor;

   Trinity_MenuHandler mHandler;
   Font menuFont;
   Trinity_Player pRef;
   
   Trinity_OwnedWeaponsList wepList;
   
   override void Init(Menu parent) {
        Super.Init(parent);

      pRef = Trinity_Player(players[consoleplayer].mo);

      // Set menu resolution
        SetBaseResolution((BASE_WIDTH, BASE_HEIGHT));

      // Set menu font
        menuFont = Font.GetFont("TRFONT");

      // Customize UI colours
      UIColor = Color(118, 118, 206);
      menuFontColor = Font.CR_LightBlue;
      //pdaListUnreadColor = Font.CR_LightBlue;
      //pdaListReadColor =  Font.CR_Black;

      // Assign the MenuHandler
        mHandler = new('Trinity_MenuHandler');
        mHandler.menu = self;

      // Create the background
      let backgroundPos = (0, 0);
      let backgroundSize = (BASE_WIDTH, BASE_HEIGHT);
        let background = new('Trinity_ZFImage').Init(backgroundPos, backgroundSize, "graphics/UpgradeMenu/UpgradeMenuBack.png", Trinity_ZFImage.AlignType_Center);
        background.Pack(mainFrame);

      // Create the weapon list
      let wepListPos = (96, 84);
      let wepListSize = (128, 128);
      wepList = Trinity_OwnedWeaponsList(new('Trinity_OwnedWeaponsList').Init(wepListPos, wepListSize, self, "on_WeaponSelect"));
      
      // fill the list of owned weapons
      fillWeaponList();
   }

   override void Ticker(void) {
      if (!pRef) {
         Close();
         return;
      }
      Super.Ticker();
   }

   override void OnDestroy(void) {
      PlayerInfo p = players[consoleplayer];
      if (pRef && p && players[consoleplayer].mo) {
         // Stop any PDA sounds currently playing when exiting the menu
         /*let pdaReader = pmo.FindInventory("PDAReader", true);
         if (pdaReader && pmo == players[consoleplayer].mo)
         {
            EventHandler.SendNetworkEvent("EV_StopPDASound");
         }*/
      }

      Super.OnDestroy();
   }

   //===========================================================================
   //
   //
   //
   //
   //===========================================================================

   void fillWeaponList(void) {
      // Build array of PDAs
      Array<Inventory> weps;
      
      for (Inventory item = pRef.Inv; item != NULL; item = item.Inv) {
         if (item is "Trinity_Weapon" && !(item is "Trinity_Fist"))
            weps.Push(item);
      }

      // Add the PDAs to the PDA list
      for (int i = 0; i < weps.Size(); i++) {
         if (weps[i]) {
            wepList.AddLine(weps[i].GetClassName());
         }
      }
   }

   int GetFontHeight(void) {
      if (!menuFont)
         return 0;
      return menuFont.GetHeight();
   }
}

class Trinity_MenuHandler : Trinity_ZFHandler {
   Trinity_UpgradeMenu menu;
   
   override void ButtonClickCommand(Trinity_ZFButton caller, String command) {
      if (!menu)
         return;
      //if (!menu.pdaContentText || !menu.pdaContentBackground) return;

      // Parse the command -- index 0 holds cmd label index 1 holds label from which it came from
      Array<String> strings;
      command.Split(strings, ":");

      // Return if the array has less than 2 strings
      if (strings.Size() < 2)
         return;

      if ((strings[0] ~== "on_WeaponSelect")) {
         console.printf(strings[0] .. " " .. strings[1]);
         // mark as read
         /*let pda = PDA(menu.pmo.FindInventory(strings[1], true));
         if (pda)
         {
            EventHandler.SendNetworkEvent("EV_MarkPDARead:" .. strings[1]);
         }

         class<PDA> cls = strings[1];
         String txt = GetDefaultByType((class<PDA>)(cls)).pdaText;
         String pdaText = StringTable.Localize(txt);

         // Update content image and text
         menu.pdaContentBackground.image = GetDefaultByType((class<PDA>)(cls)).pdaImage;
         menu.pdaContentText.SetText(pdaText);

         // Play sound if available
         Sound snd = GetDefaultByType((class<PDA>)(cls)).pdaAudio;
         if (snd)
         {
            // Find the PDA reader and play the sound from it (lol hack)
            let pdaReader = menu.pmo.FindInventory("PDAReader", true);
            if (pdaReader && menu.pmo == players[consoleplayer].mo)
            {
               pdaReader.A_StartSound(snd, CHAN_VOICE, CHANF_UI, snd_menuvolume, ATTN_NONE);
            }
         }
         else
         {
            // Stop all sounds when clicking on a soundless PDA
            EventHandler.SendNetworkEvent("EV_StopPDASound");
         }*/
      }
   }
}


Code: Select allExpand view
//===========================================================================
//
//
// // Colorizable Frame
//
//===========================================================================

class Trinity_ColoredFrame : Trinity_ZFFrame {
   Color fillColor;
   override void Drawer(void) {
      Super.Drawer();
      Fill((0, 0), box.size, fillColor, 1.0);
   }
}

//===========================================================================
//
//
// Colorizable Button
//
//===========================================================================

class Trinity_ColoredButton : Trinity_ZFButton {
   Color fillColor;
   override void Drawer(void) {
      Super.Drawer();

      if (curButtonState == ButtonState_Hover) {
         Fill((0, 0), box.size, fillColor, 1.0);
      }
   }
}

class Trinity_ScrollableFrame : Trinity_ZFFrame {
   // Reference to the menu is needed for fonts, colours, things like that
   Trinity_UpgradeMenu parentMenu;

   // The content frame is dynamically moved and resized
   Trinity_ZFFrame content;

   const SCROLLBAR_WIDTH = 4;
   Trinity_ColoredFrame scrollbarTrack;
   Trinity_ColoredFrame scrollbar;

   int mouseX;
   int mouseY;

   //===========================================================================
   //
   //
   //
   //===========================================================================

   Trinity_ScrollableFrame Init(Vector2 pos, Vector2 size, Trinity_UpgradeMenu mnu) {
      parentMenu = mnu;

      let f = Trinity_ScrollableFrame(Super.Init(pos, size));
      f.Pack(parentMenu.mainFrame);

      // Initial Y size of content frame is 0 because it will be resized as new items are added
      content = Trinity_ZFFrame(new('Trinity_ZFFrame').Init((0, 0), (size.X, 0)));
      content.Pack(f);

      // Create the scrollbar element, Y size also resized dynamically
      scrollbarTrack = Trinity_ColoredFrame(new('Trinity_ColoredFrame').Init((size.X - SCROLLBAR_WIDTH, 0), (SCROLLBAR_WIDTH, size.Y)));
      scrollbarTrack.fillColor = Color(parentMenu.UIColor.R / 2, parentMenu.UIColor.G / 2, parentMenu.UIColor.B / 2);
      scrollbarTrack.pack(f);

      scrollbar = Trinity_ColoredFrame(new('Trinity_ColoredFrame').Init((size.X - SCROLLBAR_WIDTH, 0), (SCROLLBAR_WIDTH, 0)));
      scrollbar.fillColor = parentMenu.UIColor;
      scrollbar.pack(f);

      return f;
   }

   //===========================================================================
   //
   //
   //
   //===========================================================================

   override void OnUIEvent(Trinity_ZFUiEvent ev) {
      Super.OnUIEvent(ev);

      if (!content)
         return;

      if (ev.Type == UIEvent.Type_MouseMove) {
         mouseX = ev.mouseX;
         mouseY = ev.mouseY;
      }

      if (IsEnabled() && BoxToScreen().PointCollides((mouseX, mouseY))) {
         // Mousewheel scrolling
         int scrollAmount = 5;
         if (ev.Type == UIEvent.Type_WheelUp && content.box.pos.Y < 0) {
            content.box.pos.Y += (parentMenu.GetFontHeight() * scrollAmount);
            ClampContentPos();

         }
         else if (ev.Type == UIEvent.Type_WheelDown && content.box.pos.Y > GetLowestPos()) {
            content.box.pos.Y -= (parentMenu.GetFontHeight() * scrollAmount);
            ClampContentPos();
         }
      }
   }

   override void Drawer(void) {
      Super.Drawer();

      // Show scroll bar if content is long enough
      if (GetMaxLines() > GetMaxShowableLines()) {
         scrollbar.disabled = false;
         scrollbar.hidden = false;

         // Update the scrollbar
         double scrollbarFrameHeight = box.size.Y;
         double scrollbarContentHeight = content.box.size.Y;
         double scrollbarRatio = scrollbarFrameHeight / scrollbarContentHeight;
         double scrollBarArea = scrollbarFrameHeight;// - scrollbarArrowHeight * 2;
         double scrollbarHeight = scrollBarArea * scrollbarRatio;
         double scrollBarY = -(content.box.pos.Y * scrollbarRatio);

         scrollbar.box.size.Y = scrollbarHeight;
         scrollbar.box.pos.Y = scrollBarY;
      }
      else {
         scrollbar.disabled = true;
         scrollbar.hidden = true;
      }
   }

   //===========================================================================
   //
   //
   //
   //===========================================================================

   // This is made overridable because different widgets may have different ways
   // of keeping track of a content's length.
   virtual int GetMaxLines(void) { return 0; }

   int GetMaxShowableLines(void) {
      return int(box.size.Y / parentMenu.GetFontHeight());
   }

   //===========================================================================
   //
   //
   //
   //===========================================================================

   int GetLowestPos(void) {
      return -(parentMenu.GetFontHeight() * (GetMaxLines() - GetMaxShowableLines()));
   }

   void ClampContentPos(void) {
      if (content.box.pos.Y > 0)
         content.box.pos.Y = 0;
      else if (content.box.pos.Y < GetLowestPos())
         content.box.pos.Y = GetLowestPos();
   }
}

//===========================================================================
//
//
// A scrollable frame with clickable items
//
//===========================================================================

class Trinity_ClickableList : Trinity_ScrollableFrame {
   // Command name to send to the handler when an item is clicked
   String cmdName;

   // Increases every time a new item is added to the list
   int currentLineYPos;

   //===========================================================================
   //
   //
   //
   //===========================================================================

   Trinity_ClickableList Init(Vector2 pos, Vector2 size, Trinity_UpgradeMenu mnu, String cmd) {
      let f = Trinity_ClickableList(Super.Init(pos, size, mnu));
      cmdName = cmd;
      return f;
   }

   //===========================================================================
   //
   //
   //
   //===========================================================================

   override int GetMaxLines(void) {
      return int(currentLineYPos / parentMenu.GetFontHeight());
   }

   //===========================================================================
   //
   //
   //
   //===========================================================================

   virtual void AddLine(String newItem) {
      if (!content)
         return;

      class<Actor> cls = newItem;
      String newItemTitle = GetDefaultByType((class<Actor>)(cls)).GetTag();

      // Buttons and text have to be separate because
      // button text is automatically center-aligned >_<

      // Button element
      let btn = Trinity_ColoredButton(
         new('Trinity_ColoredButton').Init
         (
            (0, currentLineYPos),
            (box.size.X - SCROLLBAR_WIDTH, parentMenu.GetFontHeight()),
            cmdHandler: parentMenu.mHandler,
            command: cmdName .. ":" .. newItem
         )
      );
      btn.SetTexture
      (
         "TNT1A0",
         "TNT1A0",
         "TNT1A0",
         "TNT1A0"
      );
      btn.fillColor = parentMenu.UIColor;
      btn.Pack(content);

      // Text element
      let txt = new('Trinity_ZFLabel').Init
      (
         (0, currentLineYPos),
         (0, 0),
         text: newItemTitle,
         fnt: parentMenu.menuFont,
         wrap: false,
         autoSize: true,
         textColor: parentMenu.menuFontColor
      );
      txt.Pack(content);

      // Increase the Y size of the content frame
      content.box.size.Y += parentMenu.GetFontHeight();

      // Increase Y position of the next item to add
      currentLineYPos += parentMenu.GetFontHeight();
   }
}

//===========================================================================
//
//
// A subclass of ClickableList with a special label specific to owned weapons
//
//===========================================================================

class Trinity_OwnedWeaponsList: Trinity_ClickableList {
   override void AddLine(String newItem) {
      if (!content)
         return;

      class<Actor> cls = newItem;
      String newItemTitle = GetDefaultByType((class<Actor>)(cls)).GetTag();

      // Buttons and text have to be separate because
      // button text is automatically center-aligned >_<

      // Button element
      let btn = Trinity_ColoredButton
      (
         new('Trinity_ColoredButton').Init
         (
            (0, currentLineYPos),
            (box.size.X - SCROLLBAR_WIDTH, parentMenu.GetFontHeight()),
            cmdHandler: parentMenu.mHandler,
            command: cmdName .. ":" .. newItem
         )
      );
      // void setTexture(string inactive, string hover, string click, string disabled)
      btn.SetTexture
      (
         "TNT1A0",
         "TNT1A0",
         "TNT1A0",
         "TNT1A0"
      );
      btn.fillColor = parentMenu.UIColor;
      btn.Pack(content);

      // Text element
      let txt = new('Trinity_OwnedWeaponLabel').Init
      (
         (0, currentLineYPos),
         (0, 0),
         text: newItemTitle,
         fnt: parentMenu.menuFont,
         wrap: false,
         autoSize: true,
         textColor: parentMenu.menuFontColor
      );
      class<Trinity_Weapon> w = newItem;
      Trinity_OwnedWeaponLabel(txt).wep = w;
      Trinity_OwnedWeaponLabel(txt).parentMenu = parentMenu;
      txt.Pack(content);

      // Increase the Y size of the content frame
      content.box.size.Y += parentMenu.GetFontHeight();

      // Increase Y position of the next item to add
      currentLineYPos += parentMenu.GetFontHeight();
   }
}


//===========================================================================
//
//
// A subclass of Label that holds a reference to the owned weapon class
// Used to show different color when it has upgrade and is read / unread
//
//===========================================================================

class Trinity_OwnedWeaponLabel : Trinity_ZFLabel {
   Trinity_UpgradeMenu parentMenu;
   class<Trinity_Weapon> wep;

   /*override void Drawer(void) {
      let pmo = players[consoleplayer].mo;
      if (pmo) {
         // Get read/unread status
         let pdainv = Trinity_Weapon(pmo.FindInventory(wep, true));
         if (pdainv)
            textColor = pdainv.isRead ? parentMenu.pdaListReadColor : parentMenu.pdaListUnreadColor;
         Super.Drawer();
      }
      else
         Console.Printf("Label can't find Player MO (shouldn't happen)!");
   }*/
}
You do not have the required permissions to view the files attached to this post.
User avatar
IvanDobrovski
 
Joined: 08 Aug 2016

Re: Weird Crash with ZForms

Postby _mental_ » Thu Aug 27, 2020 12:50 pm

Please post a runnable sample along with all steps necessary to reproduce this crash.
_mental_
 
 
 
Joined: 07 Aug 2011

Re: Weird Crash with ZForms

Postby IvanDobrovski » Thu Aug 27, 2020 1:08 pm

Load the pk3 and go to console, put "give all; netevent giveupgrades". Then press "U". Once you're in the menu just spam click a bunch of the elements on the list, and areas above or below them including empty areas. It'll crash sooner or later.

A new crash report is here because I added some debug text.
You do not have the required permissions to view the files attached to this post.
User avatar
IvanDobrovski
 
Joined: 08 Aug 2016

Re: Weird Crash with ZForms

Postby _mental_ » Fri Aug 28, 2020 12:32 am

Please share the sample without Google sing-in requirement.
_mental_
 
 
 
Joined: 07 Aug 2011

Re: Weird Crash with ZForms

Postby IvanDobrovski » Fri Aug 28, 2020 1:44 am

Here: https://easyupload.io/svbwn3

Update: It crashes without even having to do anything on the menu it seems. I waited to see if it'd crash and I kept hovering over one of the list elements. I didn't move the mouse after hovering and kept it hovering for a good 10 seconds and it crashed itself.
User avatar
IvanDobrovski
 
Joined: 08 Aug 2016

Re: Weird Crash with ZForms

Postby IvanDobrovski » Fri Aug 28, 2020 1:32 pm

I'll bump this as this is a bit of an important finding. The dev build g4.5pre-109-geaba63e13 actually fixes my problem. I had a small conversation today with leodoom85, he told me there is a known memory leak issue with 4.4.2 and as per his suggestion I used the dev build instead of 4.4.2. No more crashes. Should I make a bug report about this or is this a known issue?

EDIT: Nevermind it crashes there too after a bit. The report of the crash from the dev build mentioned is attached. This crash is somewhat mysterious in that when I launch the mod it just sometimes won't crash at all no matter what I do in the menu. But sometimes it immediately crashes on the menu within the span of 15 seconds... No idea what causes it.
You do not have the required permissions to view the files attached to this post.
User avatar
IvanDobrovski
 
Joined: 08 Aug 2016

Re: Weird Crash with ZForms

Postby _mental_ » Sat Aug 29, 2020 4:18 am

_mental_
 
 
 
Joined: 07 Aug 2011


Return to Closed Bugs

Who is online

Users browsing this forum: No registered users and 0 guests