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

Solved TFS [1.x] Is there a networkmessage byte code for opening container in game?

whitevo

Feeling good, thats what I do.
Joined
Jan 2, 2015
Messages
3,452
Solutions
1
Reaction score
625
Location
Estonia
Idea was this: If I use apple tree.
Instead of rewarding player with apples or giving him modal window option to take apples or whatever.

I create a bag in game and add the apples in it.
Then I send the opening bag network message to player.

@WibbenZ Once helped me with this network message thing when I was messing around with NPC's
Maybe its possible to do the above too?

If it is possible, then most likely I need byte code for closing the container too.
 
I don't want to be mean, but did you even tried opening the protocolgame file and search for the functions? o.o
No.
Never knew it existed or what its for.
So i looked it now and found this:

Code:
void ProtocolGame::parseSeekInContainer(NetworkMessage& msg)
{
    uint8_t containerId = msg.getByte();
    uint16_t index = msg.get<uint16_t>();
    addGameTask(&Game::playerSeekInContainer, player->getID(), containerId, index);
}
How do I use this?
Going to test this:
Code:
local networkMessage = NetworkMessage()
local bag = Game.CreateItem(1987, 1, pos)
local bagUID = bag:getUniqueId()
            networkMessage:addByte(0xCC)
networkMessage:sendToPlayer(player, bagUID )
 
No.
Never knew it existed or what its for.
So i looked it now and found this:

Code:
void ProtocolGame::parseSeekInContainer(NetworkMessage& msg)
{
    uint8_t containerId = msg.getByte();
    uint16_t index = msg.get<uint16_t>();
    addGameTask(&Game::playerSeekInContainer, player->getID(), containerId, index);
}
How do I use this?
Going to test this:
Code:
local networkMessage = NetworkMessage()
local bag = Game.CreateItem(1987, 1, pos)
local bagUID = bag:getUniqueId()
            networkMessage:addByte(0xCC)
networkMessage:sendToPlayer(player, bagUID )
So how did it work out?
 
Not gonna say no, but most likely there is none.
Mainly seeing as containers are mainly handled from the client, but there might be something hidden :p
But cipsoft seems to be getting good at cleaning (animated texts) and removing things they don't use anymore / haven't used.
 
Alright. I tried to make this work in Lua only but - as far as I know - it is not possible. I will explain everything I tried and why it did not work for future reference, and because you never know who may find the knowledge useful.

The first thing I tried, as Summ pointed out, was to recreate ProtocolGame::sendContainer in Lua:
Code:
local function sendContainer(player, container, hasParent, firstIndex)
    firstIndex = firstIndex or 0

    local msg = NetworkMessage()
    msg:addByte(0x6E)
    msg:addByte(player:getId())

    msg:addItem(container)
    msg:addString(container:getName())

    msg:addByte(container:getCapacity())
    msg:addByte(hasParent and 0x01 or 0x00)
    msg:addByte(0x01) -- Unlocked
    msg:addByte(0x00) -- No pagination

    local containerSize = container:getSize()
    msg:addU16(containerSize)
    msg:addU16(firstIndex)
    if(firstIndex < containerSize) then
        local itemsToSend = math.min(container:getCapacity(), containerSize - firstIndex)

        msg:addByte(itemsToSend)
        for i = firstIndex, itemsToSend - 1 do
            msg:addItem(container:getItem(i))
        end
    else
        msg:addByte(0x00)
    end

    msg:sendToPlayer(player)
    msg:delete()
end

It works, and what I mean by that is, the container is sent to the player. The container is opened normally and even the items are sent, however you can't make use of the items inside, actually you can't make use of the container at all. This is because even though the container is sent, the player didn't actually open it. And since the container is not assigned an id, nothing you try to do with it will work. Then let's add the container and assign it an id, shall we?

luascript.h:
Code:
static int luaPlayerAddContainer(lua_State* L);

luascript.cpp:
Code:
registerMethod("Player", "addContainer", LuaScriptInterface::luaPlayerAddContainer);

int LuaScriptInterface::luaPlayerAddContainer(lua_State* L)
{
    // player:addContainer(container)
    Player* player = getUserdata<Player>(L, 1);
    if (!player) {
        lua_pushnil(L);
        return 1;
    }

    Container* container = getUserdata<Container>(L, 2);
    if (container) {
        if (player->getContainerID(container) != -1)
        {
            lua_pushnil(L);
            return 1;
        }

        uint8_t cid = 20;
        for (int i = 0; i <= 0xF; i++) {
            if (player->getContainerByID(i) == nullptr)
            {
                cid = i;
                break;
            }

        }

        if (cid != 20)
        {
            player->addContainer(cid, container);
            player->onSendContainer(container);
            lua_pushnumber(L, cid);
        }
        else {
            lua_pushnil(L);
        }
     
    }
    else {
        lua_pushnil(L);
    }
    return 1;
}

We can now ignore the Lua function and use only this last one. Now, we can try to do this:
Code:
local bp = Game.createItem(1988, 1)
local container = Container(bp:getUniqueId())
container:addItem(2525)

player:addContainer(container)

Once again, it will apparently work. However the server will crash, because the next time it checks if the player moved away from the container (it should normally close), it will try to do so with an invalid temporary item, that has no position.

The solution is to either: give the player the container item, or place it in a position adjacent to the player, neither of which are suitable for the task at hand.

The best way I found to achieve the effect that the OP wants is to remove the tree when the player uses it (only necessary on the first use) and replace it with a custom container-tree through Game.createContainer.

Code:
--[[
actions.xml:
    <action itemid="2708" script="tree.lua"/>
- 2708 is simply a tree id.
]]

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local RESTORE_TIME = 1000 * 60 -- Restore apples every minute
    local treeContainer = item
    if(not item:isContainer()) then
        -- Remove normal tree
        item:remove()
        -- Replace it with a special container one
        treeContainer = Game.createContainer(item:getId(), 4, fromPosition)
      
        local function addApples()
            -- Empty the container
            local size = treeContainer:getSize()
            for i = 1, size  do
                treeContainer:getItem(0):remove()
            end
            -- And add new apples.
            treeContainer:addItem(2674, math.random(1, 4))  

            addEvent(addApples, RESTORE_TIME)
        end

        addApples(treContainer)
        addEvent(addApples, RESTORE_TIME)
    end

    -- Automatically open the container
    player:addContainer(treeContainer)
    return true
end

Hope it helps,

Non Sequitur
 
Last edited:
@Non Sequitur
woah thx for input. You sure used far more bytes to create container :eek:

However the server will crash, because the next time it checks if the player moved away from the container (it should normally close), it will try to do so with an invalid temporary item, that has no position.
Question about the source edit one. Cant we give static position where the container will be made?
Or the problem is that its not near player in first place?

Anyway either way don't think I will be trying to make this feature work any time soon. I tackle it again when I start modifying client.

PS: Game.createContainer() does not work and the github issue was brushed away like it was not suppose to work anyway (2 months ago.)
 
Question about the source edit one. Cant we give static position where the container will be made?
You can give a static position as long as it is next to the player, otherwise the container will not open.

PS: Game.createContainer() does not work and the github issue was brushed away like it was not suppose to work anyway (2 months ago.)
It works:

 
@whitevo
Game.createContainer is supposed to create items that should not be containers as containers (i.e the tree in my script).
The function will fail if any of the following conditions are met:
Code:
it.id == 0 || it.group == ITEM_GROUP_DEPRECATED || it.stackable || it.useable || it.moveable || it.pickupable || it.isDepot() || it.isSplash() || it.isDoor()

The item you're trying to create is a backpack (1988) that is moveable, hence it won't work. This is how you should do it:

Code:
local backpack = Game.createItem(1988)
local backpackContainer = Container(backpack:getUniqueId())
backpackContainer:addItem(2674, 4)
  
player:addItemEx(backpack)

Best,

Non Sequitur
 
@whitevo
Game.createContainer is supposed to create items that should not be containers as containers (i.e the tree in my script).
The function will fail if any of the following conditions are met:
Code:
it.id == 0 || it.group == ITEM_GROUP_DEPRECATED || it.stackable || it.useable || it.moveable || it.pickupable || it.isDepot() || it.isSplash() || it.isDoor()

The item you're trying to create is a backpack (1988) that is moveable, hence it won't work. This is how you should do it:

Code:
local backpack = Game.createItem(1988)
local backpackContainer = Container(backpack:getUniqueId())
backpackContainer:addItem(2674, 4)

player:addItemEx(backpack)

Best,

Non Sequitur
Oh did not notice the stackable parameter before >.> pfft.
Like forever I tried to use with all kind of examples.
Man this is going to be pretty epic then. Seems apples do grow on trees! :D

EDIT:
The way I make it work:
on server start up it searches for all the apples trees and replaces them with custom container.
globalevent will be the one what adds apples back
 
Last edited:
@whitevo
Game.createContainer is supposed to create items that should not be containers as containers (i.e the tree in my script).
The function will fail if any of the following conditions are met:
Code:
it.id == 0 || it.group == ITEM_GROUP_DEPRECATED || it.stackable || it.useable || it.moveable || it.pickupable || it.isDepot() || it.isSplash() || it.isDoor()

The item you're trying to create is a backpack (1988) that is moveable, hence it won't work. This is how you should do it:

Code:
local backpack = Game.createItem(1988)
local backpackContainer = Container(backpack:getUniqueId())
backpackContainer:addItem(2674, 4)
 
player:addItemEx(backpack)

Best,

Non Sequitur
I have a question ? -> does this work for container like inbox?

local container = player:getInbox()
 
I have a question ? -> does this work for container like inbox?

local container = player:getInbox()

It works, however simply copy-pasting my example won't. I would help you if you weren't so hypocritical by asking a brazilian for help when you display such prejudice against my country:

Do you hate Brasil? then you are a good person :D
 
Firstly, it was a simple question, i would use in future.

It works, however simply copy-pasting my example won't. I would help you if you weren't so hypocritical by asking a brazilian for help when you display such prejudice against my country:

And yea i wrote as some Brazilians have a such bad ethics(very bad), but so I didn't mean every Citizen tho.
 
this is good stuff.
working at 100%
only have 1 problem.
if you click the tree, its remove the tree, create the tree with size, (add the apples), all okey, now the player open the tree (perfect) you can eat the apples etc, but if you click the tree to "close" it, not work because the script send you the container even if you have opened it already.
how i can do something like
if player getContainer xyz, then close?
thanks in advance.
 
Back
Top