1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. Let your favorite entries duke it out in the 15th Techtree Contest Poll.
    Dismiss Notice
  4. Weave light to take you to your highest hopes - the 6th Special Effect Contest is here!
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

UI: OriginFrames

Discussion in 'JASS/AI Scripts Tutorials' started by Tasyen, Jun 4, 2019.

  1. Kain88

    Kain88

    Joined:
    May 26, 2020
    Messages:
    5
    Resources:
    0
    Resources:
    0
    Which frame is responsible for this?
     

    Attached Files:

    • 12.png
      12.png
      File size:
      1.2 MB
      Views:
      57
  2. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    I don't know how to access that frame directly. But one can move it by moving the parent of "SimpleInfoPanelUnitDetail". One might need to move TOPLEFT and BOTTOMRIGHT
     
  3. pr114

    pr114

    Joined:
    Mar 26, 2017
    Messages:
    116
    Resources:
    0
    Resources:
    0
    Just wanted to mention in this topic a new native that makes the above possible (as mentioned by Tasyen)

    Code (Lua):
    --Worker Button
    BlzFrameGetChild(BlzGetFrameByName("ConsoleUI", 0), 7)
     
  4. Macadamia

    Macadamia

    Joined:
    Jan 30, 2020
    Messages:
    867
    Resources:
    0
    Resources:
    0
    Thanks for updating this post with your research conducted about the 2 new UI natives.

    I don't know if I missed something while reading, but I am surprised not to find any of the messages frames on all the children you have found.
    Any chance it could be one of those you haven't managed to find out yet ?

    Still trying to access some messaging frames, like the one displaying some upgrades informations, or other specific messages that are not directly linked to the CHAT, TOP_MSG or UNIT_MSG.
     
  5. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    I have not found them, also if this frames are String we can not access them with the current behaviour of the child natives.
     
  6. Macadamia

    Macadamia

    Joined:
    Jan 30, 2020
    Messages:
    867
    Resources:
    0
    Resources:
    0
    Ok thanks for these precisions. Well let's hope we'll find ways some time - or maybe Blizzard gives us some more changes/natives to finally be able to have total control of the UI :)
     
  7. Macadamia

    Macadamia

    Joined:
    Jan 30, 2020
    Messages:
    867
    Resources:
    0
    Resources:
    0
    I have some information about a specific child frame.

    When hunting the reason for my map's crashes in multiplayer, I finally found the code responsible for it.
    My map has a hero builder, but players can buy a unique unit builder. The worker classification gives this unit an inactive worker icon.

    As you have noticed, you can access it thanks to the new BlzFrameGetChild. The inactive worker icon container is the 7th child of the Console UI. The child of this container is the icon itself, and the icon's child is the worker counter.
    To sum up, you can access the counter with
    BlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(ConsoleUI, 7), 0), 0)

    This frame (the counter) only exists after a first worker is created in the map.

    So what I did is create a global boolean variable called FirstHealer, set to true at map init.

    If the boolean is true once a first player buys a worker, it is set to false to prevent redundancy, and then a one time 0.5s timer is started (just for security, it seems that trying to access this frame immediately causes issues).
    Once the timer expires, I move the worker counter off screen with the command :
    BlzFrameSetAbsPoint(fBlzFrameGetChild(BlzFrameGetChild(BlzFrameGetChild(ConsoleUI, 7), 0), 0), FRAMEPOINT_BOTTOM, 0.0, -0.6)


    This works perfectly... in single player.

    In multiplayer, doing this crashes all other player's (that don't have a worker icon) game.
    I tried changing the counter's frame position in the local player context only, with identical results.

    I didn't try to hide the frame because it would be useless : if it is hidden, it reappears everytime the worker becomes idle again.
    I tried most of the other natives to try to move or hide this frame out of visibility, but so far all my alternative attempts have not been able to prevent the crashes.

    For the moment I am still trying to find a way to render this counter invisible, but it seems impossible, at least for the moment, except in single player of course.

    So I would strongly advise everyone not to try to hide this counter unless a method is found that would prevent other clients from crashing.


    EDIT :
    I made an attempt to get this to work by creating a dummy worker for all players referenced in my map, and this includes the computer controlled player, and even the neutral passive one.
    The attempt to move the Inactive Worker icon counter off screen unfortunately still crashed most clients.
     
    Last edited: Jul 5, 2020
  8. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    Someone asked me privatly, if one could move the UnitInfo-Hover Frame to a fixed position on the screen. The answer is yes, and it should be public common knowlage hence I write that here.

    The UnitInfo-Hover Frame is the child at index 8 of ConsoleUI, but it does not exist until any world object is hovered with the mouse.
    Hence my solution is that one starts a periodic timer and checks the child count of ConsoleUI, when it becomes bigger than 8 one moves the Child Frame at index 8. (fails if one creates SimpleFrames as children of ConsoleUI, but creating them for GAMEUI is no problem)
    The Frame has to be moved using all 4 Corner points to the wanted position on screen (3 would also be enough but one has to make sure that the frame is limited at top, Left, Bottom and right).

    Could look like that in Lua
    Desync

    Code (Lua):
    SomeTimer = CreateTimer()
    TimerStart(SomeTimer, 0, false, function()
        local parent = BlzGetFrameByName("ConsoleUI", 0)
        TimerStart(SomeTimer, 0.01, true, function()
            if BlzFrameGetChildrenCount(parent) > 8 then
                local frame = BlzFrameGetChild(parent, 8)
                --BlzFrameClearAllPoints(frame)
                BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOPLEFT, 0.6, 0.25)
                BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOPRIGHT, 0.8, 0.25)
                BlzFrameSetAbsPoint(frame, FRAMEPOINT_BOTTOMRIGHT, 0.8, 0.2)
                BlzFrameSetAbsPoint(frame, FRAMEPOINT_BOTTOMLEFT, 0.6, 0.2)
                PauseTimer(SomeTimer)
                DestroyTimer(SomeTimer)
                SomeTimer = nil
            end
        end)
    end)

    A weakness of this is, that after the moving the unitInfo-Frame will not change it's size anymore.

    I only tested that in single player.
     
    Last edited: Jul 9, 2020
  9. Macadamia

    Macadamia

    Joined:
    Jan 30, 2020
    Messages:
    867
    Resources:
    0
    Resources:
    0
    Thanks, this is some really interesting information !
    I guess we could use the same method for some other frames that do not exist yet at Map Init.

    As for multiplayer, I suppose it only depends if the UnitInfo-Hover existence is synced by the game engine.
    If it is not, the children count will return an async value.

    In such circumstance, we'd have two options :
    - check the children count locally and move the frame accordingly
    - use a second timer with a long enough arbitrary duration to stop and destroy the "SomeTimer" timer.

    If the children count is async, i don't know if pausing the timer will desync, but its destruction definitely will.

    Note :
    you don't need to nil the Timer, it has no effect. Only exception is if you'd need to test if it is nil immediately, as the reference does not disappear immediately but after a very very short duration.
     
  10. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    I now did a Lan test with running the game twice. As soon any player hovered an world object it desyncs.
    After that I removed all actions inside the inner timer except for GetChildCount > 8 and BlzFrameGetChild. It still desyncs.

    It is async, and it desyncs with using BlzFrameGetChild(parent, 8). Even when not touching the timer or the ChildFrame's values at all.

    Unsure how to solve that without to much effort.

    Maybe it would be smarter to force an world object hover and then do the actions.
    Or one would have to setup an sync trigger which checks for the amount of player that hovered yet, but that sounds like much effort.
     
    Last edited: Jul 8, 2020
  11. Macadamia

    Macadamia

    Joined:
    Jan 30, 2020
    Messages:
    867
    Resources:
    0
    Resources:
    0
    I will let you post the solution you came up with when we discussed this on Discord.

    This will definitely help everyone that wants to give that frame a fixed position.
    I might even consider using it in my current map or my next project.

    Thanks for your hard work !
     
  12. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    The hover frame is created local only and if it is then refered in code the game will desync for all players not having it created yet.
    Hence each player will sent a Sync message telling the others he has created it. Inside the SyncTrigger when all players created it, the frame will be moved.
    Code (Lua):
    SomeTimer = CreateTimer()
    TimerStart(SomeTimer, 0, false, function()
        local parent = BlzGetFrameByName("ConsoleUI", 0)
        local done = false
        local force = CreateForce()
        local trigger = CreateTrigger()
        for index = 0, bj_MAX_PLAYERS-1 do BlzTriggerRegisterPlayerSyncEvent(trigger, Player(index), "HoverDetect", false) end
        TriggerAddAction(trigger, function()
            ForceAddPlayer(force, GetTriggerPlayer())
            local player
            for index = 0, bj_MAX_PLAYERS-1 do
                player = Player(index)
                if GetPlayerSlotState(player) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(player) == MAP_CONTROL_USER and not IsPlayerInForce(player, force) then
                    return false
                end
            end
            print("move")
            local frame = BlzFrameGetChild(parent, 8)
            BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOPLEFT, 0.6, 0.25)
            BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOPRIGHT, 0.8, 0.25)
            BlzFrameSetAbsPoint(frame, FRAMEPOINT_BOTTOMRIGHT, 0.8, 0.2)
            BlzFrameSetAbsPoint(frame, FRAMEPOINT_BOTTOMLEFT, 0.6, 0.2)

            PauseTimer(SomeTimer)
            DestroyTimer(SomeTimer)
            DestroyTrigger(trigger)
            DestroyForce(force)
            SomeTimer = nil
        end)

        TimerStart(SomeTimer, 0.01, true, function()
            if BlzFrameGetChildrenCount(parent) > 8 and not done then
                done = true
                print("hovered")
                BlzSendSyncData("HoverDetect", "true")
            end
        end)
    end)

     
     
    Last edited: Jul 9, 2020
  13. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    It seems like the 4:3 Screen Limition for Frames can be avoided by creating them as child/offspring of ("ConsoleUIBackdrop", 0). ("ConsoleUIBackdrop", 0) does only exist in Reforged.

    The custom Frame does not have to be a direct Child it also can be a child's child of ("ConsoleUIBackdrop", 0).

    But by using that the Frame drops Layerwise below default SimpleFrames.
    One also has to get rid of the blackbox ("ConsoleUIBackdrop", 0) in a different manner when one use it as parent. Hiding it is in that case no option.

    It also can be used to move for example the minimap out of the 4:3 Screen like shown in the Lua code following:
    one swaps the parent of the Minimap to ConsoleUIBackdrop then one sets the position
    Code (Lua):
    TimerStart(CreateTimer(), 0, false, function()
        local parent = BlzGetFrameByName("ConsoleUIBackdrop", 0)
        local frame = BlzGetFrameByName("MiniMapFrame", 0)
        BlzFrameSetParent(frame, parent)
         BlzFrameSetAbsPoint(frame, FRAMEPOINT_BOTTOMLEFT, 0.9, 0.3)
         BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOPRIGHT, 1.05, 0.45)
     end)
    Minimap moved.jpg
     
    Last edited: Jul 13, 2020
  14. pr114

    pr114

    Joined:
    Mar 26, 2017
    Messages:
    116
    Resources:
    0
    Resources:
    0
    Thanks for sharing, this greatly helped my UI :)
     
  15. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    I searched for other such Frames that can leave the 4:3 Screen which also exist in 1.31.1.
    Now that I think about it there are 3 Frames that can Leave the 4:3 Screen, when starting the map with 16:9 they are pushed to the top right outside of 4:3.
    I talk about Multiboard, TimerDialog and LeaderBoard.


    Unlike "ConsoleUIBackdrop" they do not exist until one creates them with the none frame creater api. They are also above SimpleFrames.
    After they are created one can get the frame handling them by name. I recomment either LeaderBoard or MultiBoard. TimerDialog has a complex/wierd CreateContext usage, the other two are much simpler. LeaderBoard or Multiboard always use createContext 0.

    Anyway I suggest LeaderBoard.
    it would be TimerDialog, but TimerDialog has wierd behaviours. I also encountered a bug when I used BlzGetFrameByName("TimerDialog", 0) as parent, when I used restart map the custom Frame was not shown anymore.​

    A Lua example to spawn a ScriptDialogButton right to the command buttons.
    Code (Lua):
    TimerStart(CreateTimer(), 0, false, function()
        CreateLeaderboardBJ(bj_FORCE_ALL_PLAYERS, "title")
        local parent = BlzGetFrameByName("Leaderboard", 0)
        BlzFrameSetSize(parent, 0, 0)
        BlzFrameSetVisible(BlzGetFrameByName("LeaderboardBackdrop", 0), false)
        BlzFrameSetVisible(BlzGetFrameByName("LeaderboardTitle", 0), false)

        local button1 = BlzCreateFrameByType("GLUETEXTBUTTON", "name", parent, "ScriptDialogButton", 0)
     
        BlzFrameSetAbsPoint(button1, FRAMEPOINT_LEFT , 0.85, 0.1)
    end)
     
    First one creates the LeaderBoard with the normal api. Then one gets the new frame sets the size to 0 to make the screen space it takes clickable for the playable-world. Then one hides the Title and Backdrop Frame (to fix a grafic glitch). After that one uses it as parent of the Frame.
    If one wants to use LeaderBoards, one has to save the parentFrame in a global and has to show it with BlzFrameSetVisible after the other was shown.
     
  16. Macadamia

    Macadamia

    Joined:
    Jan 30, 2020
    Messages:
    867
    Resources:
    0
    Resources:
    0
    Thank you for your research.

    This is another really amazing possibility that might allow quite a few things and be easier to handle without side effects than the ConsoleUI Backdrop !
     
  17. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,991
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    It it possible to get Frame events of nonsimple Frames created outside the 4:3 bounds that way?
     
  18. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    Yes that way, one can place Frames outside of 4:3 and they can evoke Frameevents and have Tooltips from there.
     
  19. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,991
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    I tried the test example you posted, but it seemed to block all interactions with the game. Do I have to manually reset focus?
    Or is it because I use a universal world frame?
    Code (vJASS):

        local framehandle f = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_WORLD_FRAME, 0),"", 0)
       call BlzFrameSetAllPoints(f, BlzGetOriginFrame(ORIGIN_FRAME_WORLD_FRAME, 0))

    How would a simple snippet creating a basic invisible frame anywhere on the screen that fires mouse_enter, mouse_leave and click events look like?
     
  20. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,557
    Resources:
    18
    Tools:
    2
    Maps:
    3
    Spells:
    8
    Tutorials:
    4
    JASS:
    1
    Resources:
    18
    "FRAME" does not support any Frameevent, still catches the mouseinput on the screenspace controlled by it (here the frame screen space control logic is explained to some degree).
    An empty "BUTTON" is invisibile still supports many Frameevents.

    an invisible only 4:3 Button could look like this in Lua:
    Code (Lua):
    TimerStart(CreateTimer(), 0, false, function()
        local button = BlzCreateFrameByType("BUTTON", "someButtonFrame", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
        local trigger = CreateTrigger()

        BlzFrameSetAbsPoint(button, FRAMEPOINT_CENTER, 0.4, 0.3)
        BlzFrameSetSize(button, 0.2, 0.2)
     
        BlzTriggerRegisterFrameEvent(trigger, button, FRAMEEVENT_CONTROL_CLICK)
        BlzTriggerRegisterFrameEvent(trigger, button, FRAMEEVENT_MOUSE_ENTER)
        BlzTriggerRegisterFrameEvent(trigger, button, FRAMEEVENT_MOUSE_LEAVE)

        TriggerAddAction(trigger, function()
            if BlzGetTriggerFrameEvent() == FRAMEEVENT_CONTROL_CLICK then
                print("Click")
                BlzFrameSetVisible(BlzGetTriggerFrame(), false)
                BlzFrameSetVisible(BlzGetTriggerFrame(), true)
            elseif BlzGetTriggerFrameEvent() == FRAMEEVENT_MOUSE_ENTER then
                print("Enter")
            elseif BlzGetTriggerFrameEvent() == FRAMEEVENT_MOUSE_LEAVE then
                print("Leave")
            end
        end)
    end)
    when you want that also out of the 4:3 one has to change the parent of the BUTTON.