EngineHub / CommandHelper

Rapid scripting and command aliases for Minecraft owners
https://methodscript.com
Other
119 stars 71 forks source link

Bug in parenthesis based execution #1323

Closed LadyCailin closed 1 year ago

LadyCailin commented 2 years ago

The following code causes a repro:

register_command('astralproject', 
  array(

    'description': 'Use it like /locate', 
    'usage': colorize('&cExample: /astralproject structure village_desert'), 
    'permission': 'command.astralproject', 
    'noPermMsg': 'Sorry you don\'t have permission to use this command.', 
    'executor': closure(@alias, @player, @args) {

      if(array_size(@args) != 2){
        return(false)
      }

      @tasks = array(
        array(1000, closure() {
          tmsg(@player, 'Meditating...')
          set_peffect(@player, 'DARKNESS', 1, 7, true, false)
          set_peffect(@player, 'BLINDNESS', 1, 7, true, false)
        }),
        array(1000, closure() {
          tmsg(@player, '...')
        }),
        array(1000, closure() {
          tmsg(@player, '...')
        }),
        array(1000, closure() {
          tmsg(@player, '..')
        }),
        array(1000, closure() {
          tmsg(@player, '..')
        }),
        array(1000, closure() {
          tmsg(@player, '.')
        }),
        array(1500, closure() {
          runas('~console', '/lp user '.@player.' permission settemp minecraft.command.locate true 1s world=moddedsurvival')
        }),
        array(1000, closure() {
          //runas(@player, '/locate '.array_implode(@args))
          tmsg(@player, 'AH')
        })
      )

      @taskIndContainer = array(0)
      @executeTaskContainer = array()
      @lastScheduledTaskIdContainer = array(null)
      @executeTaskContainer[] = closure() {
        // this does not
        console('2')
        if(@taskIndContainer[0] < array_size(@tasks)) {

          # Schedule task.
          @task = @tasks[@taskIndContainer[0]++]
          @lastScheduledTaskIdContainer[0] = set_timeout(@task[0], closure() {

            # Run task.
            @task[1]()

            # Recursive call to this closure to schedule the next task.
            @executeTaskContainer[0]()
          })
        }
      }

      // this prints
      console('1')
      @executeTaskContainer[0]()

      if(!has_bind(@player.'astralProjectMove')){
        bind('player_move', array(id: @player.'astralProjectMove'), array(player: @player), @event, @lastScheduledTaskIdContainer){
            @player = @event['player']
            tmsg(@player, colorize('&7Meditation interrupted.'))
            clear_task(@lastScheduledTaskIdContainer[0])
            unbind(@player.'astralProjectCommand')
            unbind(@player.'astralProjectChat')
            unbind(@player.'astralProjectMove')
        }
      }

      if(!has_bind(@player.'astralProjectChat')){
        bind('player_chat', array(id: @player.'astralProjectChat'), array(player: @player), @event, @lastScheduledTaskIdContainer){
            @player = @event['player']
            tmsg(@player, colorize('&7Meditation interrupted.'))
            clear_task(@lastScheduledTaskIdContainer[0])
            unbind(@player.'astralProjectCommand')
            unbind(@player.'astralProjectMove')
            unbind(@player.'astralProjectChat')
        }
      }

      if(!has_bind(@player.'astralProjectCommand')){
        bind('player_command', array(id: @player.'astralProjectCommand'), array(player: @player), @event, @lastScheduledTaskIdContainer){
            @player = @event['player']
            tmsg(@player, colorize('&7Meditation interrupted.'))
            clear_task(@lastScheduledTaskIdContainer[0])
            unbind(@player.'astralProjectChat')
            unbind(@player.'astralProjectMove')
            unbind(@player.'astralProjectCommand')
        }
      }
    }
  )
)
Pieter12345 commented 1 year ago

This can be reproduced through example program:

@closureArray = array(closure() {
    console('This does not execute.')
})
console('This executes.')
@closureArray[0]()
console('Code below execution required for the bug to occur.')

Running optimizer-test on this program and manually formatting it results in:

__statements__(
    assign(@closureArray, array(closure(console('This does not execute.')))),
    console('This executes.'),
    array_get(@closureArray, 0),
    __autoconcat__(),
    console('Code below execution required for the bug to occur.')
)