| 09-14-2007, 03:23 AM | #1 |
Hi everyone, I am still new to the world of programming and JASS Is the first close to anything language i ever attempted to learn, so one thing I am confused on that needs to be made clear to me. I understand slightly that all your script uses processor time, and the cleaner your script the faster or more efficient it is. So, I've been wondering for awhile which of the below examples would be faster, slower, or if they are equal to each other. Lets say I have 3 JASS "triggers" (they are simple, I'm still learning)... JASS://trigger 1 function RockGolemCond takes nothing returns boolean local unit u = GetAttacker() local integer id = GetUnitTypeId(u) if (id=='o02X') or (id=='o03T') then set u = null return true endif set u = null return false endfunction function RockGolem takes nothing returns nothing local unit u = GetAttacker() call IssueImmediateOrder(u, "thunderclap") set u = null endfunction function InitTrig_RockGolems takes nothing returns nothing set gg_trg_RockGolems = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_RockGolems, EVENT_PLAYER_UNIT_ATTACKED) call TriggerAddCondition(gg_trg_RockGolems, Condition(function RockGolemCond)) call TriggerAddAction(gg_trg_RockGolems, function RockGolem) endfunction //trigger 2 function RootTowerCond takes nothing returns boolean local unit u = GetAttacker() local integer int = GetUnitTypeId(u) if (int=='h03U') then set u = null return true endif set u = null return false endfunction function RootTower takes nothing returns nothing local unit a = GetAttacker() local unit t = GetTriggerUnit() call IssueTargetOrder(a, "entanglingroots", t) set a = null set t = null endfunction function InitTrig_RootTower takes nothing returns nothing set gg_trg_RootTower = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_RootTower, EVENT_PLAYER_UNIT_ATTACKED) call TriggerAddCondition(gg_trg_RootTower, Condition(function RootTowerCond)) call TriggerAddAction(gg_trg_RootTower, function RootTower) endfunction //trigger 3 function StormCloudCond takes nothing returns boolean local unit u = GetAttacker() local integer int = GetUnitTypeId(u) if (int=='h06E') or (int=='h06F') then set u = null return true endif set u = null return false endfunction function StormCloud takes nothing returns nothing local unit a = GetAttacker() local unit t = GetTriggerUnit() local real r = GetUnitState(a, UNIT_STATE_MAX_MANA) call SetUnitState(a, UNIT_STATE_MANA, r * RMaxBJ(0,100) * 0.01) call IssueTargetOrder(a, "forkedlightning", t) set a = null set t = null endfunction function InitTrig_StormClouds takes nothing returns nothing set gg_trg_StormClouds = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_StormClouds, EVENT_PLAYER_UNIT_ATTACKED) call TriggerAddCondition(gg_trg_StormClouds, Condition(function StormCloudCond)) call TriggerAddAction(gg_trg_StormClouds, function StormCloud) endfunction Now, just by looking at it, the below would look like it would be much easier on your processor, but I'm not one to say so or not, because the logic behind it is the same. JASS:function Merged takes nothing returns nothing local unit u = GetAttacker() local unit t = GetTriggerUnit() local integer id = GetUnitTypeId(u) local real r = GetUnitState(a, UNIT_STATE_MAX_MANA) if (id=='o02X') or (id=='o03T') then call IssueImmediateOrder(u, "thunderclap") elseif (id=='h03U') then call IssueTargetOrder(u, "entanglingroots", t) elseif (id=='h06E') or (id=='h06F') then call SetUnitState(u, UNIT_STATE_MANA, r * RMaxBJ(0,100) * 0.01) call IssueTargetOrder(u, "forkedlightning", t) endif set u = null set t = null endfunction function InitTrig_Merged takes nothing returns nothing set gg_trg_Merged = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_Merged, EVENT_PLAYER_UNIT_ATTACKED) call TriggerAddAction(gg_trg_Merged, function Merged) endfunction I don't know the right term for which is better, so I'll use "faster". My question is, is the three triggers in the first box faster, slower, or equal to the one trigger in the second box? |
| 09-14-2007, 03:56 AM | #2 |
Ok first things first. Shorter script length doesn't have anything to do with how well it runs. Now as for some basic tips: Gamecache is slow globals are slower then locals when you have a function "take" something it uses memory every function you call is generally slower then doing it inside the function for example a call add(1,2) function add takes integer a and integer b returns integer return a + b endfunction is slower then just adding a and b in the parent function Triggerting unit is always slower then any other default thing such as dying unit. Also triggering unit will survive through waits ect where most others wont Use as few limiters as possible for example if a = 0 then w/e endif if a = 1 then w/e endif is slower then if a = 0 then w/e elseif a = 1 then w/e endif This is because it is only having to worry about the contents of the second if statement in the event that a <> 0. PS: Im at work so I dont have time to look at the JASS ill see it in about an hour when I get home. Also I am not a "super JASS pro" so this is all to the best of my knowladge however there are much more qualified people out there. (also I cant use JASS new gen pack so I only know JASS2 and not vJASS) EDIT: one thing that stuck out was the " local unit u = GetAttacker()" jsut have the function take the unit from the parent function |
| 09-14-2007, 04:22 AM | #3 |
Most of those tips were great, I did not know some if that thank you. Now, I still have my question from my first post, and a new question. You ended with "one thing that stuck out was the " local unit u = GetAttacker()" jsut have the function take the unit from the parent function". Could you elaborate on that, it confused me. |
| 09-14-2007, 05:19 AM | #4 |
ok first off if you have AIM please aim me , botanicvelious. If not ill edit the post in a few mins. EDIT: in the first JASS trigger i thought it was all one trigger.... Ne ways what I meant was for example if you had one function call another function like this: JASS:function actions takes unit u returns nothing //actions endfunction function initialize takes nothing returns nothing local unit u = GetAttackingUnit() call actions(u) endfunction you see how it passes the value instade of redeclaring it? that allows you to include things like waits ect. so then you could have something like this that would be MUI JASS:function actions takes unit u returns nothing //actions endfunction function actions2 takes unit u returns nothing //more actions endfunction function initialize takes nothing returns nothing local integer I local unit u = GetAttackingUnit() set I = 0 loop exitwhen I = 100 set I = I + 1 call actions(u) PolledWait(2.00) call actions2(u) PolledWait(2.00) endloop endfunction PS: Use the second one it looks fine to me (dunno what you are trying to accomplish with it but it seems optimized to me) My only comment on that one is that make the first if the most common action and the later ones the less common ones. It is not that important in reality however it would be slightly faster because it would reduce the number of times it has to worry about conditions in the trigger. |
| 09-14-2007, 09:22 PM | #5 |
I understand what you mean now, I just didnt' understand or know the correct terms . I try to do that as often as possible to make less lines of code. An example of one of my functions like that is one I use to swap players. I have many more this one is small so won't take up much space. JASS:function OwnershipChange takes unit u, player x, player y, integer i returns nothing if (i==1) then call SetUnitOwner(u, x, false) elseif (i==2) then call SetUnitOwner(u, y, false) endif endfunction The reason I wanted to know which of the two triggers were faster in my first post is because I have a lot of "special towers" in my map that attack with spells or create special effects. I was wondering if I should have left them all in their own trigger or merge them into one function with a bunch of if/elseifs, because they all fire with the same Event, "EVENT_PLAYER_UNIT_ATTACKED". Here is what I have for the final trigger that contains all my spells. (It's rather large). I'm wondering if this is better than multiple triggers. JASS:function Master takes nothing returns nothing local unit u = GetAttacker() local unit t = GetTriggerUnit() local location l = GetUnitLoc(t) local integer id = GetUnitTypeId(u) local real r = GetUnitState(u, UNIT_STATE_MAX_MANA) //THIS SECTION HANDLES ANY SPELL ATTACKS THE TOWERS HAVE //RockGolems - Thunderclap if (id=='o02X') or (id=='o03T') then call IssueImmediateOrder(u, "thunderclap") //Root Tower - Entangle elseif (id=='h03U') then call IssueTargetOrder(u, "entanglingroots", t) //Storm Cloud / Thunder Cloud - Forked Lightning elseif (id=='h06E') or (id=='h06F') then call SetUnitState(u, UNIT_STATE_MANA, r * RMaxBJ(0,100) * 0.01) call IssueTargetOrder(u, "forkedlightning", t) //Mind Blaster / Mind Waster / The Moon / Lunar Eclipse / Priestess - Starfall elseif (id=='h01A') or (id=='h01S') or (id=='h03J') or (id=='h049') or (id=='o02U') then call IssueImmediateOrder(u, "starfall") //Chain Lightnign Caster / Chain Lightning Blaster - Chain Lightning elseif (id=='h00B') or (id=='hC36') then call SetUnitState(u, UNIT_STATE_MANA, r * RMaxBJ(0,100) * 0.01) call IssueTargetOrder(u, "chainlightning", t) //Cloud Strife - Bloodlust elseif (id=='e015') then call IssueTargetOrder(u, "bloodlust", u) //Death Tower - Instant Death elseif (id=='h03W') then call UnitDamageTarget(u, t, 1000000000, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS) //Gravity's Pull - Slow elseif (id=='h019') then if (not(IsUnitType(t, UNIT_TYPE_ANCIENT))) then call UnitAddType(t, UNIT_TYPE_ANCIENT) call IssueTargetOrder(u, "slow", t) call IssueImmediateOrder(u, "stop") endif call PolledWait(3) call UnitRemoveType(t, UNIT_TYPE_ANCIENT) //Soul Reaver Towers - TK Blast elseif (id=='oC65') or (id=='o00N') or (id=='o00M') or (id=='o00O') or (id=='o00P') or (id=='o00Q') or (id=='o00E') or (id=='o00I') or (id=='o00G') then call IssueTargetOrder(u, "thunderbolt", t) //Faerie Mage / Faerie Chansellor - Faerie Fire elseif (id=='o016') or (id=='oC26') then if (not(IsUnitType(t, UNIT_TYPE_ANCIENT))) then call UnitAddType(t, UNIT_TYPE_ANCIENT) call IssueTargetOrder(u, "faeriefire", t) call IssueImmediateOrder(u, "stop") endif call PolledWait(10) call UnitRemoveType(t, UNIT_TYPE_ANCIENT) //Noah - Stampede 1,2,3 elseif (id=='h06J') then call UnitAddAbility(u, 'A007') call IssuePointOrderLoc(u, "stampede", l) call TriggerSleepAction(2.5) call UnitRemoveAbility(u, 'A007') call UnitAddAbility(u, 'A017') call IssuePointOrderLoc(u, "stampede", l) call TriggerSleepAction(2.5) call UnitRemoveAbility(u, 'A017') call UnitAddAbility(u, 'A018') call IssuePointOrderLoc(u, "stampede", l) call TriggerSleepAction(2.5) call UnitRemoveAbility(u, 'A018') call UnitAddAbility(u, 'A007') //Overgrown Spike Plant / Warden - Fan of Knives elseif (id=='h036') or (id=='o05A') then call IssueImmediateOrder(u, "fanofknives") //Raziel - Earth Reaver Charged - Shock Wave elseif (id=='o00J') then call IssuePointOrderLoc(u, "shockwave", l) //Raziel - Fire Reaver Charged - War Stomp elseif (id=='o00H') then call IssueImmediateOrder(u, "stomp") //Raziel - Air Reaver Charged / Storm Mage - Cyclone elseif (id=='hC85') or (id=='o00F') then if (not(IsUnitType(t, UNIT_TYPE_ANCIENT))) then call UnitAddType(t, UNIT_TYPE_ANCIENT) call IssueTargetOrder(u, "cyclone", t) call IssueImmediateOrder(u, "stop") endif call PolledWait(6) call UnitRemoveType(t, UNIT_TYPE_ANCIENT) //The Sun / Solar Eclipse - Rain of Fire elseif (id=='h03P') or (id=='h048') then call IssuePointOrderLoc(u, "rainoffire", l) //The Void - Devour elseif (id=='o01W') then call IssueTargetOrder(u, "devour", t) //Lightning Rod / Telsa Rod - Lightning Shield elseif (id=='o00R') or (id=='oC60') then if (not(IsUnitType(t, UNIT_TYPE_ANCIENT))) then call UnitAddType(t, UNIT_TYPE_ANCIENT) call IssueTargetOrder(u, "lightningshield", t) call IssueImmediateOrder(u, "stop") endif call PolledWait(12) call UnitRemoveType(t, UNIT_TYPE_ANCIENT) //Web Tower / Marksman - Web elseif (IsUnitType(t, UNIT_TYPE_FLYING)) and (id=='h03T') or (id=='h044') then if (not(IsUnitType(t, UNIT_TYPE_ANCIENT))) then call UnitAddType(t, UNIT_TYPE_ANCIENT) call IssueTargetOrder(u, "web", t) call IssueImmediateOrder(u, "stop") endif call PolledWait(10) call UnitRemoveType(t, UNIT_TYPE_ANCIENT) //THIS SECTION HANDLES ANY SPECIAL EFFECTS THE TOWERS HAVE //Blast Furnace elseif (id=='o00Y') then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Demon\\ReviveDemon\\ReviveDemon.mdl", t, "origin")) //Blizzard Master elseif (id=='o00V') then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget.mdl", t, "origin")) //Fusion Canon / Ultra Fusion Canon elseif (id=='h01X') or (id=='h05H') then call DestroyEffect(AddSpecialEffectLoc("Objects\\Spawnmodels\\NightElf\\NECancelDeath\\NECancelDeath.mdl", l)) //Grave Marker / Grave Master elseif (id=='o014') or (id=='o01B') then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Orc\\Reincarnation\\ReincarnationTarget.mdl", t, "origin")) //Ion Canon / Ion Combuster elseif (id=='hC55') or (id=='h013') then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\ReviveNightElf\\ReviveNightElf.mdl", t, "origin")) //Meteor Watcher / Lunar Watcher elseif (id=='o00X') or (id=='o017') then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Demon\\RainOfFire\\RainOfFireTarget.mdl", t, "origin")) //Nova Creator elseif (id=='o00W') then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl", t, "origin")) //Nuclear Missile Silo elseif (id=='hC59') then call DestroyEffect(AddSpecialEffectLoc("Abilities\\Spells\\Human\\Flare\\FlareTarget.mdx", l)) //Poison Spire / Deadly Spire elseif (id=='h00N') or (id=='h00R') then call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", t, "origin")) //Ursula / Ursula Valkyrie / Berserker / Heavenly ArchAngel elseif (id=='h02J') or (id=='h02P') or (id=='oC73') or (id=='o022') or (id=='e00Q') then if (IsUnitType(u, UNIT_TYPE_FLYING)) then call DestroyEffect(AddSpecialEffectTarget("Units\\NightElf\\Wisp\\WispExplode.mdl", t, "origin")) endif endif call RemoveLocation(l) set u = null set t = null set l = null endfunction function InitTrig_MasterTrigger takes nothing returns nothing set gg_trg_MasterTrigger = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_MasterTrigger, EVENT_PLAYER_UNIT_ATTACKED) call TriggerAddAction(gg_trg_MasterTrigger, function Master) endfunction Before I had multiple triggers all with the same event. Would it have been better to keep it multiple triggers, or merge it into one function? |
| 09-14-2007, 09:40 PM | #6 |
Keep it multiple, I would imagine multiple triggers would be faster (at the worst it would be equal), but mainly keep it multiple for the sake of readability. Btw: Wtf are you doing with this function? oO. Why would you not just use SetUnitOwner? JASS:function OwnershipChange takes unit u, player x, player y, integer i returns nothing if (i==1) then call SetUnitOwner(u, x, false) elseif (i==2) then call SetUnitOwner(u, y, false) endif endfunction |
| 09-14-2007, 09:58 PM | #7 |
You should seriously knock any idea of "speed" out of your head and focus on organization of code. Splitting your spells into their own triggers is much more important than a 0.000000000001 second faster processing time. |
| 09-14-2007, 10:35 PM | #8 |
+ waits are evil *yep* |
| 09-14-2007, 10:37 PM | #9 |
/agree. The main place where you need to worry about speed is when something is looping on a short interval. |
| 09-15-2007, 07:45 AM | #10 |
That mess of sloppy code was what I made real fast by merging all triggers with the same event, to use as an example to show what I meant by which is better, one function for each "tower", or a ton of if/elseif. To TaintedReality: The purpose of the function is to swap players when a unit is sent, for the reason if too many units for one player are on the map at any time, moving them becomes a pain because they start to clutter. Using 3 players for units instead of one, makes things much smoother (3x the limit before they begin to clutter). JASS:function OwnershipChange takes unit u, player x, player y, integer i returns nothing if (i==1) then call SetUnitOwner(u, x, false) elseif (i==2) then call SetUnitOwner(u, y, false) endif endfunction function BuildUnitTopActions takes nothing returns nothing local location l local rect r local unit a local unit u = GetEnteringUnit() local player x = Player(6) local player y = Player(8) local player z = Player(10) local player p = GetOwningPlayer(u) local playercolor pc = GetPlayerColor(p) local integer pn = GetPlayerId(p)+1 local integer id = GetUnitTypeId(u) local integer pv = GetUnitPointValue(u) call RemoveUnit(u) if (udg_UnitPlayerTop==3) then set udg_UnitPlayerTop = 0 endif set r = gg_rct_Middle_Center_Bottom_Left set l = GetRectCenter(r) set a = CreateUnitAtLoc(x, id, l, 270) call OwnershipChange(a, y, z, udg_UnitPlayerTop) call GroupAddUnit(udg_UnitsCenterBottomLeft, a) call RemoveLocation(l) call SetUnitColor(a, pc) set r = gg_rct_Middle_Left_Bottom set l = GetRectCenter(r) call IssuePointOrderLoc(a, "move", l) call RemoveLocation(l) set r = gg_rct_Middle_Center_Bottom_Right set l = GetRectCenter(r) set a = CreateUnitAtLoc(x, id, l, 270) call OwnershipChange(a, y, z, udg_UnitPlayerTop) call GroupAddUnit(udg_UnitsCenterBottomRight, a) call RemoveLocation(l) call SetUnitColor(a, pc) set r = gg_rct_Middle_Right_Bottom set l = GetRectCenter(r) call IssuePointOrderLoc(a, "move", l) call RemoveLocation(l) set udg_UnitPlayerTop = (udg_UnitPlayerTop + 1) set udg_Income[pn] = (udg_Income[pn] + pv) set udg_TotalIncome1 = (udg_Income[1]+(udg_Income[2]+udg_Income[3])) call MultiboardSetItemValueBJ(udg_MB, 2, (pn + 1), I2S(udg_Income[pn])) call MultiboardSetItemValueBJ(udg_MB, 2, 5, I2S(udg_TotalIncome1)) call ConditionalTriggerExecute(gg_trg_UnitKillers) set l = null set r = null set a = null set u = null set x = null set y = null set z = null set p = null set pc = null endfunction function InitTrig_BuildUnitTop takes nothing returns nothing local region r2 = CreateRegion() set gg_trg_BuildUnitTop = CreateTrigger() call RegionAddRect(r2, gg_rct_Region_Top) call TriggerRegisterEnterRegion(gg_trg_BuildUnitTop, r2, null) call TriggerAddCondition(gg_trg_BuildUnitTop, Condition(function BuildUnit)) call TriggerAddAction(gg_trg_BuildUnitTop, function BuildUnitTopActions) set r2 = null endfunction It could probably be further optimized with a loop and a rect array but I'm too lazy. Anyway, the global integer variable "udg_UnitPlayerTop" keeps track of the current position of what player to make it next. In the trigger, 0 does nothing and keeps it player 7, 1 makes it player 9, and 2 makes it player 11. Then after it hits 3, it's reset to 0 again to start the cycle over. This is one of two identical triggers, and this method is used 4 times, figured it would be easier to just make one function. You have all been great help, thank you for all your advice. |
| 09-15-2007, 08:16 PM | #11 | |
Quote:
But it does *exactly* what SetUnitOwner does, but with extra parameters that have no purpose. So instead of calling OwnershipChange(u,p1,p2,1) you could just call SetUnitOwner(u,p1,false). |
| 09-15-2007, 11:08 PM | #12 |
I could if I put the function inside the trigger but like I said I use this same method 4 times so I just made it one function. JASS:function BuildUnitTopActions takes nothing returns nothing local location l local rect r local unit a local unit u = GetEnteringUnit() local player x = Player(6) local player y = Player(8) local player z = Player(10) local player p = GetOwningPlayer(u) local playercolor pc = GetPlayerColor(p) local integer pn = GetPlayerId(p)+1 local integer id = GetUnitTypeId(u) local integer pv = GetUnitPointValue(u) call RemoveUnit(u) if (udg_UnitPlayerTop==3) then set udg_UnitPlayerTop = 0 endif set r = gg_rct_Middle_Center_Bottom_Left set l = GetRectCenter(r) set a = CreateUnitAtLoc(x, id, l, 270) if (udg_UnitPlayerTop==1) then call SetUnitOwner(u, y, false) elseif (udg_UnitPlayerTop==2) then call SetUnitOwner(u, z, false) endif call GroupAddUnit(udg_UnitsCenterBottomLeft, a) call RemoveLocation(l) call SetUnitColor(a, pc) set r = gg_rct_Middle_Left_Bottom set l = GetRectCenter(r) call IssuePointOrderLoc(a, "move", l) call RemoveLocation(l) set r = gg_rct_Middle_Center_Bottom_Right set l = GetRectCenter(r) set a = CreateUnitAtLoc(x, id, l, 270) if (udg_UnitPlayerTop==1) then call SetUnitOwner(u, y, false) elseif (udg_UnitPlayerTop==2) then call SetUnitOwner(u, z, false) endif call GroupAddUnit(udg_UnitsCenterBottomRight, a) call RemoveLocation(l) call SetUnitColor(a, pc) set r = gg_rct_Middle_Right_Bottom set l = GetRectCenter(r) call IssuePointOrderLoc(a, "move", l) call RemoveLocation(l) set udg_UnitPlayerTop = (udg_UnitPlayerTop + 1) set udg_Income[pn] = (udg_Income[pn] + pv) set udg_TotalIncome1 = (udg_Income[1]+(udg_Income[2]+udg_Income[3])) call MultiboardSetItemValueBJ(udg_MB, 2, (pn + 1), I2S(udg_Income[pn])) call MultiboardSetItemValueBJ(udg_MB, 2, 5, I2S(udg_TotalIncome1)) call ConditionalTriggerExecute(gg_trg_UnitKillers) set l = null set r = null set a = null set u = null set x = null set y = null set z = null set p = null set pc = null endfunction function InitTrig_BuildUnitTop takes nothing returns nothing local region r2 = CreateRegion() set gg_trg_BuildUnitTop = CreateTrigger() call RegionAddRect(r2, gg_rct_Region_Top) call TriggerRegisterEnterRegion(gg_trg_BuildUnitTop, r2, null) call TriggerAddCondition(gg_trg_BuildUnitTop, Condition(function BuildUnit)) call TriggerAddAction(gg_trg_BuildUnitTop, function BuildUnitTopActions) set r2 = null endfunction The whole idea is to switch players every time its run for 3 times, then reset, because moving 3 players doesn't clutter like moving one. I can't think of a better way to do it, if there is one. |
| 09-15-2007, 11:22 PM | #13 |
I understand the 3 players thing, but that function has no purpose. It's not really a big deal though and I think we're both misunderstanding each other =p. |
