MUI

From WarCraft3

< wc3
Jump to: navigation, search

What is MUI?

MUI stands for Multi-Unit Instance-ability, that is, whether or not code can be run with multiple units at the same time without bugging. Contrary to popular belief, there isn't really any specific way of defining a code as 'MUI'. Instead, code is deemed not-MUI when it bugs with multiple instances of the code running, usually caused from variables being overwritten. When it is said that a script or trigger is MUI, it means that multiple instances can be running at a time with no bugs. Any code that is executed instantly is automatically MUI.

Detailed Examples

When trigger fires it is called a trigger instance.

This is a simple trigger which is not MUI (written in GUI):

Timed Special Effect
    Events
        Player - Player 1 (Red) skips a cinematic sequence
    Conditions
    Actions
        Special Effect - Create a special effect at (Center of (Playable map area)) using units\human\Footman\Footman.mdl
        Wait 10.00 game-time seconds
        Special Effect - Destroy (Last created special effect)

'Last created special effect' is a Blizzard made variable which can store only one value at any given time. Each instance is forced to use the same variable. Conflicts here usually occur because variable resources are limited while there is no fire limit for instances.

A solution is to use a timer in conjunction with a group of variable arrays. It gives a total of 8191 (2^13 - 1, the max size of an array) properly working instances.

Here is an example of a trigger using a timer with a group of variable arrays to achieve MUI:

    Actions
        Set instanceIndex = (instanceIndex + 1)
        Special Effect - Create a special effect at (Center of (Playable map area)) using units\human\Footman\Footman.mdl
        Set instanceSpecialEffect[instanceIndex] = (Last created special effect)

First things first, an instance assigned a unique integer. The effect will be stored within an effect array using that unique integer. The duration the effect will last requires storage as well.

Actions
    Set instanceIndex = (instanceIndex + 1)
    Special Effect - Create a special effect at (Center of (Playable map area)) using units\human\Footman\Footman.mdl
    Set instanceSpecialEffect[instanceIndex] = (Last created special effect)
    Set instanceWait[instanceIndex] = 10.00

Using such indexing methods are called parallel arrays (global arrays). Lastly, timer expiration needs to be set. One timer can handle all instances, but it is important that you know the exact waiting time.

Actions
    Set instanceIndex = (instanceIndex + 1)
    Special Effect - Create a special effect at (Center of (Playable map area)) using units\human\Footman\Footman.mdl
    Set instanceSpecialEffect[instanceIndex] = (Last created special effect)
    Set instanceWait[instanceIndex] = 10.00
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        If - Conditions
            instanceIndex Equal to 1
        Then - Actions
            Countdown Timer - Start userCreatedTimer as a One-shot timer that will expire in 10.00 seconds
            Skip remaining actions
        Else - Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        If - Conditions
            (Remaining time for userCreatedTimer) Greater than instanceWait[instanceIndex]
        Then - Actions
            Countdown Timer - Pause userCreatedTimer
            Countdown Timer - Start userCreatedTimer as a One-shot timer that will expire in instanceWait[instanceIndex] seconds
        Else – Actions

When the timer expires, we loop through all instances. If an instance has reached its lifespan, we finish the spell. If there are still instances left, we restart the timer.

Destroy Timer Special Effect
    Events
        Time - userCreatedTimer expires
    Conditions
    Actions
        For each (Integer instanceLoopIndex) from 1 to instanceIndex, do (Actions)
            Loop - Actions
                Set instanceWait[instanceLoopIndex] = (instanceWait[instanceLoopIndex] - (Elapsed time for userCreatedTimer))

This is variable loop with subtracting from currently handled instance duration elapsed time (instanceLoopIndex variable). If wait variable becomes zero or less its time to end instance. This means destroying special effect and doing variable recycling. By variable recycling last instance data (instanceIndex) is moved to current instance (instanceLoopIndex) and last index freed (by lowering instance max count by one):

Actions
    For each (Integer instanceLoopIndex) from 1 to instanceIndex, do (Actions)
        Loop - Actions
            Set instanceWait[instanceLoopIndex] = (instanceWait[instanceLoopIndex] - (Elapsed time for userCreatedTimer))
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                If - Conditions
                    instanceWait[instanceLoopIndex] Greater than 0.00
                    instanceWait[instanceLoopIndex] Less than instanceNewWait
                Then - Actions
                    Set instanceNewWait = instanceWait[instanceLoopIndex]
                Else – Actions

This If/Then/Else action picks out shortest wait time which is used later for new expiration time. Another If/Then/Else action checks does instance needs destroying and when it is true last instance is replaced with it and max instances decreased by one. Loop needs to check once more same index because now it holds new instance:

Actions
    For each (Integer instanceLoopIndex) from 1 to instanceIndex, do (Actions)
        Loop - Actions
            Set instanceWait[instanceLoopIndex] = (instanceWait[instanceLoopIndex] - (Elapsed time for userCreatedTimer))
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                If - Conditions
                    instanceWait[instanceLoopIndex] Greater than 0.00
                    instanceWait[instanceLoopIndex] Less than instanceNewWait
                Then - Actions
                    Set instanceNewWait = instanceWait[instanceLoopIndex]
                Else - Actions
            If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                If - Conditions
                    instanceWait[instanceLoopIndex] Less than or equal to 0.00
                Then - Actions
                    Special Effect - Destroy instanceSpecialEffect[instanceLoopIndex]
                    Set instanceSpecialEffect[instanceLoopIndex] = instanceSpecialEffect[instanceIndex]
                    Set instanceWait[instanceLoopIndex] = instanceWait[instanceIndex]
                    Set instanceLoopIndex = (instanceLoopIndex - 1)
                    Set instanceIndex = (instanceIndex - 1)
                Else – Actions

Good practice is not to nest If/Then/Else actions. Try to avoid adding new If/Then/Else action to another If/Then/Else 'Else' actions. It makes code easier to understand.

When loop has ended expired instances and there are still more instances left which need to wait timer is started with shortest wait time. Before not done, but required is to set 'instanceNewWait' before loop start to value, that value could be default duration or bigger value. It is needed for new wait time comparison:

Destroy Timer Special Effect
    Events
        Time - userCreatedTimer expires
    Conditions
    Actions
        Set instanceNewWait = 10.00
        For each (Integer instanceLoopIndex) from 1 to instanceIndex, do (Actions)
            Loop - Actions
                Set instanceWait[instanceLoopIndex] = (instanceWait[instanceLoopIndex] - (Elapsed time for userCreatedTimer))
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        instanceWait[instanceLoopIndex] Greater than 0.00
                        instanceWait[instanceLoopIndex] Less than instanceNewWait
                    Then - Actions
                        Set instanceNewWait = instanceWait[instanceLoopIndex]
                    Else - Actions
                If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    If - Conditions
                        instanceWait[instanceLoopIndex] Less than or equal to 0.00
                    Then - Actions
                        Special Effect - Destroy instanceSpecialEffect[instanceLoopIndex]
                        Set instanceSpecialEffect[instanceLoopIndex] = instanceSpecialEffect[instanceIndex]
                        Set instanceWait[instanceLoopIndex] = instanceWait[instanceIndex]
                        Set instanceLoopIndex = (instanceLoopIndex - 1)
                        Set instanceIndex = (instanceIndex - 1)
                    Else - Actions
        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            If - Conditions
                instanceIndex Greater than 0
            Then - Actions
                Countdown Timer - Start userCreatedTimer as a One-shot timer that will expire in instanceNewWait seconds
            Else – Actions

MUI in GUI can also be achieved by using hashtables as an attachment method.

Personal tools