• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Lua Function Game.loadMapChunk(path, position, remove)

Infernum

Senator
Joined
Feb 14, 2015
Messages
5,643
Solutions
559
Reaction score
3,948
Loads/unloads an OTBM file live into your server by using an offset.
File must be mapped starting from x:0 y:0 coordinates to make offset work properly.

Params:
Path: The path to the OTBM file (with the .otbm extension in it, example "data/world/test.otbm")
Position: The position offset (remember to put the map you're loading at x:0 y:0 in map editor so the offset works properly, example: Position(1000, 1000, 0) will offset x with +1000, y +1000, and z +0, so the map will load at Position(1000, 1000, 7) if you map it on the 7th floor)
Remove: Boolean, true makes it remove all items instead of adding them, if you want to just add/load the chunk you don't have to set this argument or set it to false if you do.

Code: otland/forgottenserver (https://github.com/otland/forgottenserver/compare/master...infernumx:dynamicMapLoader)

Example:
Lua:
Game.loadMapChunk("data/world/test.otbm", Position(1000, 1000, 0)) -- load the chunk
addEvent(Game.loadMapChunk, 10000, "data/world/test.otbm", Position(1000, 1000, 0), true) -- remove it after 10 sec
 
Last edited:
This...
This, sir, is a big thing especially if you want event's to trigger different pieces of map.
I am impressed.
 
Awesome script :D Thanks.
I have one bug. After unload map, server down and i get error on console
"Segmentation fault (core dumped)"
Anyone notice it? Any issue?
My lua for it:
Lua:
function onSay(player, words)
    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Map added");
    Game.loadMapChunk("data/world/test.otbm", Position(0, 0, 0));
    addEvent(Game.loadMapChunk, 60*1000, "data/world/test.otbm", Position(0, 0, 0), true);
    return false;
end

Also when I give Position(6000, 6000, 0) where is nothing on my map, I'm getting same error while unload.
 
Last edited:
Could you send a stacktrace by using gdb or run it through visual studio debugger (if you're using windows)?
 
Could you send a stacktrace by using gdb or run it through visual studio debugger (if you're using windows)?
I took a quick look and it seems that you are referencing a destroyed item when unloaded is set to true:
C++:
if (item->isRemoved()) {
    item->onRemoved();
    item->decrementReferenceCounter();//Item destroyed(use g_game.ReleaseItem for it? or just destroy it after postRemoveNotification)
}

tile->postRemoveNotification(item, nullptr, index);//Referencing destroyed Item
 
Can I simply make a big giant line of tiles from my map to the position (0,0,0)? Or add 1 tile at (0,0,0)?
By the way, awesome!

Edit: added 1 tile at (0,0,0):

Code:
<globalevent name="ReloadMap" time="21:04:00" script="reloadmap.lua"/>

Code:
function onTime(interval)
    broadcastMessage("Reloading map", MESSAGE_STATUS_WARNING)
    Game.loadMapChunk("data/world/forgottenworld1098oldglobal.otbm", Position(1000, 1000, 0)) -- load the chunk
    addEvent(Game.loadMapChunk, 10000, "data/world/forgottenworld1098oldglobal.otbm", Position(1000, 1000, 0), true) -- remove it after 10 sec
    return true
end

Code:
God has logged in.
> Broadcasted message: "Reloading map".
> Map size: 33945x33071.
Duplicate unique id: 50001
Duplicate unique id: 50007
Duplicate unique id: 50003
Duplicate unique id: 50009
Duplicate unique id: 50010
Duplicate unique id: 50014
Duplicate unique id: 50015
Duplicate unique id: 50013
Duplicate unique id: 50004
Duplicate unique id: 50005
Duplicate unique id: 50002
Duplicate unique id: 50008
Duplicate unique id: 50011
Duplicate unique id: 50016
Duplicate unique id: 50012
Duplicate unique id: 50006
Duplicate unique id: 1062
Duplicate unique id: 1063
Duplicate unique id: 1064
Duplicate unique id: 1061
Duplicate unique id: 1060
Duplicate unique id: 1033
Duplicate unique id: 1034
Duplicate unique id: 1035
Duplicate unique id: 1082
Duplicate unique id: 1096
Duplicate unique id: 1097
Duplicate unique id: 50101
Duplicate unique id: 50114
Duplicate unique id: 50115
Duplicate unique id: 50116
Duplicate unique id: 50117
Duplicate unique id: 50102
Duplicate unique id: 50103
Duplicate unique id: 50104
Duplicate unique id: 50107
Duplicate unique id: 50106
Duplicate unique id: 50105
Duplicate unique id: 1013
Duplicate unique id: 1014
Duplicate unique id: 1011
Duplicate unique id: 1065
Duplicate unique id: 1017
Duplicate unique id: 1015
Duplicate unique id: 1016
Duplicate unique id: 1075
Duplicate unique id: 1076
Duplicate unique id: 1077
Duplicate unique id: 1041
Duplicate unique id: 1040
Duplicate unique id: 1039
Duplicate unique id: 1038
Duplicate unique id: 1037
Duplicate unique id: 1058
Duplicate unique id: 1072
Duplicate unique id: 1012
Duplicate unique id: 1093
Duplicate unique id: 23203
Duplicate unique id: 4038
Duplicate unique id: 4039
Duplicate unique id: 1094
Duplicate unique id: 1095
Duplicate unique id: 23202
Duplicate unique id: 4033
Duplicate unique id: 1090
Duplicate unique id: 4034
Duplicate unique id: 1091
Duplicate unique id: 1092
Duplicate unique id: 23201
Duplicate unique id: 4028
Duplicate unique id: 1087
Duplicate unique id: 1088
Duplicate unique id: 4029
Duplicate unique id: 1089
Duplicate unique id: 1051
Duplicate unique id: 1050
Duplicate unique id: 1049
Duplicate unique id: 1048
Duplicate unique id: 1047
Duplicate unique id: 1046
Duplicate unique id: 50110
Duplicate unique id: 1057
Duplicate unique id: 1056
Duplicate unique id: 1055
Duplicate unique id: 1054
Duplicate unique id: 1053
Duplicate unique id: 1052
Duplicate unique id: 50109
Duplicate unique id: 50108
Duplicate unique id: 1018
Duplicate unique id: 1019
Duplicate unique id: 1020
Duplicate unique id: 1001
Duplicate unique id: 1002
Duplicate unique id: 1003
Duplicate unique id: 1074
Duplicate unique id: 1073
Duplicate unique id: 1045
Duplicate unique id: 1078
Duplicate unique id: 1079
Duplicate unique id: 1080
Duplicate unique id: 1081
Duplicate unique id: 1021
Duplicate unique id: 1022
Duplicate unique id: 1083
Duplicate unique id: 1059
Duplicate unique id: 1023
Duplicate unique id: 1025
Duplicate unique id: 1026
Duplicate unique id: 1024
Duplicate unique id: 1009
Duplicate unique id: 1010
Duplicate unique id: 1004
Duplicate unique id: 1027
Duplicate unique id: 1028
Duplicate unique id: 1029
Duplicate unique id: 1030
Duplicate unique id: 1066
Duplicate unique id: 1006
Duplicate unique id: 1005
Duplicate unique id: 50111
Duplicate unique id: 50112
Duplicate unique id: 50113
Duplicate unique id: 1007
Duplicate unique id: 1008
Duplicate unique id: 1036
Duplicate unique id: 1032
Duplicate unique id: 1031
Duplicate unique id: 1084
Duplicate unique id: 1085
Duplicate unique id: 1086
Duplicate unique id: 1067
Duplicate unique id: 1068
Duplicate unique id: 1070
Duplicate unique id: 1069
Duplicate unique id: 1071
> Map loading time: 8.495 seconds.
> Map size: 33945x33071.

And crashed

Does the load occurs from left to right, from top to down initiating on the given pos?
Or the load occurs only on the specif tile given?

Edit: created a tile in all floors in x=0 and y=0
Code:
function onTime(interval)
    broadcastMessage("Reloading map", MESSAGE_STATUS_WARNING)
    Game.loadMapChunk("data/world/forgottenworld1098oldglobal.otbm", Position(33059, 31334, 4)) -- load the chunk
    addEvent(Game.loadMapChunk, 10000, "data/world/forgottenworld1098oldglobal.otbm", Position(33059, 31334, 4)--[[, true]]) -- remove it after 10 sec
    return true
end
Code:
God has logged in.
> Broadcasted message: "Reloading map".
> Map size: 33945x33071.
ERROR: Attempt to set tile on invalid coordinate ( 33059 / 31334 / 016 )!
...
 
Last edited:
Can I simply make a big giant line of tiles from my map to the position (0,0,0)? Or add 1 tile at (0,0,0)?
By the way, awesome!

Edit: added 1 tile at (0,0,0):

Code:
<globalevent name="ReloadMap" time="21:04:00" script="reloadmap.lua"/>

Code:
function onTime(interval)
    broadcastMessage("Reloading map", MESSAGE_STATUS_WARNING)
    Game.loadMapChunk("data/world/forgottenworld1098oldglobal.otbm", Position(1000, 1000, 0)) -- load the chunk
    addEvent(Game.loadMapChunk, 10000, "data/world/forgottenworld1098oldglobal.otbm", Position(1000, 1000, 0), true) -- remove it after 10 sec
    return true
end

Code:
God has logged in.
> Broadcasted message: "Reloading map".
> Map size: 33945x33071.
Duplicate unique id: 50001
Duplicate unique id: 50007
Duplicate unique id: 50003
Duplicate unique id: 50009
Duplicate unique id: 50010
Duplicate unique id: 50014
Duplicate unique id: 50015
Duplicate unique id: 50013
Duplicate unique id: 50004
Duplicate unique id: 50005
Duplicate unique id: 50002
Duplicate unique id: 50008
Duplicate unique id: 50011
Duplicate unique id: 50016
Duplicate unique id: 50012
Duplicate unique id: 50006
Duplicate unique id: 1062
Duplicate unique id: 1063
Duplicate unique id: 1064
Duplicate unique id: 1061
Duplicate unique id: 1060
Duplicate unique id: 1033
Duplicate unique id: 1034
Duplicate unique id: 1035
Duplicate unique id: 1082
Duplicate unique id: 1096
Duplicate unique id: 1097
Duplicate unique id: 50101
Duplicate unique id: 50114
Duplicate unique id: 50115
Duplicate unique id: 50116
Duplicate unique id: 50117
Duplicate unique id: 50102
Duplicate unique id: 50103
Duplicate unique id: 50104
Duplicate unique id: 50107
Duplicate unique id: 50106
Duplicate unique id: 50105
Duplicate unique id: 1013
Duplicate unique id: 1014
Duplicate unique id: 1011
Duplicate unique id: 1065
Duplicate unique id: 1017
Duplicate unique id: 1015
Duplicate unique id: 1016
Duplicate unique id: 1075
Duplicate unique id: 1076
Duplicate unique id: 1077
Duplicate unique id: 1041
Duplicate unique id: 1040
Duplicate unique id: 1039
Duplicate unique id: 1038
Duplicate unique id: 1037
Duplicate unique id: 1058
Duplicate unique id: 1072
Duplicate unique id: 1012
Duplicate unique id: 1093
Duplicate unique id: 23203
Duplicate unique id: 4038
Duplicate unique id: 4039
Duplicate unique id: 1094
Duplicate unique id: 1095
Duplicate unique id: 23202
Duplicate unique id: 4033
Duplicate unique id: 1090
Duplicate unique id: 4034
Duplicate unique id: 1091
Duplicate unique id: 1092
Duplicate unique id: 23201
Duplicate unique id: 4028
Duplicate unique id: 1087
Duplicate unique id: 1088
Duplicate unique id: 4029
Duplicate unique id: 1089
Duplicate unique id: 1051
Duplicate unique id: 1050
Duplicate unique id: 1049
Duplicate unique id: 1048
Duplicate unique id: 1047
Duplicate unique id: 1046
Duplicate unique id: 50110
Duplicate unique id: 1057
Duplicate unique id: 1056
Duplicate unique id: 1055
Duplicate unique id: 1054
Duplicate unique id: 1053
Duplicate unique id: 1052
Duplicate unique id: 50109
Duplicate unique id: 50108
Duplicate unique id: 1018
Duplicate unique id: 1019
Duplicate unique id: 1020
Duplicate unique id: 1001
Duplicate unique id: 1002
Duplicate unique id: 1003
Duplicate unique id: 1074
Duplicate unique id: 1073
Duplicate unique id: 1045
Duplicate unique id: 1078
Duplicate unique id: 1079
Duplicate unique id: 1080
Duplicate unique id: 1081
Duplicate unique id: 1021
Duplicate unique id: 1022
Duplicate unique id: 1083
Duplicate unique id: 1059
Duplicate unique id: 1023
Duplicate unique id: 1025
Duplicate unique id: 1026
Duplicate unique id: 1024
Duplicate unique id: 1009
Duplicate unique id: 1010
Duplicate unique id: 1004
Duplicate unique id: 1027
Duplicate unique id: 1028
Duplicate unique id: 1029
Duplicate unique id: 1030
Duplicate unique id: 1066
Duplicate unique id: 1006
Duplicate unique id: 1005
Duplicate unique id: 50111
Duplicate unique id: 50112
Duplicate unique id: 50113
Duplicate unique id: 1007
Duplicate unique id: 1008
Duplicate unique id: 1036
Duplicate unique id: 1032
Duplicate unique id: 1031
Duplicate unique id: 1084
Duplicate unique id: 1085
Duplicate unique id: 1086
Duplicate unique id: 1067
Duplicate unique id: 1068
Duplicate unique id: 1070
Duplicate unique id: 1069
Duplicate unique id: 1071
> Map loading time: 8.495 seconds.
> Map size: 33945x33071.

And crashed

Does the load occurs from left to right, from top to down initiating on the given pos?
Or the load occurs only on the specif tile given?

Edit: created a tile in all floors in x=0 and y=0
Code:
function onTime(interval)
    broadcastMessage("Reloading map", MESSAGE_STATUS_WARNING)
    Game.loadMapChunk("data/world/forgottenworld1098oldglobal.otbm", Position(33059, 31334, 4)) -- load the chunk
    addEvent(Game.loadMapChunk, 10000, "data/world/forgottenworld1098oldglobal.otbm", Position(33059, 31334, 4)--[[, true]]) -- remove it after 10 sec
    return true
end
Code:
God has logged in.
> Broadcasted message: "Reloading map".
> Map size: 33945x33071.
ERROR: Attempt to set tile on invalid coordinate ( 33059 / 31334 / 016 )!
...
You have an offset of 4 (Z pos), and I'm assuming you mapped on floor 12 beacuse it adds base floor z + offset z, making it 16th floor (doesn't exist in Tibia)
I'm surprised people are getting crashes somehow cause I tested this for hours (I guess I did only test single-floor maps, but it shouldn't be a problem) but it's not surprising as well cause this code is pretty volatile. Could you send the map you're testing so I can check?
 
You have an offset of 4 (Z pos), and I'm assuming you mapped on floor 12 beacuse it adds base floor z + offset z, making it 16th floor (doesn't exist in Tibia)
I'm surprised people are getting crashes somehow cause I tested this for hours (I guess I did only test single-floor maps, but it shouldn't be a problem) but it's not surprising as well cause this code is pretty volatile. Could you send the map you're testing so I can check?
There is nothing wrong with the code. It's working properly and with more source edits to make it spawn monsters from RME too, this is the best solution for dungeon instances.
 
I was thinking it was some kind of system like /reload monsters /reload weapons
But it is more like a "changeable map event", and that is a great work too! But dont fit my needs :(
 
There is nothing wrong with the code. It's working properly and with more source edits to make it spawn monsters from RME too, this is the best solution for dungeon instances.
You will be able to see/use this exact thing on LoA very soon!
 
You have an offset of 4 (Z pos), and I'm assuming you mapped on floor 12 beacuse it adds base floor z + offset z, making it 16th floor (doesn't exist in Tibia)
I'm surprised people are getting crashes somehow cause I tested this for hours (I guess I did only test single-floor maps, but it shouldn't be a problem) but it's not surprising as well cause this code is pretty volatile. Could you send the map you're testing so I can check?
I already writed what's wrong with your code and you even liked it so why do you pretend like you don't know?
So here we go again if you change the unload code part to this it should remove the crashes:
C++:
if (unload) {
    Tile* tile = map.getTile(Position(x, y, z));
    TileItemVector* items = tile->getItemList();
    if (items) {
        TileItemVector item_list = *items;
        if (!item_list.size() == 0) {
            for (Item* item : item_list) {
                if (item != nullptr) {
                    //tile->queryRemove(*item, item->getItemCount(), 0); // WTF?
                    int32_t index = tile->getThingIndex(item);

                    //remove the item
                    tile->removeThing(item, item->getItemCount());
                    tile->postRemoveNotification(item, nullptr, index);
                    if (item->isRemoved()) {
                        item->onRemoved();
                        item->decrementReferenceCounter();
                    }
                }
            }
        }
    }

    Item* ground = tile->getGround();
    if (ground) {
        //tile->queryRemove(*ground, 1, 0); // WTF?
        int32_t index = tile->getThingIndex(ground);

        //remove the item
        tile->removeThing(ground, 1);
        tile->postRemoveNotification(ground, nullptr, index);
        if (ground->isRemoved()) {
            ground->onRemoved();
            ground->decrementReferenceCounter();
        }
    }
    continue;
}
Again you shouldn't destroy items before calling "postRemoveNotification" because it check if it needs to execute onRemoveItem movement script and when you have destroyed(decrementReferenceCounter) item you shouldn't call this function because it's undefined behavior. Keep in mind even your exception catcher wouldn't help identify this crash because it is hardware exception(like for example value / 0) not the software one.
 
I already writed what's wrong with your code and you even liked it so why do you pretend like you don't know?
So here we go again if you change the unload code part to this it should remove the crashes:
C++:
if (unload) {
    Tile* tile = map.getTile(Position(x, y, z));
    TileItemVector* items = tile->getItemList();
    if (items) {
        TileItemVector item_list = *items;
        if (!item_list.size() == 0) {
            for (Item* item : item_list) {
                if (item != nullptr) {
                    //tile->queryRemove(*item, item->getItemCount(), 0); // WTF?
                    int32_t index = tile->getThingIndex(item);

                    //remove the item
                    tile->removeThing(item, item->getItemCount());
                    tile->postRemoveNotification(item, nullptr, index);
                    if (item->isRemoved()) {
                        item->onRemoved();
                        item->decrementReferenceCounter();
                    }
                }
            }
        }
    }

    Item* ground = tile->getGround();
    if (ground) {
        //tile->queryRemove(*ground, 1, 0); // WTF?
        int32_t index = tile->getThingIndex(ground);

        //remove the item
        tile->removeThing(ground, 1);
        tile->postRemoveNotification(ground, nullptr, index);
        if (ground->isRemoved()) {
            ground->onRemoved();
            ground->decrementReferenceCounter();
        }
    }
    continue;
}
Again you shouldn't destroy items before calling "postRemoveNotification" because it check if it needs to execute onRemoveItem movement script and when you have destroyed(decrementReferenceCounter) item you shouldn't call this function because it's undefined behavior. Keep in mind even your exception catcher wouldn't help identify this crash because it is hardware exception(like for example value / 0) not the software one.
Wasn't intentionally ignoring your post, I didn't get around to fixing it immediately and responded quickly when that person posted their crash then just completely forgot about your post (a lot of the times I just check my notifications quickly, I get a lot being on support team). Most of the code I copied from Game::internalRemoveItem. I have no fucking clue what I was thinking with queryRemove, but in internalRemoveItem postRemoveNotification is called after removeThing gets called as well. Also, the item shouldn't even be destroyed before postRemoveNotification anyways (so the movement scripts shouldn't be an issue), items get deleted when their reference counter is zero, which is why decrement is called after those are called.
 
Updated the main post's code link to its own repository for future updates, recently pushed a commit to use Game::internalRemoveItem instead of manually writing my own potentially buggy removal code for unloading map.
 
Back
Top