- Joined
- Jul 18, 2010
- Messages
- 2,377
Introduction
Currently none of the versions of warcraft 3 that have access to the UI-Frame natives do probably Save&Load the usage of Frames/TOC (this was written when 1.32.8 /1.32.9 PTR were the current Versions).
This broken Save&Load stops Frames from being recreaterd/modified when the Game is Loaded (but they still hold their handleIds). It is even worser as it sounds, when one uses a variable reference of such a now broken Frame then the game can crash.
As mapper one could fix it without Blizzard fixing the Save&Load for Frames.
This broken Save&Load stops Frames from being recreaterd/modified when the Game is Loaded (but they still hold their handleIds). It is even worser as it sounds, when one uses a variable reference of such a now broken Frame then the game can crash.
As mapper one could fix it without Blizzard fixing the Save&Load for Frames.
How to fix it
The idea is simple. We just let the old broken Frames leak (can't do much about it anyway) and repeat every frame creation/modification after a 0s timer run in a trigger with a Game was Loaded Event. With that all references should be updated and the custom UI does continue to work. Also be aware that you also have to restore any counters being used in the Frame creation and that you have to repeat the TOC-Loading. This works cleaner and better when your Frame creation/modification function doesn't do anything else then TOC and Frames.
One could write a ReLoader with that Game is Loaded Event that runs all the UI-Frame Init Functions.
In Lua one would have array of functions. But in vjass a trigger to which you add all the functions that have to be repeated after loading the game.
One could write a ReLoader with that Game is Loaded Event that runs all the UI-Frame Init Functions.
In Lua one would have array of functions. But in vjass a trigger to which you add all the functions that have to be repeated after loading the game.
Code Example
The crash code Example, it just creates a button at the center of the screen at 0s and makes it visible once a second. After the game was Saved & Loaded. The game will crash as soon the game tries to make the frame visible.
This are a Lua and vjass example of the above described "reloading".
First the reloader:
Second the example: This takes the first Hero Button and moves it to the center of the screen.
Second the example: This takes the first Hero Button and moves it to the center of the screen.
Lua:
do
local frame
local real = MarkGameStarted
function MarkGameStarted()
real()
frame = BlzCreateFrame("ScriptDialogButton", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
BlzFrameSetAbsPoint(frame, FRAMEPOINT_CENTER, 0.4, 0.3)
TimerStart(CreateTimer(), 1, true, function()
BlzFrameSetVisible(frame, true)
end)
end
end
Lua
vjass
First the reloader:
Lua:
-- in 1.31 and upto 1.32.9 PTR (when I wrote this). Frames are not correctly saved and loaded, breaking the game.
-- This runs all functions added to it with a 0s delay after the game was loaded.
do
local data = {}
local real = MarkGameStarted
local timer
function FrameLoaderAdd(func)
table.insert(data, func)
end
function MarkGameStarted()
real()
local trigger = CreateTrigger()
timer = CreateTimer()
TriggerRegisterGameEvent(trigger, EVENT_GAME_LOADED)
TriggerAddAction(trigger, function()
TimerStart(timer, 0, false, function()
for _,v in ipairs(data) do v() end
end)
end)
end
end
Lua:
do
local real = MarkGameStarted
local function Init()
BlzEnableUIAutoPosition(false)
local frame = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 0)
BlzFrameClearAllPoints(frame)
BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOPLEFT, 0.4, 0.3)
end
function MarkGameStarted()
real()
Init()
if FrameLoaderAdd then FrameLoaderAdd(Init) end
end
end
JASS:
library FrameLoader initializer init_function
// in 1.31 and upto 1.32.9 PTR (when I wrote this). Frames are not correctly saved and loaded, breaking the game.
// This library runs all functions added to it with a 0s delay after the game was loaded.
// function FrameLoaderAdd takes code func returns nothing
// func runs when the game is loaded.
globals
private trigger eventTrigger = CreateTrigger()
private trigger actionTrigger = CreateTrigger()
private timer t = CreateTimer()
endglobals
function FrameLoaderAdd takes code func returns nothing
call TriggerAddAction(actionTrigger, func)
endfunction
private function timerAction takes nothing returns nothing
call TriggerExecute(actionTrigger)
endfunction
private function eventAction takes nothing returns nothing
call TimerStart(t, 0, false, function timerAction)
endfunction
private function init_function takes nothing returns nothing
call TriggerRegisterGameEvent(eventTrigger, EVENT_GAME_LOADED)
call TriggerAddAction(eventTrigger, function eventAction)
endfunction
endlibrary
JASS:
library Example initializer init_function requires FrameLoader
private function At0s takes nothing returns nothing
local framehandle frame = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, 0)
call BlzEnableUIAutoPosition(false)
call BlzFrameClearAllPoints(frame)
call BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOPLEFT, 0.4, 0.3)
endfunction
private function init_function takes nothing returns nothing
call FrameLoaderAdd(function At0s)
call TimerStart(CreateTimer(), 0, false, function At0s)
endfunction
endlibrary