UnderminersTeam / UndertaleModTool

The most complete tool for modding, decompiling and unpacking Undertale (and other Game Maker: Studio games!)
GNU General Public License v3.0
1.07k stars 205 forks source link

Deltarune PC "gml_Object_obj_mainchara_Step_0" infinite loop freeze between lines 286-316 #224

Open Grossley opened 4 years ago

Grossley commented 4 years ago

If Kris runs into a corner the game freezes. The cause is probably due to a missing "break" after "bkxy = 1" in the following section (lines 288-293) :

It currently decompiles to this:

            if (!place_meeting((x + i), (y + j), obj_solidblock))
            {
                px = i
                py = j
                bkxy = 1
            }

But it should decompile to this:

            if (!place_meeting((x + i), (y + j), obj_solidblock))
            {
                px = i
                py = j
                bkxy = 1
                break;
            }
Kneesnap commented 4 years ago

This should be tested after the decompiler is rewritten.

Grossley commented 4 years ago

This same error also occurs in "gml_Object_obj_heart_Step_0" between lines 177 and 182:

It decompiles to this:

        if (!place_meeting((x + i), (y + j), obj_battlesolid))
        {
            px = i
            py = j
            bkxy = 1
        }

When it should decompile to this:

        if (!place_meeting((x + i), (y + j), obj_battlesolid))
        {
            px = i
            py = j
            bkxy = 1
            break;
        }
H-A-M-G-E-R commented 1 year ago

how to debug the decompiler to fix the bug

Jacky720 commented 1 year ago

a) remake the decompiler from scratch b) as a workaround, manually add the break to the decompiled code and do future edits to that code entry in an external editor that won't invoke the decompiler, or using the tool's "profile mode" that does the same in the built-in editor.

H-A-M-G-E-R commented 1 year ago

the decompiler can easily be fooled by unreachable sections

Jacky720 commented 1 year ago

I don't understand. There isn't anything unreachable here, it's just break/continue statements that don't work sometimes.

H-A-M-G-E-R commented 1 year ago

there's unreachable assembly in gml_Object_obj_heart_Step_0 look at the line that says ":[27]" of the assembly

H-A-M-G-E-R commented 1 year ago

i don't know gml assembly very well..

H-A-M-G-E-R commented 1 year ago

in lines 36-55 of gml_Object_DEVICE_CHOICE_Step_0 it should decompile to this:

            while move
            {
                ccc = NAME[CURX, CURY]
                if (ccc == ">")
                    CURX += 1
                else if (ccc == "<")
                    CURX -= 1
                else
                    move = 0
            }

instead of this:

            if move
            {
                ccc = NAME[CURX, CURY]
                if (ccc == ">")
                    CURX += 1
                else if (ccc == "<")
                    CURX -= 1
                else
                    move = 0
                while move
                {
                    ccc = NAME[CURX, CURY]
                    if (ccc == ">")
                        CURX += 1
                    else if (ccc == "<")
                        CURX -= 1
                    else
                        move = 0
                }
            }
H-A-M-G-E-R commented 1 year ago

there are unnessessary elses and continues in gml_Object_obj_heart_Step_0 that change the compiled assembly that's the problem

H-A-M-G-E-R commented 1 year ago

gml_Script_scr_armorget should decompile to this:

i = 0
loop = true
noroom = false
global.armor[12] = 999
while (loop == true)
{
    if (global.armor[i] == 0)
    {
        global.armor[i] = argument0
        break
    }
    if (i == 12)
    {
        noroom = true
        break
    }
    i += 1
}
script_execute(scr_armorinfo_all)
H-A-M-G-E-R commented 1 year ago

For reference, here's what gml_Object_obj_heart_Step_0 should decompile to:

wallcheck = 0
press_l = 0
press_r = 0
press_d = 0
press_u = 0
bkx = 0
bky = 0
bkxy = 0
jelly = 2
if left_h()
    press_l = 1
if right_h()
    press_r = 1
if up_h()
    press_u = 1
if down_h()
    press_d = 1
px = 0
py = 0
if (press_r == 1)
    px = wspeed
if (press_l == 1)
    px = (-wspeed)
if (press_d == 1)
    py = wspeed
if (press_u == 1)
    py = (-wspeed)
xmeet = 0
ymeet = 0
xymeet = 0
if place_meeting((x + px), (y + py), obj_battlesolid)
    xymeet = 1
if place_meeting((x + px), y, obj_battlesolid)
{
    if place_meeting((x + px), y, obj_battlesolid)
    {
        g = wspeed
        while (g > 0)
        {
            mvd = 0
            if (press_d == 0 && (!(place_meeting((x + px), (y - g), obj_battlesolid))))
            {
                y -= g
                py = 0
                break
                mvd = 1
            }
            if (press_u == 0 && mvd == 0 && (!(place_meeting((x + px), (y + g), obj_battlesolid))))
            {
                y += g
                py = 0
                break
            }
            g -= 1
        }
    }
    xmeet = 1
    bkx = 0
    if (px > 0)
    {
        i = px
        while (i >= 0)
        {
            if (!(place_meeting((x + i), y, obj_battlesolid)))
            {
                px = i
                bkx = 1
                break
            }
            i -= 1
        }
    }
    if (px < 0)
    {
        i = px
        while (i <= 0)
        {
            if (!(place_meeting((x + i), y, obj_battlesolid)))
            {
                px = i
                bkx = 1
                break
            }
            i += 1
        }
    }
    if (bkx == 0)
        px = 0
}
if place_meeting(x, (y + py), obj_battlesolid)
{
    ymeet = 1
    bky = 0
    if place_meeting(x, (y + py), obj_battlesolid)
    {
        g = wspeed
        while (g > 0)
        {
            mvd = 0
            if (press_r == 0 && (!(place_meeting((x - g), (y + py), obj_battlesolid))))
            {
                x -= g
                px = 0
                break
                mvd = 1
            }
            if (mvd == 0 && press_l == 0 && (!(place_meeting((x + g), (y + py), obj_battlesolid))))
            {
                x += g
                px = 0
                break
            }
            g -= 1
        }
    }
    if (py > 0)
    {
        i = py
        while (i >= 0)
        {
            if (!(place_meeting(x, (y + i), obj_battlesolid)))
            {
                py = i
                bky = 1
                break
            }
            i -= 1
        }
    }
    if (py < 0)
    {
        i = py
        while (i <= 0)
        {
            if (!(place_meeting(x, (y + i), obj_battlesolid)))
            {
                py = i
                bky = 1
                break
            }
            i += 1
        }
    }
    if (bky == 0)
        py = 0
}
if place_meeting((x + px), (y + py), obj_battlesolid)
{
    xymeet = 1
    bkxy = 0
    i = px
    j = py
    while (j != 0 || i != 0)
    {
        if (!(place_meeting((x + i), (y + j), obj_battlesolid)))
        {
            px = i
            py = j
            bkxy = 1
            break
        }
        if (abs(j) >= 1)
        {
            if (j > 0)
                j -= 1
            if (j < 0)
                j += 1
        }
        else
            j = 0
        if (abs(i) >= 1)
        {
            if (i > 0)
                i -= 1
            if (i < 0)
                i += 1
        }
        else
            i = 0
    }
    if (bkxy == 0)
    {
        px = 0
        py = 0
    }
}
if ((x + px) >= ((__view_get(0, 0) + 640) - sprite_width))
    px = (((__view_get(0, 0) + 640) - sprite_width) - x)
if ((x + px) <= 0)
    px = (-x)
if ((y + py) <= 0)
    py = (-y)
if ((y + py) >= (((__view_get(1, 0) + 320) - sprite_height) + boundaryup))
    py = ((((__view_get(1, 0) + 320) - sprite_height) - y) + boundaryup)
x += px
y += py
if (dmgnoise == true)
{
    dmgnoise = false
    snd_stop(snd_hurt1)
    snd_play(snd_hurt1)
}
global.inv -= 1
if (global.inv > 0)
    image_speed = 0.25
else
{
    image_speed = 0
    image_index = 0
}
global.heartx = ((x + 2) - __view_get(0, 0))
global.hearty = ((y + 2) - __view_get(1, 0))