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

C++ [TFS 1.2]How to create more than 31 item attributes?

Sacarus

Member
Joined
Mar 15, 2016
Messages
52
Reaction score
7
I've been trying to create more item attributes. I had success until the attribute n31 in enums.h. Above 31, it just doesn't keep the information after close the server. Until 31, is totally normal, they all have the same implementation. If I keep server running, it's working, but is useless.
I did some adaptation taking const.h PlayerFlags as base, because enum itemAttrTypes : uint32_t doesnt fit more than 31 elements, as i understood. So i changed to uint64_t and made a cast after elements number 31. It doesnt give me red lines, any error or console warnings.

C++:
//enums.h
enum itemAttrTypes : uint64_t {

    ITEM_ATTRIBUTE_NONE,

    ITEM_ATTRIBUTE_ACTIONID = 1 << 0,
    ITEM_ATTRIBUTE_UNIQUEID = 1 << 1,
//...
    ITEM_ATTRIBUTE_WATER = static_cast<uint64_t>(1) << 31,
    ITEM_ATTRIBUTE_FIRE = static_cast<uint64_t>(1) << 32,
    ITEM_ATTRIBUTE_EARTH = static_cast<uint64_t>(1) << 33
//...

Im just trying to know how to keep values in those new attributes. I did the propStream.read and propStream.write in item.cpp also, and some other stuff that I think it's not necessary to show.


C++:
//item.cpp
 if (hasAttribute(ITEM_ATTRIBUTE_WATER)) {
        propWriteStream.write<uint8_t>(ATTR_WATER);
        propWriteStream.write<uint32_t>(getIntAttr(ITEM_ATTRIBUTE_WATER));
    }
//...

        case ATTR_WATER: {
            int32_t water;
            if (!propStream.read<int32_t>(water)) {
                return ATTR_READ_ERROR;
            }
            setIntAttr(ITEM_ATTRIBUTE_WATER, water);
            break;
        }
//...
 
So.. Bits, huh.
ITEM_ATTRIBUTE_POOP = static_cast<uint64_t>(1) << static_cast<uint64_t>(63)
Done. 63 is the biggest. Remember to change to uint64_t wherever it's related to these attributes.
 
Last edited:
So I have to do a cast after the "<<" (i dont understand shift), is that? Im gonna test
Yup, just make sure both numbers are cast to uint64_t. Made tests and numbers are big ;)
1 << 31 = 2147483648
static_cast<uint64_t>(1) << static_cast<uint64_t>(63) = 9223372036854775808
 
Well, I changed everything related to the attribute and no success. It doesnt keep the value after restart the server. I wanna test more, but i don't know where to change. My new attributes implementation are just like other original attributes, like extraDefense for ex. The others below 31 are working, as i mentioned.
item.cpp:
if (hasAttribute(ITEM_ATTRIBUTE_POOP)) {
propWriteStream.write<uint64_t>(ATTR_POOP);
propWriteStream.write<uint64_t>(getIntAttr(ITEM_ATTRIBUTE_POOP));
}
Tryed that passing uint_8t at the first line, happens the same.. In some way, item doesnt support more than 31 attributes, i just dont know why.
 
Well, I changed everything related to the attribute and no success. It doesnt keep the value after restart the server. I wanna test more, but i don't know where to change. My new attributes implementation are just like other original attributes, like extraDefense for ex. The others below 31 are working, as i mentioned.
item.cpp:
if (hasAttribute(ITEM_ATTRIBUTE_POOP)) {
propWriteStream.write<uint64_t>(ATTR_POOP);
propWriteStream.write<uint64_t>(getIntAttr(ITEM_ATTRIBUTE_POOP));
}
Tryed that passing uint_8t at the first line, happens the same.. In some way, item doesnt support more than 31 attributes, i just dont know why.
Make sure that propWriteStream is able to handle that amount of data and getIntAttr is returning uint64_t.
 
getIntAttr is returning 0 and i can't find any documentation about propWriteStream . Im gonna test some last stuff and if it doesnt work, the most probable, I think I'm gonna give up and try to pass some attributes in just one value, then I split the number.
 
I didn't see this mentioned anywhere in here but feel free to disregard whatever I'm about to write if you have done this privately already. When you're adding new item attributes, you need to alter the hexadecimal value for either isIntAttrType or isStrAttrType (as their names implies, it comes down to whether the type is an integer or string). Have fun! ;)
 
Make sure your database can handle that big data on save / load, that might be the issue
I think the problem is happening before this, as i sayed, getIntAttr is returning 0, before get in sql. But I changed attributes to medium blob in db, just in case, tnx!
I didn't see this mentioned anywhere in here but feel free to disregard whatever I'm about to write if you have done this privately already. When you're adding new item attributes, you need to alter the hexadecimal value for either isIntAttrType or isStrAttrType (as their names implies, it comes down to whether the type is an integer or string). Have fun! ;)
I've seen somebody changing that value in an attribute script here in otland, but i didnt understand why do I need to change it and to which value should I change.
 
I've seen somebody changing that value in an attribute script here in otland, but i didnt understand why do I need to change it and to which value should I change.
Anywhere that your attributes values are being passed by and returned or converted to type different than int64, they immediately lose data, and in this case, a lot of data. That is why you are getting 0 as a return.
 
I've seen somebody changing that value in an attribute script here in otland, but i didnt understand why do I need to change it and to which value should I change.
I see, alright. You need to combine the values of all integer flags (attributes) and vice versa. Find a bitwise calculatoronline that can help you with this specific task (Keep in mind that you're supposed to shift the bits to the left, and not right).
 
Anywhere that your attributes values are being passed by and returned or converted to type different than int64, they immediately lose data, and in this case, a lot of data. That is why you are getting 0 as a return.
hmm
I see, alright. You need to combine the values of all integer flags (attributes) and vice versa. Find a bitwise calculatoronline that can help you with this specific task (Keep in mind that you're supposed to shift the bits to the left, and not right).
Let me see if I understood. I think I dint cause its crashing.
Data type: Decimal
Number: I put 36 that is the number of total attributes that im using
The number of bits to shift: 64

It gives me
Result in binary1001000000000000000000000000000000000000000000000000000000000000000000
Result in decimal664082786653543858176
Result in hexadecimal240000000000000000

I tried overriding 0x7FFE13 to 240000000000000000, but its crashing now, server does not start.
 
I tried overriding 0x7FFE13 to 240000000000000000, but its crashing now, server does not start.
You were supposed to sum the values for all operations (and convert them into a hexadecimal) and not just the highest bit shift (36 in this case).

Let's say you've got 5 attribute flags (3 of them [A, C, E] which are supposed to hold integers, and two of them [B, D] strings).
Code:
ITEM_ATTRIBUTE_A = 1 << 0,
ITEM_ATTRIBUTE_B = 1 << 1,
ITEM_ATTRIBUTE_C = 1 << 2,
ITEM_ATTRIBUTE_D = 1 << 3,
ITEM_ATTRIBUTE_E = 1 << 4,

If you sum A, C, and E, you should be getting the following result: 1 (1 << 0) + 4 (1 << 2) + 16 (1 << 4) = 0x15.
C++:
        static bool isIntAttrType(itemAttrTypes type) {
            return (type & 0x15) != 0;
        }

If you sum B and D: 2 (1 << 1) + 8 (1 << 3) = 0x0A.
C++:
        static bool isStrAttrType(itemAttrTypes type) {
            return (type & 0x0A) != 0;
        }
 
If you want more than 32 attributes(not 31) you should change in item.h
Code:
uint32_t attributeBits = 0;
to:
Code:
uint64_t attributeBits = 0;

In serialization you should have:
Code:
if (hasAttribute(ITEM_ATTRIBUTE_POOP)) {
propWriteStream.write<uint8_t>(ATTR_POOP);
propWriteStream.write<uint64_t>(getIntAttr(ITEM_ATTRIBUTE_POOP));
}
because writing ATTR_POOP as uint64_t will fuck'd up your unserialization process later.

You need to add in item.cpp under function "readAttr":
Code:
case ATTR_POOP: {
            uint64_t poop;
            if (!propStream.read<uint64_t >(poop)) {
                return ATTR_READ_ERROR;
            }

            setIntAttr(ITEM_ATTRIBUTE_POOP, poop);
            break;
}

You can change function "isIntAttrType" to:
Code:
inline static bool isIntAttrType(itemAttrTypes type) {
            uint64_t types = ITEM_ATTRIBUTE_ACTIONID;
            types |= ITEM_ATTRIBUTE_UNIQUEID;
            types |= ITEM_ATTRIBUTE_DATE;
            types |= ITEM_ATTRIBUTE_WEIGHT;
            types |= ITEM_ATTRIBUTE_ATTACK;
            types |= ITEM_ATTRIBUTE_DEFENSE;
            types |= ITEM_ATTRIBUTE_EXTRADEFENSE;
            types |= ITEM_ATTRIBUTE_ARMOR;
            types |= ITEM_ATTRIBUTE_HITCHANCE;
            types |= ITEM_ATTRIBUTE_SHOOTRANGE;
            types |= ITEM_ATTRIBUTE_OWNER;
            types |= ITEM_ATTRIBUTE_DURATION;
            types |= ITEM_ATTRIBUTE_DECAYSTATE;
            types |= ITEM_ATTRIBUTE_CORPSEOWNER;
            types |= ITEM_ATTRIBUTE_CHARGES;
            types |= ITEM_ATTRIBUTE_FLUIDTYPE;
            types |= ITEM_ATTRIBUTE_DOORID;
            //Etc
            return (type & types) != 0;
}
which will allow you to easy specify which attribute is int attributes.
 
Last edited:
@Madzix Ty, I have done it all before, but through many changes, it helped me clear my mind.
About the isIntAttrType function, I tried the hardest way, did what ninja said, it worked! Thank you all, guys!
 
Back
Top