Раздел:
Основы

Циклы и их лимиты (JASS)

Автор статьи: host_pi
Вот у нас есть код:
function Loop0 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL = 10000
	loop
		set i = i + 1
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction
и казалось бы, всё работает, что ещё надо?
Но добавив всего 1 строку BJDebugMsg в этот цикл - он остановится не на 10000, а на 800 и с обрывом перестанет исполняться
function Loop1 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL = 10000
	loop
		set i = i + 1
		call BJDebugMsg(I2S(i))
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction
точно также остановятся и следующие 9 вариаций с циклами (только Loop8 сможет дотянуть аж до 2500 из 10000, а Loop9 дотянет до 30000 из 50000)
Loop2 - на глобалках - 800 / 2000
function Loop2 takes nothing returns nothing
	local integer bj_forLoopAIndexEnd = 2000
	set bj_forLoopAIndex = 0
	loop
		set bj_forLoopAIndex = bj_forLoopAIndex + 1
		call BJDebugMsg(I2S(bj_forLoopAIndex))
		exitwhen bj_forLoopAIndex == bj_forLoopAIndexEnd
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction
Loop3 - два цикла подряд - 500+300 / 1000
function Loop3 takes nothing returns nothing
	local integer i = 0
	local integer k = 0
	local integer TOTAL = 500
	loop
		set k = k + 1
		set i = i + 1
		call BJDebugMsg(I2S(i)+"-"+I2S(k))
		exitwhen i == TOTAL
	endloop
	set i = 0
	loop
		set k = k + 1
		set i = i + 1
		call BJDebugMsg(I2S(i)+"-"+I2S(k))
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(k))
	call BJDebugMsg(I2S(i))
endfunction
Loop4 - вложенный цикл - 800 / 10000
function Loop4 takes nothing returns nothing
	local integer i1 = 0
	local integer i2 = 0
	local integer k = 0
	local integer TOTAL = 100
	loop
		set i1 = i1 + 1
		set i2 = 0
		loop
			set k = k + 1
			set i2 = i2 + 1
			call BJDebugMsg(I2S(i1)+"-"+I2S(i2)+"-"+I2S(k))
			exitwhen i2 == TOTAL
		endloop
		exitwhen i1 == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(k))
	call BJDebugMsg(I2S(i1))
	call BJDebugMsg(I2S(i2))
endfunction
Loop5 - вызов функции - 800 / 10000
function Loop5 takes nothing returns nothing
	call Loop1()
endfunction
Loop6 - другой вызов функции - 800 / 10000
function Loop6 takes nothing returns nothing
	call ExecuteFunc("Loop1")
endfunction
Loop7 - вызов нескольких малых функций 500+300 / 1000
function Loop7_2 takes integer i, integer j returns integer
	loop
		set i = i + 1
		call BJDebugMsg(I2S(j)+"-"+I2S(i))
		exitwhen i == 500
	endloop
	return i
endfunction

function Loop7 takes nothing returns nothing
	local integer i=0
	call BJDebugMsg("--1--")
	set i=i+Loop7_2(0,1)
	call BJDebugMsg("--2--")
	set i=i+Loop7_2(0,2)
	call BJDebugMsg("--E--")
	call BJDebugMsg(I2S(i))
endfunction
Loop8 - цикл с использованием ForForce - 2500 / 10000
function Loop8_2 takes nothing returns nothing
	loop
		set bj_forLoopAIndex = bj_forLoopAIndex + 1
		call BJDebugMsg(I2S(bj_forLoopAIndex))
		exitwhen bj_forLoopAIndex == bj_forLoopAIndexEnd
	endloop
	set bj_forLoopAIndex = bj_forLoopAIndex - 1
endfunction

function Loop8 takes nothing returns nothing
	set bj_forLoopAIndex=0
	set bj_forLoopAIndexEnd=10000
	call ForForce(bj_FORCE_PLAYER[0], function Loop8_2)
	call BJDebugMsg("--1--")
	call ForForce(bj_FORCE_PLAYER[0], function Loop8_2)
	call BJDebugMsg("--2--")
	call ForForce(bj_FORCE_PLAYER[0], function Loop8_2)
	call BJDebugMsg("--E--")
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction
Loop9 - через триггер 30000 / 50000
function Loop9_2 takes nothing returns nothing
	set bj_forLoopAIndex = bj_forLoopAIndex + 1
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction

function Loop9 takes nothing returns nothing
	local integer TOTAL = 50000
	local trigger t=null
	set t = CreateTrigger()
	call TriggerAddAction(t, function Loop9_2)
	set bj_forLoopAIndex=0
	loop
		call TriggerExecute(t)
		exitwhen bj_forLoopAIndex == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction

Заметка:

а дальше интересный момент - если в Loop1 заменить BJDebugMsg на DisplayTimedTextToPlayer, то количество итераций сразу вырастет с 800 до 9700 (потому что 1 BJDebugMsg это 12 раз DisplayTimedTextToPlayer, даже если в карте 2 слота для игроков)
Loop10 - замена BJDebugMsg на DisplayTimedTextToPlayer - 9700 / 20000
function Loop10 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL =20000
	loop
		set i = i + 1
		call DisplayTimedTextToPlayer(Player(0),0,0,1,I2S(i)) //LIMIT 9700
		//call BJDebugMsg(I2S(i)) //LIMIT 800
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction
function BJDebugMsg takes string msg returns nothing
//    constant integer   bj_MAX_PLAYERS                   =  12
    local integer i = 0
    loop
        call DisplayTimedTextToPlayer(Player(i),0,0,60,msg)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYERS
    endloop
endfunction

Причина:

циклы обрываются, потому что все команды выполняются в одной очереди, в одном стеке. поэтому он переполняется и обрывается. для обхода этого переполнения нужно использовать Loop11 , Loop12 , Loop13
Loop11 - через TriggerEvaluate - 400000 / 400000
globals
	trigger loop11_2 = CreateTrigger()
	trigger loop11_3 = CreateTrigger()
	integer i1
	integer i2
	integer i3
	integer i123
	integer i123TOTAL=74
endglobals

function Loop11 takes integer TOTAL returns nothing
	set i123TOTAL=TOTAL
	set i123=0
	set i1 = 0
	loop
		set i1 = i1 + 1
		call TriggerEvaluate(loop11_2)
		exitwhen i1 == i123TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i123))
endfunction

function Loop11_2 takes nothing returns boolean
	set i2 = 0
	loop
		set i2 = i2 + 1
		call TriggerEvaluate(loop11_3)
		exitwhen i2 == i123TOTAL
	endloop
	return false
endfunction

function Loop11_3 takes nothing returns boolean
	set i3 = 0
	loop
		//Actions here
		set i3 = i3 + 1
		set i123=i123 + 1
		call BJDebugMsg(I2S(i1)+"-"+I2S(i2)+"-"+I2S(i3)) //CPU LIMIT
		exitwhen i3 == i123TOTAL
	endloop
	return false
endfunction

function Loop11_init takes nothing returns nothing
	call TriggerAddCondition(loop11_2, Condition(function Loop11_2))
	call TriggerAddCondition(loop11_3, Condition(function Loop11_3))
endfunction

function main takes nothing returns nothing
    call Loop11_init()
endfunction
Loop12 - через таймерный триггер - 400000 / 400000
globals
	integer array t_loop_N
	trigger array t_loop
	integer array t_loop_init
	hashtable ht = InitHashtable()
endglobals

function Loop12_Actions takes nothing returns nothing
	local integer i = LoadInteger(ht, GetHandleId(GetTriggeringTrigger()), 0)
	set t_loop_N[i] = t_loop_N[i] + 1
	call BJDebugMsg(I2S(t_loop_N[i]))
	if t_loop_N[i] == 400000 then
		call BJDebugMsg("-----")
		call BJDebugMsg(I2S(t_loop_N[i]))
		set t_loop_N[i] = 0
		call DisableTrigger(t_loop[i])
	endif
endfunction

function Loop12 takes nothing returns nothing
	local integer i = GetPlayerId(GetTriggerPlayer()) + 1
	if t_loop_init[i] == 0 then
		set t_loop_init[i] = 1
		set t_loop[i] = CreateTrigger()
		call SaveInteger(ht, GetHandleId(t_loop[i]), 0, i)
		call TriggerRegisterTimerEvent(t_loop[i], 0.001, true)
		call TriggerAddAction(t_loop[i], function Loop12_Actions)
		call DisableTrigger(t_loop[i])
	endif
	if IsTriggerEnabled(t_loop[i]) then
		call DisableTrigger(t_loop[i])
	else
		set t_loop_N[i]=0
		call EnableTrigger(t_loop[i])
	endif
endfunction
Loop13 - через таймер - 400000 / 400000
globals
	timer array ti_time
	integer array ti_N
	boolean array ti_run
	integer ti_i
endglobals

function Loop13_Actions takes nothing returns nothing
	set ti_i=LoadInteger(ht,GetHandleId(GetExpiredTimer()),0)
	set ti_N[ti_i]=ti_N[ti_i]+1
	call BJDebugMsg("Timer "+I2S(ti_i)+" - "+I2S(ti_N[ti_i]))
	if ti_N[ti_i]==400000 then
		call PauseTimer(ti_time[ti_i])
		set ti_N[ti_i]=0
		set ti_run[ti_i]=false
		call BJDebugMsg("Player: "+I2S(ti_i)+", Autostop")
	endif
endfunction

function Loop13_Time takes nothing returns nothing
	set ti_i=GetPlayerId(GetTriggerPlayer())
	if(ti_run[ti_i])then
		call PauseTimer(ti_time[ti_i])
		set ti_N[ti_i]=0
		set ti_run[ti_i]=false
		call BJDebugMsg("Player: "+I2S(ti_i)+", Stop")
		return
	endif
	set ti_run[ti_i]=true
	call TimerStart(ti_time[ti_i],0.005,true,function Loop13_Actions)
endfunction

function Loop13_init takes nothing returns nothing
	local trigger t=CreateTrigger()
	set ti_i=0
	loop
		exitwhen(ti_i>=bj_MAX_PLAYER_SLOTS)
		if(GetPlayerController(Player(ti_i))==MAP_CONTROL_USER and GetPlayerSlotState(Player(ti_i))==PLAYER_SLOT_STATE_PLAYING)then
			call TriggerRegisterPlayerChatEvent(t,Player(ti_i),"-l13",false)
			set ti_N[ti_i]=0
			set ti_run[ti_i]=false
			set ti_time[ti_i]=CreateTimer()
			call SaveInteger(ht,GetHandleId(ti_time[ti_i]),0,ti_i)
		endif
		set ti_i=ti_i+1
	endloop
	call TriggerAddAction(t,function Loop13_Time)
	set t=null
endfunction

function main takes nothing returns nothing
    call Loop13_init()
endfunction
все три цикла дошли до 400000:

Бонус:

ну и ниже бонусная функция Preload с замером выполнения каждого действия. создаёт файлы в папке Warcraft\save-test\*.txt
и в каждом файле пишет строку call PreloadEnd( 0.0 )
если добавить туда какую-нибудь функцию, то можно отследить скорость её выполнения
а также отследить замедление - например если в 1.txt будет написано PreloadEnd( 0.1 ) это 0.1 сек , а в 50.txt будет написано PreloadEnd( 3.2 ) - значит 3.2 сек, что к середине цикла аж в 30 раз медленнее
Loop14 - Debug через Preload
function Loop14_Debug takes integer i, string txt returns nothing
	call PreloadGenClear()
	call PreloadGenStart()
	//Long Actions Here
	call Preload(txt+I2S(i))
	call PreloadGenEnd("save-test\\"+I2S(i)+".txt")
endfunction

function Loop14 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL = 100
	local string txt=""
	loop
		set txt = GetPlayerName(GetTriggerPlayer())
		set i = i + 1
		//Long Actions Here
		call Loop14_Debug(i,txt)
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction

Команды карты:

ниже прикреплена карта с примерами:
в чате вводить такие команды:
-l0 или -l / Loop0
-l1 / Loop1
-l2 / Loop2
-l3 / Loop3
-l4 / Loop4
-l5 / Loop5
-l6 / Loop6
-l7 / Loop7
-l8 / Loop8
-l9 / Loop9
-l10 / Loop10
-l11 / Loop11 20
-l11 XX / Loop11 XX - ввод кубический. т.е. ввод -l11 10 даст 10x10x10=1000 итераций, -l11 20 даст 8000, l11 50 даст 125000
-l12 / Loop12
-l13 / Loop13
-l14 / Loop14

Производительность:

Loop11 - TriggerEvaluate - зависнет пока не доделает
Loop12 - таймерный триггер TriggerRegisterTimerEvent - неплохо работает на скорости 0.001, к 350000 начинает чуть подтормаживать - на 400000 итераций уходит 7 минут
Loop13 - таймер TimerStart - на скорости 0.001 нокаутирует варик на 120 000, нормально работает на 0.004 / 0.005 - т.е. таймер раза в 4 прожорливее чем таймерный триггер
А также - если держать окно варика активным а не переключаться в другое окно - то варик будет работать чуть стабильнее
Итог - Loop12 является самым оптимальным и быстрым. Лучше чем Loop11 тем, что можно настраивать временной интервал и лучше чем Loop13 тем, что потребляет меньше ресурсов

Код карты:

Открыть спойлер с кодом карты

//***************************************************************************
//*
//*  Global Variables
//*
//***************************************************************************

globals
	trigger loop11_2 = CreateTrigger()
	trigger loop11_3 = CreateTrigger()
	integer i1
	integer i2
	integer i3
	integer i123
	integer i123TOTAL=74

	integer array t_loop_N
	trigger array t_loop
	integer array t_loop_init
	hashtable ht = InitHashtable()

	timer array ti_time
	integer array ti_N
	boolean array ti_run
	integer ti_i
endglobals

function Loop0 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL = 10000
	loop
		set i = i + 1
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction

function Loop1 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL = 2000
	loop
		set i = i + 1
		call BJDebugMsg(I2S(i))
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction

function Loop2 takes nothing returns nothing
	local integer bj_forLoopAIndexEnd = 2000
	set bj_forLoopAIndex = 0
	loop
		set bj_forLoopAIndex = bj_forLoopAIndex + 1
		call BJDebugMsg(I2S(bj_forLoopAIndex))
		exitwhen bj_forLoopAIndex == bj_forLoopAIndexEnd
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction

function Loop3 takes nothing returns nothing
	local integer i = 0
	local integer k = 0
	local integer TOTAL = 500
	loop
		set k = k + 1
		set i = i + 1
		call BJDebugMsg(I2S(i)+"-"+I2S(k))
		exitwhen i == TOTAL
	endloop
	set i = 0
	loop
		set k = k + 1
		set i = i + 1
		call BJDebugMsg(I2S(i)+"-"+I2S(k))
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(k))
	call BJDebugMsg(I2S(i))
endfunction

function Loop4 takes nothing returns nothing
	local integer i1 = 0
	local integer i2 = 0
	local integer k = 0
	local integer TOTAL = 100
	loop
		set i1 = i1 + 1
		set i2 = 0
		loop
			set k = k + 1
			set i2 = i2 + 1
			call BJDebugMsg(I2S(i1)+"-"+I2S(i2)+"-"+I2S(k))
			exitwhen i2 == TOTAL
		endloop
		exitwhen i1 == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(k))
	call BJDebugMsg(I2S(i1))
	call BJDebugMsg(I2S(i2))
endfunction

function Loop5 takes nothing returns nothing
	call Loop1()
endfunction

function Loop6 takes nothing returns nothing
	call ExecuteFunc("Loop1")
endfunction

function Loop7_2 takes integer i, integer j returns integer
	loop
		set i = i + 1
		call BJDebugMsg(I2S(j)+"-"+I2S(i))
		exitwhen i == 500
	endloop
	return i
endfunction

function Loop7 takes nothing returns nothing
	local integer i=0
	call BJDebugMsg("--1--")
	set i=i+Loop7_2(0,1)
	call BJDebugMsg("--2--")
	set i=i+Loop7_2(0,2)
	call BJDebugMsg("--E--")
	call BJDebugMsg(I2S(i))
endfunction

function Loop8_2 takes nothing returns nothing
	loop
		set bj_forLoopAIndex = bj_forLoopAIndex + 1
		call BJDebugMsg(I2S(bj_forLoopAIndex))
		exitwhen bj_forLoopAIndex == bj_forLoopAIndexEnd
	endloop
	set bj_forLoopAIndex = bj_forLoopAIndex - 1
endfunction

function Loop8 takes nothing returns nothing
	set bj_forLoopAIndex=0
	set bj_forLoopAIndexEnd=10000
	call ForForce(bj_FORCE_PLAYER[0], function Loop8_2)
	call BJDebugMsg("--1--")
	call ForForce(bj_FORCE_PLAYER[0], function Loop8_2)
	call BJDebugMsg("--2--")
	call ForForce(bj_FORCE_PLAYER[0], function Loop8_2)
	call BJDebugMsg("--E--")
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction

function Loop9_2 takes nothing returns nothing
	set bj_forLoopAIndex = bj_forLoopAIndex + 1
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction

function Loop9 takes nothing returns nothing
	local integer TOTAL = 50000
	local trigger t=null
	set t = CreateTrigger()
	call TriggerAddAction(t, function Loop9_2)
	set bj_forLoopAIndex=0
	loop
		call TriggerExecute(t)
		exitwhen bj_forLoopAIndex == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(bj_forLoopAIndex))
endfunction

function Loop10 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL =20000
	loop
		set i = i + 1
		call DisplayTimedTextToPlayer(Player(0),0,0,1,I2S(i)) //LIMIT 9700
		//call BJDebugMsg(I2S(i)) //LIMIT 800
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction

function Loop11 takes integer TOTAL returns nothing
	set i123TOTAL=TOTAL
	set i123=0
	set i1 = 0
	loop
		set i1 = i1 + 1
		call TriggerEvaluate(loop11_2)
		exitwhen i1 == i123TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i123))
endfunction

function Loop11_2 takes nothing returns boolean
	set i2 = 0
	loop
		set i2 = i2 + 1
		call TriggerEvaluate(loop11_3)
		exitwhen i2 == i123TOTAL
	endloop
	return false
endfunction

function Loop11_3 takes nothing returns boolean
	set i3 = 0
	loop
		//Actions here
		set i3 = i3 + 1
		set i123=i123 + 1
		call BJDebugMsg(I2S(i1)+"-"+I2S(i2)+"-"+I2S(i3)) //CPU LIMIT
		exitwhen i3 == i123TOTAL
	endloop
	return false
endfunction

function Loop11_init takes nothing returns nothing
	call TriggerAddCondition(loop11_2, Condition(function Loop11_2))
	call TriggerAddCondition(loop11_3, Condition(function Loop11_3))
endfunction

function Loop12_Actions takes nothing returns nothing
	local integer i = LoadInteger(ht, GetHandleId(GetTriggeringTrigger()), 0)
	set t_loop_N[i] = t_loop_N[i] + 1
	call BJDebugMsg(I2S(t_loop_N[i]))
	if t_loop_N[i] == 400000 then
		call BJDebugMsg("-----")
		call BJDebugMsg(I2S(t_loop_N[i]))
		set t_loop_N[i] = 0
		call DisableTrigger(t_loop[i])
	endif
endfunction

function Loop12 takes nothing returns nothing
	local integer i = GetPlayerId(GetTriggerPlayer()) + 1
	if t_loop_init[i] == 0 then
		set t_loop_init[i] = 1
		set t_loop[i] = CreateTrigger()
		call SaveInteger(ht, GetHandleId(t_loop[i]), 0, i)
		call TriggerRegisterTimerEvent(t_loop[i], 0.001, true)
		call TriggerAddAction(t_loop[i], function Loop12_Actions)
		call DisableTrigger(t_loop[i])
	endif
	if IsTriggerEnabled(t_loop[i]) then
		call DisableTrigger(t_loop[i])
	else
		set t_loop_N[i]=0
		call EnableTrigger(t_loop[i])
	endif
endfunction

function Loop13_Actions takes nothing returns nothing
	set ti_i=LoadInteger(ht,GetHandleId(GetExpiredTimer()),0)
	set ti_N[ti_i]=ti_N[ti_i]+1
	call BJDebugMsg("Timer "+I2S(ti_i)+" - "+I2S(ti_N[ti_i]))
	if ti_N[ti_i]==400000 then
		call PauseTimer(ti_time[ti_i])
		set ti_N[ti_i]=0
		set ti_run[ti_i]=false
		call BJDebugMsg("Player: "+I2S(ti_i)+", Autostop")
	endif
endfunction

function Loop13_Time takes nothing returns nothing
	set ti_i=GetPlayerId(GetTriggerPlayer())
	if(ti_run[ti_i])then
		call PauseTimer(ti_time[ti_i])
		set ti_N[ti_i]=0
		set ti_run[ti_i]=false
		call BJDebugMsg("Player: "+I2S(ti_i)+", Stop")
		return
	endif
	set ti_run[ti_i]=true
	call TimerStart(ti_time[ti_i],0.005,true,function Loop13_Actions)
endfunction

function Loop13_init takes nothing returns nothing
	local trigger t=CreateTrigger()
	set ti_i=0
	loop
		exitwhen(ti_i>=bj_MAX_PLAYER_SLOTS)
		if(GetPlayerController(Player(ti_i))==MAP_CONTROL_USER and GetPlayerSlotState(Player(ti_i))==PLAYER_SLOT_STATE_PLAYING)then
			call TriggerRegisterPlayerChatEvent(t,Player(ti_i),"-l13",false)
			set ti_N[ti_i]=0
			set ti_run[ti_i]=false
			set ti_time[ti_i]=CreateTimer()
			call SaveInteger(ht,GetHandleId(ti_time[ti_i]),0,ti_i)
		endif
		set ti_i=ti_i+1
	endloop
	call TriggerAddAction(t,function Loop13_Time)
	set t=null
endfunction

function Loop14_Debug takes integer i, string txt returns nothing
	call PreloadGenClear()
	call PreloadGenStart()
	//Long Actions Here
	call Preload(txt+I2S(i))
	call PreloadGenEnd("save-test\\"+I2S(i)+".txt")
endfunction

function Loop14 takes nothing returns nothing
	local integer i = 0
	local integer TOTAL = 100
	local string txt=""
	loop
		set txt = GetPlayerName(GetTriggerPlayer())
		set i = i + 1
		//Long Actions Here
		call Loop14_Debug(i,txt)
		exitwhen i == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i))
endfunction

function Start takes nothing returns nothing
	local string s=GetEventPlayerChatString()
	if s=="-l0" or s=="-l" then
		call Loop0()
	elseif s=="-l1" then
		call Loop1()
	elseif s=="-l2" then
		call Loop2()
	elseif s=="-l3" then
		call Loop3()
	elseif s=="-l4" then
		call Loop4()
	elseif s=="-l5" then
		call Loop5()
	elseif s=="-l6" then
		call Loop6()
	elseif s=="-l7" then
		call Loop7()
	elseif s=="-l8" then
		call Loop8()
	elseif s=="-l9" then
		call Loop9()
	elseif s=="-l10" then
		call Loop10()
	elseif SubString(s,0,5)=="-l11 " then
		call Loop11(S2I(SubString(s,5,99)))
	elseif s=="-l11" then
		call Loop11(20)
	elseif s=="-l12" then
		call Loop12()
	elseif s=="-l14" then
		call Loop14()
	endif
endfunction

function Start_init takes nothing returns nothing
	local trigger t=CreateTrigger()
	local integer PLAYERS=12
	local integer i=1
	loop
		exitwhen i>PLAYERS
		call TriggerRegisterPlayerChatEvent(t,Player(i-1),"-",false)
		set i=i+1
	endloop
	call TriggerAddAction(t,function Start)
endfunction

function InitGlobals takes nothing returns nothing
endfunction

//***************************************************************************
//*
//*  Unit Creation
//*
//***************************************************************************

//===========================================================================
function CreateUnitsForPlayer0 takes nothing returns nothing
    local player p = Player(0)
    local unit u
    local integer unitID
    local trigger t
    local real life

    set u = CreateUnit( p, 'Hblm', -143.7, -155.1, 106.197 )
endfunction

//===========================================================================
function CreatePlayerBuildings takes nothing returns nothing
endfunction

//===========================================================================
function CreatePlayerUnits takes nothing returns nothing
    call CreateUnitsForPlayer0(  )
endfunction

//===========================================================================
function CreateAllUnits takes nothing returns nothing
    call CreatePlayerBuildings(  )
    call CreatePlayerUnits(  )
endfunction

//***************************************************************************
//*
//*  Players
//*
//***************************************************************************

function InitCustomPlayerSlots takes nothing returns nothing

    // Player 0
    call SetPlayerStartLocation( Player(0), 0 )
    call ForcePlayerStartLocation( Player(0), 0 )
    call SetPlayerColor( Player(0), ConvertPlayerColor(0) )
    call SetPlayerRacePreference( Player(0), RACE_PREF_HUMAN )
    call SetPlayerRaceSelectable( Player(0), false )
    call SetPlayerController( Player(0), MAP_CONTROL_USER )

    // Player 1
    call SetPlayerStartLocation( Player(1), 1 )
    call ForcePlayerStartLocation( Player(1), 1 )
    call SetPlayerColor( Player(1), ConvertPlayerColor(1) )
    call SetPlayerRacePreference( Player(1), RACE_PREF_ORC )
    call SetPlayerRaceSelectable( Player(1), false )
    call SetPlayerController( Player(1), MAP_CONTROL_COMPUTER )

endfunction

function InitCustomTeams takes nothing returns nothing
    // Force: TRIGSTR_007
    call SetPlayerTeam( Player(0), 0 )

    // Force: TRIGSTR_008
    call SetPlayerTeam( Player(1), 1 )

endfunction

//***************************************************************************
//*
//*  Main Initialization
//*
//***************************************************************************

//===========================================================================
function main takes nothing returns nothing
    call Start_init()
    call Loop11_init()
    call Loop13_init()

    call SetCameraBounds( -3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), -3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), -3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), -3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM) )
    call SetDayNightModels( "Environment\\DNC\\DNCLordaeron\\DNCLordaeronTerrain\\DNCLordaeronTerrain.mdl", "Environment\\DNC\\DNCLordaeron\\DNCLordaeronUnit\\DNCLordaeronUnit.mdl" )
    call NewSoundEnvironment( "Default" )
    call SetAmbientDaySound( "LordaeronSummerDay" )
    call SetAmbientNightSound( "LordaeronSummerNight" )
    call SetMapMusic( "Music", true, 0 )
    call CreateAllUnits(  )
    call InitBlizzard(  )
    call InitGlobals(  )

endfunction

//***************************************************************************
//*
//*  Map Configuration
//*
//***************************************************************************

function config takes nothing returns nothing
    call SetMapName( "TRIGSTR_001" )
    call SetMapDescription( "TRIGSTR_003" )
    call SetPlayers( 2 )
    call SetTeams( 2 )
    call SetGamePlacement( MAP_PLACEMENT_USE_MAP_SETTINGS )

    call DefineStartLocation( 0, -128.0, -192.0 )
    call DefineStartLocation( 1, -128.0, -192.0 )

    // Player setup
    call InitCustomPlayerSlots(  )
    call InitCustomTeams(  )
endfunction

`
ОЖИДАНИЕ РЕКЛАМЫ...
0
33
1 год назад
0
А есть ли такое понятие как лимит триггеров?
1
37
1 год назад
Отредактирован ScorpioT1000
1
Похожая статья: xgm.guru/p/wc3/code-flow-and-data-access-op-limit (на правах рекламы)
0
14
1 год назад
Отредактирован host_pi
0
Вышла новая версия! Прокрутить к ресурсу
в статью добавлен пункт "производительность"
в карту добавлена превьюшка и wts, а также Loop13 замедлен с 0.001 до 0.005
0
14
1 год назад
Отредактирован host_pi
0
Итог
ну а Loop0 я всё-таки тоже добил - и получилось максимум 23000 операций i+1
при 24000 уже ничего не выведет на экран после цикла
т.е. loop лучше вообще нигде не использовать (больше сотни итераций)
function Loop0_test takes nothing returns nothing
	local integer i=0
	call BJDebugMsg("--S--")
	loop
		set i=i+1
		exitwhen i == 24000 //23000 max
	endloop
	call BJDebugMsg("--E--")
	call BJDebugMsg("i="+I2S(i))
endfunction
5
20
1 год назад
Отредактирован Unryze
5
  1. TriggerRegisterTimerEvent создаёт CTimerEventReg, который так же используется в CTimerWar3
Скриншоты
  1. Разброс скорости ты создаёшь сам, ибо у тебя разница текстов и переменных и т.д.:
Перед тем как читать дальше, прошу заметить, что тесты делаются на UjAPI, где более точное сравнение времени, нежели чем через мемхак, потому скорость операций значительно быстрее. Так же все тесты делаются на 10000 итераций, получаемый результат в ms, конечный результат будет указан в ns или же ms / 1000000 / 10000 (Количество итераций).
Для начала изучим сколько скорости мы теряем из-за ClearTextMessages( ) и I2S( ), получаем:
ClearTextMessages( ) = 400ns на 1 операцию.
I2S( ) = 600ns на 1 операцию.
Теперь сравним I2S( 0 ) и I2S( k ) и I2S( l[k] ).
I2S( 0 ) и I2S( k ):
раскрыть
I2S( 0 ) = 500ns
I2S( k ) = 600ns
I2S( k ) и I2S( l[k] ):
I2S( k ) = 600ns
I2S( l[k] ) = 600ns
На удивление они выдали одинаковый результат. А теперь посмотрим вывод текстов с использованием ClearTextMessages, чтобы не дать игре "зависать".
А теперь к сравнению текстов, которые у тебя в Loop12 и Loop13, к сожалению оба вместе тестировать не получалось, потому решил проверить их отдельно, вот результат:
Для начала сравним сами тексты:
I2S( l[k] ) против "Timer "+ I2S( k ) + " - " + I2S( l[k] )
раскрыть
I2S( l[k] ) = 600ns
"Timer "+ I2S( k ) + " - " + I2S( l[k] ) = 2000ns
Что значит разницу в 3.33~, примерно то, что у тебя и получилось.
Теперь же сравним всё через BJDebugMsg...
раскрыть
call BJDebugMsg( I2S( l[k] ) )
call BJDebugMsg( "Timer "+ I2S( k ) + " - " + I2S( l[k] ) )
call BJDebugMsg( I2S( l[k] ) ) = 26300ns
call BJDebugMsg( "Timer "+ I2S( k ) + " - " + I2S( l[k] ) ) = 70300ns
Разница в 2.67~ раз но это с большими погрешностями, так что разница будет ближе к 3.
Итог:
Скриншот
Получаем ожидаемый результат, что у них НЕТ разницы по скорости.
Собственно вот код:
Код
globals
    timer tStopWatch = CreateTimer( )
    timer tIterator = CreateTimer( )
    trigger trTrig = CreateTrigger( )
    
    integer iTimerTestValue = 0
    integer iTriggerTestValue = 0
    integer iLimitValue = 400000
    
    integer iElapsedTime = 0
endglobals

function TimeAction takes nothing returns nothing
    set iElapsedTime = iElapsedTime + 1
endfunction

function IterateValue takes nothing returns nothing
    set iTimerTestValue = iTimerTestValue + 1
    
    if iTimerTestValue >= iLimitValue then
        call PauseTimer( tIterator )
        call BJDebugMsg( "IterateValue Elapsed Time: " + R2S( I2R( iElapsedTime ) / 1000. ) + "s" )
    endif
endfunction

function IterateTriggerValue takes nothing returns nothing
    set iTriggerTestValue = iTriggerTestValue + 1

    if iTriggerTestValue >= iLimitValue then
        call DisableTrigger( trTrig )
        call BJDebugMsg( "IterateTriggerValue Elapsed Time: " + R2S( I2R( iElapsedTime ) / 1000. ) + "s" )
    endif
endfunction

function StartTest takes nothing returns nothing
    call TimerStart( tStopWatch, .001, true, function TimeAction )
    call TimerStart( tIterator, .001, true, function IterateValue )
    call TriggerRegisterTimerEvent( trTrig, .001, true )
    call TriggerAddAction( trTrig, function IterateTriggerValue )
endfunction
По итогу вот из-за таких извини, невнимательных тестов и рождаются мифы...
2
14
5 месяцев назад
Отредактирован host_pi
2
уменьшенные коды, не такие громоздкие как Loop12 Loop13: (хотя чёт по колву строк такие же и получились)
Loop15 - через пошаговый локальный триггер - 400000 / 400000
globals
	hashtable ht = InitHashtable()
	integer TimerStop=1
endglobals

function Loop15_Actions takes nothing returns nothing
	local trigger localTrigger = CreateTrigger()
	local trigger oldTrigger = LoadTriggerHandle(ht, 0, StringHash("loop15"))
	call DisableTrigger(oldTrigger)
	call DestroyTrigger(oldTrigger)
	//call DestroyTrigger(GetTriggeringTrigger())
	call SaveTriggerHandle(ht, 0, StringHash("loop15"),localTrigger)
	set i1 = i1+1
	call BJDebugMsg(I2S(i1))
	if TimerStop==0 and i1<400000 then
		call TriggerRegisterTimerEvent(localTrigger, 0.001, false)
		call TriggerAddAction(localTrigger, function Loop15_Actions)
	else
		set TimerStop=1
		call DisableTrigger(oldTrigger)
		call DestroyTrigger(oldTrigger)
		call DisableTrigger(localTrigger)
		call DestroyTrigger(localTrigger)
		call BJDebugMsg("Timer Stop")
	endif
	set localTrigger = null
	set oldTrigger = null
endfunction

function Loop15 takes nothing returns nothing
	if TimerStop==0 then
		set TimerStop=1
	else
		set TimerStop=0
		call BJDebugMsg("Trigger Go")
		set i1=0
		call Loop15_Actions()
	endif
endfunction
Loop16 - через пошаговый локальный таймер - 400000 / 400000
globals
	hashtable ht = InitHashtable()
	integer TimerStop=1
endglobals

function Loop16_Actions takes nothing returns nothing
	local timer localTimer = CreateTimer()
	local timer oldTimer = LoadTimerHandle(ht, 0, StringHash("loop16"))
	call PauseTimer(oldTimer)
	call DestroyTimer(oldTimer)
	//call DestroyTimer(GetExpiredTimer())
	call SaveTimerHandle(ht, 0, StringHash("loop16"),localTimer)
	set i1 = i1+1
	call BJDebugMsg(I2S(i1))
	if TimerStop==0 and i1<400000 then
		call TimerStart(localTimer, 0.001, false, function Loop16_Actions)
	else
		set TimerStop=1
		call PauseTimer(oldTimer)
		call DestroyTimer(oldTimer)
		call PauseTimer(localTimer)
		call DestroyTimer(localTimer)
		call BJDebugMsg("Timer Stop")
	endif
	set localTimer = null
	set oldTimer = null
endfunction

function Loop16 takes nothing returns nothing
	if TimerStop==0 then
		set TimerStop=1
	else
		set TimerStop=0
		call BJDebugMsg("Timer Go")
		set i1=0
		call Loop16_Actions()
	endif
endfunction
Загруженные файлы
1
18
5 месяцев назад
1
Априорная оценка «вычислений» относительно лимита операций
1
14
5 месяцев назад
Отредактирован host_pi
1
на хайве www.hiveworkshop.com/threads/executefunc.211792
и на xgm xgm.guru/forum/showthread.php?t=30152
пишут, что ExecuteFunc открывает новый поток
на практике же она не смогла даже пропечатать выше 20 000, вот вам и "отдельный поток". который не сравнится ни с таймером ни с триггером
Loop17 - через ExecuteFunc 18000/400000
function Loop17 takes nothing returns nothing
	local integer TOTAL = 400000
	set i1 = 0
	loop
		set i1 = i1 + 1
		call ExecuteFunc("Loop17_Actions")
		exitwhen i1 == TOTAL
	endloop
	call BJDebugMsg("----")
	call BJDebugMsg(I2S(i1))
endfunction
function Loop17_Actions takes nothing returns nothing
	call BJDebugMsg(I2S(i1))
endfunction
Загруженные файлы
0
20
5 месяцев назад
Отредактирован Unryze
0
Немного путаешь логики ExecuteFunc, ты открываешь новый поток, но ничего в нём не делаешь. Твой лимит достигается именно в главном потоке.
Поясняю, ExecuteFunc 5000 (200 + 4800) нс против обычного call (200нс). То бишь ты лишь ускорил процесс истекания лимита операций. Чтобы его "избежать", нужно запускать Loop17 через экзекут (но не в текущем виде кода).
В любом случае все эти попытки обхода - это попытки обойти фантомную проблему ещё более фантомными решениями.
1
32
5 месяцев назад
1
Мне вот интересно, а зачем?
Проблемы были лишь в Гуи говнокартах и дотах, где оптимизатор сливает все в одну функцию и начинаются обрывы, которые лечатся сверхпросто.
Но проще думать головой и не плодить сущности, инит нет надобности делать в мейне и разом, необходимые триггеры вовсе можно создавать во время игры, к примеру когда игрок выберет героя к котором эти триггеры относятся.
0
14
5 месяцев назад
Отредактирован host_pi
0
quq_CCCP: Мне вот интересно, а зачем?
классический вопрос от @ quq_CCCP
что, в картах не бывает циклов которые обрываются из-за оплимита?
бывают или нет?
если не бывает - то мы вам перезвоним
если бывает - то где статья с кодом и со всеми различными способами обхода оплимита ?
1
32
5 месяцев назад
1
host_pi, нет, не припомню ни одной задачи, где бы были такие циклы.
2
20
5 месяцев назад
2
В картах обычно цикл до 8192 (прелести структур и вджасс) - и это подавляющее большинство. Если каким-то чудом цикл уже больше 8192 - то это скорее проблема разработчика, нежели ОП лимита.
И нет, обычно проблема не в циклах, а в перегруженности потока, который можно "разгружать" - да. Но все эти проблемы ОП лимита обходятся дроблениями main функции, да и самих циклов на отдельные "потоки" либо через ExecuteFunc, либо через TimerStart. В любом случае, такой прямо катастрофической проблемы банально нет.
Говоря проще, причина по которой не было подобных тем - скорее потому что ОП лимит достигается лишь фокусниками/извращенцами, нежели из-за неизбежности/случайно, ну а те, кто юзают Мемхак этот лимит могут поднять вручную, на UjAPI он вообще 2 миллиарда, а на рефе 30 миллионов с 300к.
Тут уже скорее проблема ванилы, но и она на деле не проблема, ибо испытывается единицами.
0
14
5 месяцев назад
Отредактирован host_pi
0
quq_CCCP: ни одной задачи, где бы были такие циклы
а я вот встретился с оплимитом в первой же карте, с которой работал - поэтому вообще без понятия - как за 20 лет вара челик 14го левела на хигаме - его ни разу не видел
и без подобных методов обхода оплимита - карта бы не работала как должна
классическое нинужна?
0
32
5 месяцев назад
0
host_pi, потому что вы что то не то делайте, сами себе создаёте проблему.
0
14
5 месяцев назад
Отредактирован host_pi
0
quq_CCCP: потому что вы что то не то делайте, сами себе создаёте проблему
ах да, это я такой криворукий, а не оплимит в варике
только вот сегодня утром опять наткнулся, уже в 3й раз в карте, на проблему оплимита в цикле, когда цикл тупо не доходит до конца и молча прерывается посередине
первый раз было с координатами юнитов - ладно, создал триггер вместо цикла - проблема решилась
вчера он аналогично не захотел обработать 50 строк длиннее 1000 символов - ну ладно, на тебе второй триггер
но нет же, сегодня во втором триггере заглох при обработке одной строки на 1400 символов (во время вызова доп функции) - пришлось делать триггер в триггере
итого 3 раза цикл из-за оплимита оборвался и не доработал, пока его на триггер не посадили
сидишь только и борешься с оплимитом в циклах сутками (а по пути на втором языке с нормальным отладчиком всё дублируешь),
действительно, никогда не было и вот опять
вместо работы над самой картой - для банальных вещей писать костыли к жасу, подпинывая эту калеку, чтобы он хоть как-то ходил
0
20
5 месяцев назад
0
Скинь все эти карты, я готов тебе потыкать где и как создатель этих карт буквально нагадил и в коде и в штаны. А то этот сыр бор - банально мимо кассы.
И повторюсь, коли так тебя душат ОП лимиты у тебя есть несколько выборов:
  1. UjAPI.
  2. MemHack.
  3. Патч 1.29 или выше.
  4. Реф.
Тебя кто-то душит сидеть на 1.26а и тем более Ванильном? Если да, то тогда соизволь пытаться умещаться в лимиты, а не городить костыли обходить то, что достигаться и не должно.
1
18
5 месяцев назад
Отредактирован Vlod
1
вчера он аналогично не захотел обработать 50 строк длиннее 1000 символов - ну ладно, на тебе второй триггер
но нет же, сегодня во втором триггере заглох при обработке одной строки на 1400 символов (во время вызова доп функции) - пришлось делать триггер в триггере
итого 3 раза цикл из-за оплимита оборвался и не доработал, пока его на триггер не посадили
сидишь только и борешься с оплимитом в циклах сутками
Да понимаю что это сложно, поэтому рекомендуй уйти на lua где нет такого лимита и больше перфоманс. Если такой возможности нет то дели код на части и делай отложенные вычисления типа таймером на 0 сек и т.п.
0
14
5 месяцев назад
Отредактирован host_pi
0
Vlod: на lua нет такого лимита
каким же образом?
это религия альтернативно-кодеров?
каким образом можно писать что lua hrua cjass vjass ...{вставить ещё сотню языков} могут больше чем оригинал?
если они в конце компиляции тупо конвертят свой личный код в обычный жас
фактически это не больше чем обёртка от конфеты, только конфета остаётся всё той же
1
18
5 месяцев назад
1
каким образом можно писать что lua hrua cjass vjass ...{вставить ещё сотню языков} могут больше чем оригинал?
если они в конце компиляции тупо конвертят свой личный код в обычный жас
lua не конвертируется в jass, это отдельный язык со своей luaVM который интегрируется в игру и дергает нативки как сишные функции, оп-лимит это прикол исключительно jassVM
1
14
5 месяцев назад
Отредактирован host_pi
1
Vlod: lua не конвертируется в jass, это отдельный язык со своей luaVM который интегрируется в игру
а дай карту для 1.26, которая написана на луа и без жаса через супа пупа крутые dll интегрируется в игру
0
18
8 часов назад
Отредактирован EugeAl
0
А чем отличается trigger evaluate от trigger execute? В плане потоков? Разве trigger add action с функцией не создаёт новый поток?
Чтобы оставить комментарий, пожалуйста, войдите на сайт.