calref / cboe

Classic Blades of Exile
http://spiderwebforums.ipbhost.com/index.php?/forum/12-blades-of-exile/
Other
168 stars 41 forks source link

Leaving ZKR starting fort through the south gate (by abnormal means) and traveling a few steps south leads to a crash #240

Open x-qq opened 4 years ago

x-qq commented 4 years ago

The issue was identifies as trying to check if the tile has a road in a next sector to the south.

Save attached - move 1 tile south.

zkr_road_check_crash.exg.zip

Backtrace:

Thread 1 "Blades of Exile" received signal SIGSEGV, Segmentation fault.
-----------------------------------------------------------------------------------------------------------------------[regs]
  RAX: 0x0000000000000EA9  RBX: 0x000000000000000F  RCX: 0x0000000000000000  RDX: 0x000000000000000E  o d I t s z a P c 
  RSI: 0x00000000000000C1  RDI: 0x000055555598AE20  RBP: 0x00007FFFFFFFA580  RSP: 0x00007FFFFFFFA540  RIP: 0x000055555570D6A0
  R8 : 0x000000000000000F  R9 : 0x0000555556BF01E0  R10: 0x0000000000000006  R11: 0x000055555652FD50  R12: 0x000055555557CE10
  R13: 0x0000000000000000  R14: 0x0000000000000000  R15: 0x0000000000000000
  CS: 0033  DS: 0000  ES: 0000  FS: 0000  GS: 0000  SS: 002B                
-----------------------------------------------------------------------------------------------------------------------[code]
=> 0x55555570d6a0 <cCurOut::is_road(int, int)+192>: movzx  eax,BYTE PTR [rax]
   0x55555570d6a3 <cCurOut::is_road(int, int)+195>: add    rsp,0x38
   0x55555570d6a7 <cCurOut::is_road(int, int)+199>: pop    rbx
   0x55555570d6a8 <cCurOut::is_road(int, int)+200>: pop    rbp
   0x55555570d6a9 <cCurOut::is_road(int, int)+201>: ret    
   0x55555570d6aa <cUniverse::cUniverse(long)>: push   rbp
   0x55555570d6ab <cUniverse::cUniverse(long)+1>:   mov    rbp,rsp
   0x55555570d6ae <cUniverse::cUniverse(long)+4>:   push   rbx
-----------------------------------------------------------------------------------------------------------------------------
0x000055555570d6a0 in cCurOut::is_road (this=0x55555599fa98 <univ+87256>, x=0xe, y=0x0) at src/universe/universe.cpp:904
904     return univ.scenario.outdoors[sector_x][sector_y]->roads[x][y];
gdb$ bt full
#0  0x000055555570d6a0 in cCurOut::is_road (this=0x55555599fa98 <univ+87256>, x=0xe, y=0x0) at src/universe/universe.cpp:904
        sector_x = 0x0
        sector_y = 0xf
#1  0x0000555555602669 in draw_terrain (mode=0x0) at build/obj/game/boe.graphics.cpp:901
        r = 0x8
        q = 0x0
        where_draw = {x = 0xe, y = 0x30}
        sector_p_in = {x = 0x0, y = 0xe}
        view_loc = {x = 0x0, y = 0x0}
        can_draw = 0x1
        spec_terrain = 0x0
        off_terrain = 0x0
        draw_frills = 0x1
        frills_on = 0x1
#2  0x00005555555848f3 in handle_action (event=...) at build/obj/game/boe.actions.cpp:1420
        s1 = 0x0
        s2 = 0x0
        s3 = 0x0
        item_hit = 0x0
        are_done = 0x0
        need_redraw = 0x1
        did_something = 0x1
        need_reprint = 0x0
        pc_delayed = 0x0
        cur_loc = {x = 0x12, y = 0x2b}
        loc_in_sec = {x = 0x0, y = 0x0}
        cur_direction = {x = 0x0, y = 0x1}
        button_hit = 0xc
        right_button = 0x0
        previous_mode = 3208677224
        world_screen = {top = 0x14, left = 0x20, bottom = 0x159, right = 0x11d}
        str = <incomplete type>
        the_point = {x = 0x95, y = 0xd7}
        point_in_area = {x = 0x0, y = 0x0}
#3  0x00005555555860ff in handle_keystroke (event=...) at build/obj/game/boe.actions.cpp:1680
        i = 0x2
        are_done = 0x0
        pass_point = {x = 0x12b, y = 0x1ae}
        sout = <incomplete type>
        keypad = {sf::Keyboard::Numpad0, sf::Keyboard::Numpad1, sf::Keyboard::Numpad2, sf::Keyboard::Numpad3, sf::Keyboard::Numpad4, sf::Keyboard::Numpad5, sf::Keyboard::Numpad6, sf::Keyboard::Numpad7, sf::Keyboard::Numpad8, sf::Keyboard::Numpad9}
        terrain_click = {{x = 0x96, y = 0xb9}, {x = 0x78, y = 0xd7}, {x = 0x96, y = 0xd7}, {x = 0xb4, y = 0xd7}, {x = 0x78, y = 0xb9}, {x = 0x96, y = 0xb9}, {x = 0xb4, y = 0xb9}, {x = 0x78, y = 0x9b}, {x = 0x96, y = 0x9b}, {x = 0xb4, y = 0x87}}
        talk_chars = {sf::Keyboard::L, sf::Keyboard::N, sf::Keyboard::J, sf::Keyboard::B, sf::Keyboard::S, sf::Keyboard::R, sf::Keyboard::D, sf::Keyboard::G, sf::Keyboard::A}
        shop_chars = {sf::Keyboard::A, sf::Keyboard::B, sf::Keyboard::C, sf::Keyboard::D, sf::Keyboard::E, sf::Keyboard::F, sf::Keyboard::G, sf::Keyboard::H}
        chr2 = sf::Keyboard::Numpad2
        pass_event = {type = sf::Event::MouseButtonPressed, {size = {width = 0x0, height = 0x12b}, key = {code = sf::Keyboard::A, alt = 0x2b, control = 0x1, shift = 0x0, system = 0x0}, text = {unicode = 0x0}, mouseMove = {x = 0x0, y = 0x12b}, mouseButton = {button = sf::Mouse::Left, x = 0x12b, y = 0x1ae}, mouseWheel = {delta = 0x0, x = 0x12b, y = 0x1ae}, mouseWheelScroll = {wheel = sf::Mouse::VerticalWheel, delta = 4.18988241e-43, x = 0x1ae, y = 0x0}, joystickMove = {joystickId = 0x0, axis = 299, position = 6.0255834e-43}, joystickButton = {joystickId = 0x0, button = 0x12b}, joystickConnect = {joystickId = 0x0}, touch = {finger = 0x0, x = 0x12b, y = 0x1ae}, sensor = {type = sf::Sensor::Accelerometer, x = 4.18988241e-43, y = 6.0255834e-43, z = 0}}}
        chr = 0xa2
#4  0x00005555556336e1 in Handle_One_Event () at build/obj/game/boe.main.cpp:257
        twentyTicks = 0x14d
        fortyTicks = 0x29a
#5  0x0000555555632bc0 in main (argc=0x1, argv=0x7fffffffde78) at build/obj/game/boe.main.cpp:137
        remaining_time_budget_in_us = 0x38bc
        framerate_clock = {m_startTime = {static Zero = {static Zero = <same as static member of an already seen type>, m_microseconds = 0x0}, m_microseconds = 0x2884dd32b}}
        desired_microseconds_per_frame = 0x411a
gdb$
CelticMinstrel commented 4 years ago

More precisely, it's trying to access the next sector to the south, which doesn't exist. We either need to enable "dummy" values if the view scrolls off the edge of the map, or have some special case so that it doesn't scroll at all when you're at the edge.

retropipes commented 4 years ago

You could also use a system like what Realmz does here: setting invalid map sectors to ID -1, and checking for that ID before attempting to load an adjacent section. If there’s no sector there, don’t scroll the map past what would be the transition point.

CelticMinstrel commented 4 years ago

I think that's basically the sort of idea I meant here:

have some special case so that it doesn't scroll at all when you're at the edge.

The other method is probably easier, but then you'd see blackness or something beyond the edge. On the other hand, that might be okay - scenarios are supposed to be structured so you can't get that close, anyway. As long as it doesn't crash…

NQNStudios commented 2 weeks ago

Loading this save file and moving south in the current build, I don't get a crash.

CelticMinstrel commented 2 weeks ago

Responding to what you said on IRC…

[01:45am] NQNStudios: celticminstrel did outdoor sections used to be 96x96 tiles? [01:46am] NQNStudios: I reproduced this bug by making a scenario with no walls blocking the south boundary https://github.com/calref/cboe/issues/240 [01:46am] NQNStudios: it's boundary checking for 96, but the outdoor section is actually 48x48 [02:02am] NQNStudios: ohhhhh would it be 96 because multiple sections could be in the vector it's checking?

The original game loads 4 outdoor sections into a 96x96 combined grid, shifting them as you move around the outdoors. I don't think I remember altering that aspect.