OrionUO / OrionUO

ABANDONED
MIT License
23 stars 11 forks source link

`Orion.FindType` will return objects when searching "closed" containers. #20

Open Vlek opened 5 years ago

Vlek commented 5 years ago

Information we need from you if you want to have something fixed:

On UOForever.

In order to determine if a container is closed or not I issue a Orion.FindType.

function _openClosedContainer(serial) {
    if (Orion.FindType('0xFFFF', '0xFFFF', serial).length < 1) {
        _tryOpenContainer(serial);
     }
}

function _tryOpenContainer(serial) {
    while(true) {
        if (Orion.FindType('0xFFFF', '0xFFFF', serial).length < 1) {
            Orion.OpenContainer(serial)
            continue;
        }
        return;
    }
}

I expect Orion.FindType to return an empty array or undefined/null results if the container isn't open. However, in some cases Orion.FindType seems to be returning some results. When I then go to move items from the container to another destination, I fail to actually move anything (likely the server thinks I don't have the container open). When I later search for objects of a specific type in the "closed" container, I receive 0 results.

To resolve this I can move many steps away from the container, manually open it, or close my UO client and re-open. It seems randomly triggered (can macro for hours without hitting it or hit it immediately).

Maybe related I've also noticed that Orion will leave open containers after I move > 2 units away from them. If I try to interact with an object in the container I get a "you are too far away" type message. I'd expect the UI to have closed the container once I moved out of range.

The function looks like:

function refresh(refresher, src, src2, dst) {
    var rsrc = Orion.FindObject(src);
    if (!rsrc) {
        Orion.Print('Missing restock source.');
        return;
    }

    var rsrc2 = Orion.FindObject(src2);
    if (!rsrc2) {
        Orion.Print('Missing second restock source.');
        return;
    }

    var rdst = Orion.FindObject(dst);
    if (!rdst) {
        Orion.Print('Missing restock destination.');
        return;
    }

    _openClosedContainer(rsrc.Serial());
    _openClosedContainer(rsrc2.Serial());
    _openClosedContainer(rdst.Serial());

    var countrows = refresher.length;
    Orion.Print(countrows + ' items to refresh');
    for (i=0; i < countrows; i++){
        // Verify if more is needed
        Orion.Print('Refreshing: ' + refresher[i][0] + ' @ ' + refresher[i][1]);
        var bagitem = Orion.Count(refresher[i][0]);
        var needed = refresher[i][1]-bagitem
        if (needed > 0){
            itemfound = Orion.FindType(refresher[i][0], '-1', rsrc.Serial());
            if (itemfound.length == 0) {
                itemfound = Orion.FindType(refresher[i][0], '-1', rsrc2.Serial());
            }
            if (itemfound.length == 0) {
                // BUG REPORT IS RETURNING HERE. It seems the Orion.FindType fails,
                // even though there are items in the bag and checked the bag was open.
                return false;
            }
            var sourceItem = Orion.FindObject(itemfound[0])
            if (sourceItem.Count() < needed) {
                _printSelf("Need to restock " + refresher[i][0] + ".");
                return false
            }
            Orion.Print('Grabbing ' + needed + ' ' + refresher[i][0] + '.');
            _tryMove(sourceItem.Serial(), needed, rdst.Serial());
            Orion.Wait(100);
        }
    }

    return true
}

Not sure how helpful the uolog is here. I truncated 1mb worth of lines where it was looping trying to move the expected items forever. uolog.txt

Vlek commented 5 years ago

I think this is really interesting and important to hash out. I am wondering what the best solution would be under the covers, and I think I have come up with something of a solution, both long term and short term.

For the short term, you could potentially save a JavaScript object of container serials where you put their contents, or at the very lease, a flag or timestamp. If the object does not contain that container, then you know you haven't requested it before. You could also use the timestamp to know if you should refresh the contents based on some predefined value. This does not help with doing waits however, which I think is one of the most important and time consuming parts. a waitForContents(container_serial) function would be great for this sort of thing.

The long term solution is to hash out what we as a community think the value of no contents ought to be, whether that's throwing an error, returning null, or some other value. I think that error handling is a bit much for the community, and, instead I would suggest null if we are not privy to the contents. I am afraid though that, if the contents of containers is kept in memory, that could turn into a memory leak problem. So, not only would we need to figure out a return value, we would also need to discuss how long to keep the contents in memory. The server sends a packet, either the add item to container or add multiple items to container packet, and it contains either an item or a list of items. The client would have to capture this information and store it for as long as it is necessary. Maybe it ought to be a fifo queue that keeps a certain number that has options for the player to change the total saved?