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

Compiling House item sent to depot doesn't work if player is offline

Ray's OT

New Member
Joined
Jun 2, 2016
Messages
13
Reaction score
0
Hello, my name is Ray and this is my first attemt using otland,
I have a weird problem in my ot and was told I could get proper help here :)

I'm using sources you find here: https://github.com/otland/forgottenserver
And I've downgraded it to use client 8.60, and everything have been working fine for me but I found something really strange that I seem cannot solve, I've tried for hours but I just can't find what's causing it.

The problem occur when you own a house and make the command /owner none, the items is supposed to be sent to the depot which the house belongs to.
It works fine if the owner of the house is online, but if he's not, the items just disappear, they don't end up in any depots, there's no new records in the database.

I've tried multiple times to solve it but it seems to be impossible..
So I'd really appreciate if I could get help with this one :)

House.cpp
PHP:
bool House::transferToDepot() const
{
    if (townid == 0 || owner == 0) {
        return false;
    }

    Player* player = g_game.getPlayerByGUID(owner);
    if (player) {
        transferToDepot(player);
    } else {
        Player tmpPlayer(nullptr);
        if (!IOLoginData::loadPlayerById(&tmpPlayer, owner)) {
            return false;
        }

        transferToDepot(&tmpPlayer);
        IOLoginData::savePlayer(&tmpPlayer);
    }
    return true;
}
Notice, the tmpPlayer seems to be valid, because if I put std::cout to debug and write like tmpPlayer.getName() the name of the owner is displayed in the console.
I also tried to make tmpPlayer.addExperience thing, making owner get 10k experience when offline and house is left, and it works, I login the owner and he has 10k more in experience..

House.cpp
PHP:
bool House::transferToDepot(Player* player) const
{
    if (townid == 0 || owner == 0) {
        return false;
    }

    ItemList moveItemList;
    for (HouseTile* tile : houseTiles) {
        if (const TileItemVector* items = tile->getItemList()) {
            for (Item* item : *items) {
                if (item->isPickupable()) {
                    moveItemList.push_back(item);
                } else {
                    Container* container = item->getContainer();
                    if (container) {
                        for (Item* containerItem : container->getItemList()) {
                            moveItemList.push_back(containerItem);
                        }
                    }
                }
            }
        }
    }

    DepotLocker* depotLocker = player->getDepotLocker(townid);
    if (depotLocker) {
        for (Item* item : moveItemList) {
            g_game.internalMoveItem(item->getParent(), depotLocker, INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
        }
    }
    return true;
}

player.cpp
PHP:
DepotLocker* Player::getDepotLocker(uint32_t depotId)
{
    auto it = depotLockerMap.find(depotId);
    if (it != depotLockerMap.end()) {
        return it->second;
    }

    DepotLocker* depotLocker = new DepotLocker(ITEM_LOCKER);
    depotLocker->setDepotId(depotId);
    depotLocker->internalAddThing(getDepotChest(depotId, true));
    depotLockerMap[depotId] = depotLocker;
    return depotLocker;
}

game.cpp
PHP:
ReturnValue Game::internalMoveItem(Cylinder* fromCylinder, Cylinder* toCylinder, int32_t index,
                                   Item* item, uint32_t count, Item** _moveItem, uint32_t flags /*= 0*/, Creature* actor/* = nullptr*/, Item* tradeItem/* = nullptr*/)
{
    Item* toItem = nullptr;

    Cylinder* subCylinder;
    int floorN = 0;

    while ((subCylinder = toCylinder->queryDestination(index, *item, &toItem, flags)) != toCylinder) {
        toCylinder = subCylinder;
        flags = 0;

        //to prevent infinite loop
        if (++floorN >= MAP_MAX_LAYERS) {
            break;
        }
    }

    //destination is the same as the source?
    if (item == toItem) {
        return RETURNVALUE_NOERROR;    //silently ignore move
    }

    //check if we can add this item
    ReturnValue ret = toCylinder->queryAdd(index, *item, count, flags, actor);
    if (ret == RETURNVALUE_NEEDEXCHANGE) {
        //check if we can add it to source cylinder
        ret = fromCylinder->queryAdd(fromCylinder->getThingIndex(item), *toItem, toItem->getItemCount(), 0);
        if (ret == RETURNVALUE_NOERROR) {
            //check how much we can move
            uint32_t maxExchangeQueryCount = 0;
            ReturnValue retExchangeMaxCount = fromCylinder->queryMaxCount(INDEX_WHEREEVER, *toItem, toItem->getItemCount(), maxExchangeQueryCount, 0);

            if (retExchangeMaxCount != RETURNVALUE_NOERROR && maxExchangeQueryCount == 0) {
                return retExchangeMaxCount;
            }

            if (toCylinder->queryRemove(*toItem, toItem->getItemCount(), flags) == RETURNVALUE_NOERROR) {
                int32_t oldToItemIndex = toCylinder->getThingIndex(toItem);
                toCylinder->removeThing(toItem, toItem->getItemCount());
                fromCylinder->addThing(toItem);

                if (oldToItemIndex != -1) {
                    toCylinder->postRemoveNotification(toItem, fromCylinder, oldToItemIndex);
                }

                int32_t newToItemIndex = fromCylinder->getThingIndex(toItem);
                if (newToItemIndex != -1) {
                    fromCylinder->postAddNotification(toItem, toCylinder, newToItemIndex);
                }

                ret = toCylinder->queryAdd(index, *item, count, flags);
                toItem = nullptr;
            }
        }
    }

    if (ret != RETURNVALUE_NOERROR) {
        return ret;
    }

    //check how much we can move
    uint32_t maxQueryCount = 0;
    ReturnValue retMaxCount = toCylinder->queryMaxCount(index, *item, count, maxQueryCount, flags);
    if (retMaxCount != RETURNVALUE_NOERROR && maxQueryCount == 0) {
        return retMaxCount;
    }

    uint32_t m;
    if (item->isStackable()) {
        if (item->isRune()) {
            m = std::min<uint32_t>(item->getItemCount(), maxQueryCount);
        } else {
            m = std::min<uint32_t>(count, maxQueryCount);
        }
    } else {
        m = maxQueryCount;
    }

    Item* moveItem = item;

    //check if we can remove this item
    ret = fromCylinder->queryRemove(*item, m, flags);
    if (ret != RETURNVALUE_NOERROR) {
        return ret;
    }

    if (tradeItem) {
        if (toCylinder->getItem() == tradeItem) {
            return RETURNVALUE_NOTENOUGHROOM;
        }

        Cylinder* tmpCylinder = toCylinder->getParent();
        while (tmpCylinder) {
            if (tmpCylinder->getItem() == tradeItem) {
                return RETURNVALUE_NOTENOUGHROOM;
            }

            tmpCylinder = tmpCylinder->getParent();
        }
    }

    //remove the item
    int32_t itemIndex = fromCylinder->getThingIndex(item);
    Item* updateItem = nullptr;
    fromCylinder->removeThing(item, m);

    //update item(s)
    if (item->isStackable()) {
        uint32_t n;

        if (!item->isRune() && item->equals(toItem)) {
            n = std::min<uint32_t>(100 - toItem->getItemCount(), m);
            toCylinder->updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
            updateItem = toItem;
        } else {
            n = 0;
        }

        int32_t newCount = m - n;
        if (newCount > 0) {
            moveItem = item->clone();
            moveItem->setItemCount(newCount);
        } else {
            moveItem = nullptr;
        }

        if (item->isRemoved()) {
            ReleaseItem(item);
        }
    }

    //add item
    if (moveItem /*m - n > 0*/) {
        toCylinder->addThing(index, moveItem);
    }

    if (itemIndex != -1) {
        fromCylinder->postRemoveNotification(item, toCylinder, itemIndex);
    }

    if (moveItem) {
        int32_t moveItemIndex = toCylinder->getThingIndex(moveItem);
        if (moveItemIndex != -1) {
            toCylinder->postAddNotification(moveItem, fromCylinder, moveItemIndex);
        }
    }

    if (updateItem) {
        int32_t updateItemIndex = toCylinder->getThingIndex(updateItem);
        if (updateItemIndex != -1) {
            toCylinder->postAddNotification(updateItem, fromCylinder, updateItemIndex);
        }
    }

    if (_moveItem) {
        if (moveItem) {
            *_moveItem = moveItem;
        } else {
            *_moveItem = item;
        }
    }

    //we could not move all, inform the player
    if (item->isStackable() && maxQueryCount < count) {
        return retMaxCount;
    }

    return ret;
}

If you need more functions from the sources tell me and I'll add them in here, but hopefully you guys can see something in these codes that I couldn't.

The server is going to be a custom server using 8.60 custom edited client but that shouldn't matter much I think
 
Code:
if (depotLocker) {
 for (Item* item : moveItemList) {g_game.internalMoveItem(item->getParent(), depotLocker, INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
 }
 }

i think the problem would be here, i think depotLocker is wrong.. because internalMoveItem doesn't require player and since player exist everything should go fine, just adding debug lines

Code:
std::cout << "Reached Here Fine" << std::endl
and find out where does it stop..
 
Code:
if (depotLocker) {
for (Item* item : moveItemList) {g_game.internalMoveItem(item->getParent(), depotLocker, INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
}
}

i think the problem would be here, i think depotLocker is wrong.. because internalMoveItem doesn't require player and since player exist everything should go fine, just adding debug lines

Code:
std::cout << "Reached Here Fine" << std::endl
and find out where does it stop..

Thank you for replying, I already tested that, but for the sake of showing I'm willing to get proper help, I did what you told me, and I tested, console says "Reached Here Fine" after the house is cleaned, but nothing in the depot, and no records in database in player_depotitems (I completely cleaned it to make it easier to see changes)
And this is when player is offline, if he's online everything works great :eek:

Edit:
This is driving me crazy.. I can't see anything that could fuck this up.. if the player is offline the game create the player, just like he would be online, except he's not.. and everything about that player can be edited while he's a "dummy".. but yet it's not possible to make him get stuffs to his depot when houses are cleaned <.<

Edit 2:
Just to add, the items in the house disappear when emptied, from the house, if player is online, it's in his depot.. if he's not.. they're not existing anymore..

If I clean a house that doesn't have a proper owner (it has a owner but doesn't exist anymore) and I clean it, items stays in the house..

Edit 3:
I added std::cout << "Reached Here Fine" << std::endl; to game.cpp at internalmoveitem as well.
at bottom, right above:
return ret;

And console showed that text as well when cleaned the house

Edit 4:
I spammed down entire internalmoveitem with loggers, and I tested them online, and offline, they're identical..
TW0QMjo.png
 
Last edited:
added:
Item* item2 = Item::CreateItem(2160, 1);
g_game.internalPlayerAddItem(tmpPlayer, item2, false, CONST_SLOT_WHEREEVER);

after the g_game.internalMoveItem codes..
the char gets 1 cc every time if he's offline.. so char is loaded and saved correctly at least....
 
Back
Top