• 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!

[MAP ISSUE] Downstairs->NoCharacter->CTRL+G = Black Screen.

darkshin

New old member
Joined
Dec 14, 2010
Messages
231
Reaction score
21
Hello Guys!!!!!

I was with this issue at a Global Map sometime ago, but then I started mapping one for my own and suddenly two sets of stairs at the same location but one brings -1 and other +1 both are with this bug. When you move into the stair you lose the control of your character and if you relog u get a black screen.

Anyone can help?
 
I've just made a code compare between my sources and the sources from TFS Git, also I've done a code compare between my OTClient sources and the Up to dates ones. I've compared the modules also, and now the bug changed to this:

"no creature found to move" and "no thing at pos x x x"

So, the functions that are missings these informations from OTClient are:

Code:
ThingPtr ProtocolGame::getMappedThing(const InputMessagePtr& msg)
{
    ThingPtr thing;
    uint16 x = msg->getU16();

    if(x != 0xffff) {
        Position pos;
        pos.x = x;
        pos.y = msg->getU16();
        pos.z = msg->getU8();
        uint8 stackpos = msg->getU8();
        assert(stackpos != 255);
        thing = g_map.getThing(pos, stackpos);
        if(!thing)
            g_logger.traceError(stdext::format("no thing at pos:%s, stackpos:%d", stdext::to_string(pos), stackpos));
    } else {
        uint32 id = msg->getU32();
        thing = g_map.getCreatureById(id);
        if(!thing)
            g_logger.traceError(stdext::format("no creature with id %u", id));
    }

    return thing;
}

void ProtocolGame::parseCreatureMove(const InputMessagePtr& msg)
{
    ThingPtr thing = getMappedThing(msg);
    Position newPos = getPosition(msg);

    if(!thing || !thing->isCreature()) {
        g_logger.traceError("no creature found to move");
        return;
    }

    if(!g_map.removeThing(thing)) {
        g_logger.traceError("unable to remove creature");
        return;
    }

    CreaturePtr creature = thing->static_self_cast<Creature>();
    creature->allowAppearWalk();

    g_map.addThing(thing, newPos, -1);
}

So, @Flatlander. Do you know how I can trace back to the server the message that contains the "thing" itself? I don't really know how to identify the communication between them, I just know that it happens in protocol files.

@Summ, do you know anything about this bug?
 
@Flatlander: Here's one thing I figured out. I've done some tests following your tutorial and some strange stuff happened.

At
static const int32_t maxClientViewportX = 8;
static const int32_t maxClientViewportY = 6;
No bug Happens, but any configuration higher than it, ex:(X= 12 Y=10 or X=14 Y=10 or X=16 Y=14) starts to bug some spots where I change the floor level. The more higher is the configuration, more bugs happens.

Another thing is that even If I don't change the functions MoveDownCreature and MoveUpCreature, The character can move up or down at mostly spots without bugging.

Could it be related to the size of the Byte sent to the client? Because the thing in common that I saw are the numbers size switched in X Y.
Code:
bool ProtocolGame::canSee(int32_t x, int32_t y, int32_t z) const
{
    if (!player) {
        return false;
    }

    const Position& myPos = player->getPosition();
    if (myPos.z <= 7) {
        //we are on ground level or above (7 -> 0)
        //view is from 7 -> 0
        if (z > 7) {
            return false;
        }
    } else if (myPos.z >= 8) {
        //we are underground (8 -> 15)
        //view is +/- 2 from the floor we stand on
        if (std::abs(myPos.getZ() - z) > 2) {
            return false;
        }
    }

    //negative offset means that the action taken place is on a lower floor than ourself
    int32_t offsetz = myPos.getZ() - z;
    if ((x >= myPos.getX() - 12 + offsetz) && (x <= myPos.getX() + 13 + offsetz) &&
           (y >= myPos.getY() - 10 + offsetz) && (y <= myPos.getY() + 11 + offsetz)) { //MORE TILES
        return true;
    }
    return false;
}

Code:
void ProtocolGame::sendMapDescription(const Position& pos)
{
    NetworkMessage msg;
    msg.addByte(0x64);
    msg.addPosition(player->getPosition());
    GetMapDescription(pos.x - 12, pos.y - 10, pos.z, 26, 22, msg); //MORE TILES
    writeToOutputBuffer(msg);
}

Code:
void ProtocolGame::sendMoveCreature(const Creature* creature, const Position& newPos, int32_t newStackPos, const Position& oldPos, int32_t oldStackPos, bool teleport)
{
    if (creature == player) {
        if (oldStackPos >= 10) {
            sendMapDescription(newPos);
        } else if (teleport) {
            NetworkMessage msg;
            RemoveTileThing(msg, oldPos, oldStackPos);
            writeToOutputBuffer(msg);
            sendMapDescription(newPos);
        } else {
            NetworkMessage msg;
            if (oldPos.z == 7 && newPos.z >= 8) {
                RemoveTileThing(msg, oldPos, oldStackPos);
            } else {
                msg.addByte(0x6D);
                msg.addPosition(oldPos);
                msg.addByte(oldStackPos);
                msg.addPosition(newPos);
            }

            if (newPos.z > oldPos.z) {
                MoveDownCreature(msg, creature, newPos, oldPos);
            } else if (newPos.z < oldPos.z) {
                MoveUpCreature(msg, creature, newPos, oldPos);
            }

            if (oldPos.y > newPos.y) { // north, for old x
                msg.addByte(0x65);
                GetMapDescription(oldPos.x - 12, newPos.y - 10, newPos.z, 26, 1, msg); //MORE TILES
            } else if (oldPos.y < newPos.y) { // south, for old x
                msg.addByte(0x67);
                GetMapDescription(oldPos.x - 12, newPos.y + 11, newPos.z, 26, 1, msg);
            }

            if (oldPos.x < newPos.x) { // east, [with new y]
                msg.addByte(0x66);
                GetMapDescription(newPos.x + 13, newPos.y - 10, newPos.z, 1, 22, msg); //MORE TILES
            } else if (oldPos.x > newPos.x) { // west, [with new y]
                msg.addByte(0x68);
                GetMapDescription(newPos.x - 12, newPos.y - 10, newPos.z, 1, 22, msg);
            }
            writeToOutputBuffer(msg);
        }
    } else if (canSee(oldPos) && canSee(creature->getPosition())) {
        if (teleport || (oldPos.z == 7 && newPos.z >= 8) || oldStackPos >= 10) {
            sendRemoveTileThing(oldPos, oldStackPos);
            sendAddCreature(creature, newPos, newStackPos, false);
        } else {
            NetworkMessage msg;
            msg.addByte(0x6D);
            msg.addPosition(oldPos);
            msg.addByte(oldStackPos);
            msg.addPosition(creature->getPosition());
            writeToOutputBuffer(msg);
        }
    } else if (canSee(oldPos)) {
        sendRemoveTileThing(oldPos, oldStackPos);
    } else if (canSee(creature->getPosition())) {
        sendAddCreature(creature, newPos, newStackPos, false);
    }
}
 
Oh, so you increased the screen size? And that is when the bugs started happening?

Yes, but look, even If I change everything in protocolgame.cpp, like your tutorial says, to increased the screen size properly. It will bug some stairs. But If I reduce it back to X = 8 and Y = 6, it stops bugging. So, I've done some tests to see which function was bugging. At first I just changed the 3 Functions above to make the screen works properly at OTClient, and it was enough (I've tested different sizes/rates). The same way some stairs don't bug while screen is larger, some does. Considering that I didn't changed anything at MoveDown/UpCreature Functions. Interesting, ins't?
 
Above it doesn't look like you used maxViewPort like I suggested.

You followed this tutorial I made?
https://otland.net/threads/tutorial-adding-more-tiles-to-game-window.228243/#post-2199001

Ye I did, but then I changed it to numbers to see if the bugg changes its behavior. I've changed it back just now. Ill edit this post with my sources as your tutorial explains when I finish testing other variables.

Edit//
Here is my source code after following your tutorial. Is as this how it should look?

Protocolgame.cpp
Code:
bool ProtocolGame::canSee(int32_t x, int32_t y, int32_t z) const
{
    if (!player) {
        return false;
    }

    const Position& myPos = player->getPosition();
    if (myPos.z <= 7) {
        //we are on ground level or above (7 -> 0)
        //view is from 7 -> 0
        if (z > 7) {
            return false;
        }
    } else if (myPos.z >= 8) {
        //we are underground (8 -> 15)
        //view is +/- 2 from the floor we stand on
        if (std::abs(myPos.getZ() - z) > 2) {
            return false;
        }
    }

    //negative offset means that the action taken place is on a lower floor than ourself
    int32_t offsetz = myPos.getZ() - z;
    if ((x >= myPos.getX() - Map::maxClientViewportX + offsetz) && (x <= myPos.getX() + (Map::maxClientViewportX + 1) + offsetz) &&
        (y >= myPos.getY() - Map::maxClientViewportY + offsetz) && (y <= myPos.getY() + (Map::maxClientViewportY + 1) + offsetz)) { //MORE TILES
        return true;
    }
    return false;
}

void ProtocolGame::sendMapDescription(const Position& pos)
{
    NetworkMessage msg;
    msg.addByte(0x64);
    msg.addPosition(player->getPosition());
    GetMapDescription(pos.x - Map::maxClientViewportX, pos.y - Map::maxClientViewportY, pos.z, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), msg); //MORE TILES
    writeToOutputBuffer(msg);
}

void ProtocolGame::sendMoveCreature(const Creature* creature, const Position& newPos, int32_t newStackPos, const Position& oldPos, int32_t oldStackPos, bool teleport)
{
    if (creature == player) {
        if (oldStackPos >= 10) {
            sendMapDescription(newPos);
        } else if (teleport) {
            NetworkMessage msg;
            RemoveTileThing(msg, oldPos, oldStackPos);
            writeToOutputBuffer(msg);
            sendMapDescription(newPos);
        } else {
            NetworkMessage msg;
            if (oldPos.z == 7 && newPos.z >= 8) {
                RemoveTileThing(msg, oldPos, oldStackPos);
            } else {
                msg.addByte(0x6D);
                msg.addPosition(oldPos);
                msg.addByte(oldStackPos);
                msg.addPosition(newPos);
            }

            if (newPos.z > oldPos.z) {
                MoveDownCreature(msg, creature, newPos, oldPos);
            } else if (newPos.z < oldPos.z) {
                MoveUpCreature(msg, creature, newPos, oldPos);
            }

            if (oldPos.y > newPos.y) { // north, for old x
                msg.addByte(0x65);
                GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, ((Map::maxClientViewportX * 2) + 2), 1, msg); //MORE TILES
            } else if (oldPos.y < newPos.y) { // south, for old x
                msg.addByte(0x67);
                GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y + (Map::maxClientViewportY + 1), newPos.z, ((Map::maxClientViewportX * 2) + 2), 1, msg);
            }

            if (oldPos.x < newPos.x) { // east, [with new y]
                msg.addByte(0x66);
                GetMapDescription(newPos.x + (Map::maxClientViewportX + 1), newPos.y - Map::maxClientViewportY, newPos.z, 1, ((Map::maxClientViewportY * 2) + 2), msg); //MORE TILES
            } else if (oldPos.x > newPos.x) { // west, [with new y]
                msg.addByte(0x68);
                GetMapDescription(newPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, 1, ((Map::maxClientViewportY * 2) + 2), msg);
            }
            writeToOutputBuffer(msg);
        }
    } else if (canSee(oldPos) && canSee(creature->getPosition())) {
        if (teleport || (oldPos.z == 7 && newPos.z >= 8) || oldStackPos >= 10) {
            sendRemoveTileThing(oldPos, oldStackPos);
            sendAddCreature(creature, newPos, newStackPos, false);
        } else {
            NetworkMessage msg;
            msg.addByte(0x6D);
            msg.addPosition(oldPos);
            msg.addByte(oldStackPos);
            msg.addPosition(creature->getPosition());
            writeToOutputBuffer(msg);
        }
    } else if (canSee(oldPos)) {
        sendRemoveTileThing(oldPos, oldStackPos);
    } else if (canSee(creature->getPosition())) {
        sendAddCreature(creature, newPos, newStackPos, false);
    }
}


void ProtocolGame::MoveUpCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos)
{
    if (creature != player) {
        return;
    }

    //floor change up
    msg.addByte(0xBE);

    //going to surface
    if (newPos.z == 7) { //MORE TILES
        int32_t skip = -1;
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 5, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), 3, skip); //(floor 7 and 6 already set)
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 4, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), 4, skip);
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 3, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), 5, skip);
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 2, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), 6, skip);
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 1, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), 7, skip);
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 0, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), 8, skip);

        if (skip >= 0) {
            msg.addByte(skip);
            msg.addByte(0xFF);
        }
    }
    //underground, going one floor up (still underground)
    else if (newPos.z > 7) {//MORE TILES
        int32_t skip = -1;
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, oldPos.getZ() - 3, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), 3, skip);

        if (skip >= 0) {
            msg.addByte(skip);
            msg.addByte(0xFF);
        }
    }

    //moving up a floor up makes us out of sync //TESTE BUG NA ESCADA //MORE TILES
    //west
    msg.addByte(0x68);
    GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - (Map::maxClientViewportY - 1), newPos.z, 1, ((Map::maxClientViewportY * 2) + 2), msg);

    //north
    msg.addByte(0x65);
    GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, ((Map::maxClientViewportX * 2) + 2), 1, msg);
}

void ProtocolGame::MoveDownCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos)
{
    if (creature != player) {
        return;
    }

    //floor change down
    msg.addByte(0xBF);

    //going from surface to underground //MORE TILES
    if (newPos.z == 8) {
        int32_t skip = -1;

        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), -1, skip);
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 1, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), -2, skip);
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), -3, skip);

        if (skip >= 0) {
            msg.addByte(skip);
            msg.addByte(0xFF);
        }
    }
    //going further down //MORE TILES
    else if (newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) {
        int32_t skip = -1;
        GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, ((Map::maxClientViewportX * 2) + 2), ((Map::maxClientViewportY * 2) + 2), -3, skip);

        if (skip >= 0) {
            msg.addByte(skip);
            msg.addByte(0xFF);
        }
    }

    //moving down a floor makes us out of sync //TESTE BUG NA ESCADA //MORE TILES ESSE NAO TA NO TUTORIAL
    //east
    msg.addByte(0x66);
    GetMapDescription(oldPos.x + (Map::maxClientViewportX + 1), oldPos.y - (Map::maxClientViewportY + 1), newPos.z, 1, ((Map::maxClientViewportY * 2) + 2), msg);

    //south
    msg.addByte(0x67);
    GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y + (Map::maxClientViewportY + 1), newPos.z, ((Map::maxClientViewportX * 2) + 2), 1, msg);
}

map.h
Code:
static const int32_t maxViewportX = 20; //min value: maxClientViewportX + 1
        static const int32_t maxViewportY = 14; //min value: maxClientViewportY + 1
        static const int32_t maxClientViewportX = 12;
        static const int32_t maxClientViewportY = 10;

OTC map.cpp
Code:
void Map::resetAwareRange()
{
    AwareRange range;
    range.left = 12; //Change this to = maxClientViewportX
    range.top = 10; //Change this to = maxClientViewportY
    range.bottom = range.top + 1;
    range.right = range.left + 1;
    setAwareRange(range);
}
 
Last edited:
I Double checked your entire protocalgame.cpp and it looks correct.

I would guess it is SOMETHING weird with your map.
Especially since when you log in, it is all black, (makes me think there are bigger things going on, because this should not happen)

When you get messed up, and log out. You said when you log back in it is all black.

Could you check the SQL and see what your character's position is saved as?
 
I Double checked your entire protocalgame.cpp and it looks correct.

I would guess it is SOMETHING weird with your map.
Especially since when you log in, it is all black, (makes me think there are bigger things going on, because this should not happen)

When you get messed up, and log out. You said when you log back in it is all black.

Could you check the SQL and see what your character's position is saved as?

This is the pos when I try to move a floor up with a mountain stair.
My last pos is: 14:38 Your current position is: 703, 1310, 5.
Black Screen Pos (Currently the character don't login anymore, freezes at "Connecting to the game server.."): 705 1310 4

But Flat, thats the problem. I used the Global Map from OTLand and almost every stair was bugged. So I started a map of my own, and now it suddenly bugs some stairs while I send more tiles to the client. If I reduce the tiles to x8 y6, it works normally.

Ah, I've noticed something and I don't really know if it has any influence over this issue but at the following custom function at protocolgame.cpp don't add a byte to send and usually all other functions does:

Code:
void ProtocolGame::AddPlayerAttributes(NetworkMessage& msg) //CUSTOM
{
    //msg.addByte(0xA9); cant make parse work correctly

    for (uint8_t i = ATTRIBUTE_FIRST; i <= ATTRIBUTE_LAST; ++i) {
        msg.add<uint16_t>(std::min<int32_t>(player->getAttValor(i), std::numeric_limits<uint16_t>::max()));
        msg.add<uint16_t>(player->getBaseAtt(i));
    }
}
 
Attributes wouldn't cause this issue.

If you log in and you can see the screen (not black), and use the talkaction /goto 705, 1310, 4 (might be /goto 705 1310 4 without commas). Does it take you to a Valid Tile? What is at that tile? Can you check other positions and see if it has the same kind of tile? (find a pattern).

Honestly maybe I should just grab an otclient, and log into your server and test it myself...
 
Attributes wouldn't cause this issue.

If you log in and you can see the screen (not black), and use the talkaction /goto 705, 1310, 4 (might be /goto 705 1310 4 without commas). Does it take you to a Valid Tile? What is at that tile? Can you check other positions and see if it has the same kind of tile? (find a pattern).

Honestly maybe I should just grab an otclient, and log into your server and test it myself...

Well, the character can't login anymore. So I had to reset his position to temple. I mean, he does login, but the client doesn't show. If I cancel the attempt to login screen, the server responds that the player logged out.

The talk action /goto from my server only reaches creatures, not positions.

If you want to login into my server just tell me when you have time and Ill share my client with you, Flat.

Does it only happen on ramps? or have you noticed this issue on Ropes/Ladders/Holes? How about Stairs?

I happens with ropes, ladders, holes, exani hur up/down, stairs ramps. Whatever makes you change the floor.

<------>

Just to know, why do you want to know if the position is reachable by command?
 
Well, the character can't login anymore. So I had to reset his position to temple. I mean, he does login, but the client doesn't show. If I cancel the attempt to login screen, the server responds that the player logged out.

The talk action /goto from my server only reaches creatures, not positions.

If you want to login into my server just tell me when you have time and Ill share my client with you, Flat.



I happens with ropes, ladders, holes, exani hur up/down, stairs ramps. Whatever makes you change the floor.

<------>

Just to know, why do you want to know if the position is reachable by command?

When going up/down floors, it runs a function called moveUpCreature or moveDownCreature. but when you teleport, it just reloads the entire screen.
I wanted to see if it would bug-out when teleporting, rather than going up/down.
 
When going up/down floors, it runs a function called moveUpCreature or moveDownCreature. but when you teleport, it just reloads the entire screen.
I wanted to see if it would bug-out when teleporting, rather than going up/down.

So Ill place an NPC there and Teleport my self to the NPC located in that pos. Ill edit here with a result.

Edit: IT BUGGED!!
 
Last edited:
So Ill place an NPC there and Teleport my self to the NPC located in that pos. Ill edit here with a result.

Edit: IT BUGGED!!

To me, I feel it is the map.

I've seen other people with the same problem on my thread say it is the map as well.
Have you added new sprites, items, or anything to the server?
 
To me, I feel it is the map.

I've seen other people with the same problem on my thread say it is the map as well.
Have you added new sprites, items, or anything to the server?

I want to add new sprites, items and stuff. But I use .dat and .spr from 10.76.. and there's no data editor for this version :(
But now that you mentioned there's a strange thing that happens in the map editor "remere". Every time I load my map its set as 10.55. So I update it to 10.76 and save it. But when I open it again, it's back to 10.55. Could the error be something at spr file or dat file? Considering that when I load my server the map is set to 10.55 and I run the server at 10.76?
 
Well, just put the 10.76 .spr, .dat, and .otb into the 10.55 folder for your remeres. (lazy way of making sure)

You ALSO need a 10.76 .otb in your items folder for TFS.
I actually had this happen to me yesterday. I went back to one of my older servers, and I had changed certain items in the .spr and .dat, but the older server did not have an updated .otb file in the items folder. So every time I went on the screen with that item, my client would crash or bug out.
 
Back
Top