jo3bingham
Excellent OT User
First of all, if this is the wrong board, feel free to move this thread accordingly.
Since I, and the rest of the OX team, have no plans of returning to the Tibia community, or releasing any of our work, I decided to contribute somewhat to the Open Tibia community by giving you a full breakdown of Tibia's update to 10.76 since TFS is not currently 100%.
Login
-protocollogin.cpp
--ProtocolLogin::onRecvFirstMessage()
The last 128 bytes of this NetworkMessage needs to be RSA decrypted to get the authenticator token, and the stayLoggedInForSession value. This should be done after getting the accountName and password.
--ProtocolLogin::getCharacterList()
This is where I generated an authenticator token and made sure the one read from the NetworkMessage matched it. If no match, send authenticator token failed to the client and close the connection.
If there was a match then you need to tell the client.
This should be done before adding session key, character list, premium, etc.
Now, personally, I don't like that TFS creates the session key out of the account name and password. Like real Tibia, TFS should generate a 30-character, alphanumeric string and use it as the session key. The whole point of the session key is to remove the account name and password from being stored in the client like before. But it's up to you guys as to what you want to do. I generated a random string, but if account name and password is fine with you then so be it.
Game
-protocolgame.cpp
--Parse Methods
0x1F = PerformanceMetrics
0x77 = EquipObject
0x9B = GuildMessage
0x9C = EditGuildMessage
0xF2 = RuleViolationReport
--PerformanceMetrics
I never used this information, but it could be handy to someone.
--EquipObject
data seems to always return 0, from my tests, so I'm not really sure what it's purpose is. This packet is for the new auto-equip CipSoft added to Tibia in the 10.76 update. objectId is the id of the item to equip, however, it is the client id and not the server id. So, for example, gold coin would be objectId of 3031, even though it's server id is 2048 (I believe). Now, it is up to you to write the code in the server to equip/unequip the item in game.cpp. I used a combination of Game::playerMoveItem() and Game::internalMoveItem() + player->sendInventoryItem() depending on whether the container the item was located in was closed or not, or if it was already equipped. Real Tibia works by first checking if the item is already equipped. If so, it places it in the first open slot in your backpack, no matter where that is. If not, it looks through your backpack, finds the first occurrence, then moves it to the corresponding inventory slot. If it's a stackable item (arrows, small stones, etc.) and you have 100 in your inventory slot, or no more in your backpack, it moves it to your backpack, otherwise, it moves them from your backpack until you have 100 in your inventory slot. It took me quite a bit of coding and improvements to get it 100% like real Tibia, so don't beat yourself up if it takes some time.
--GuildMessage
This packet has no extra data. Basically, it just tells the server that the player wants to edit the guild message of the day in the guild channel.
--EditGuildMessage
This packet contains the text that the player has changed the guild message of the day to.
--RuleViolationReport
In enums.h place:
CipSoft uses the same value for multiple reasons making it pretty much useless. For example, when reporting a name, reasons offensive, sexual, and one or two others shared the same reason value. The rest of the information can be useful, though.
--Send Methods
0x9C = Blessings
0x9D = SwitchPreset
0xB7 = UnjustifiedPoints
0xB8 = PvpSituations
0xAE = EditGuildMessage
0xF5 = PlayerObjects
0x9F = BasicData
--Blessings
I never used this packet in our server, or dug in to see what it's purpose was, but it passes a single uint16_t value.
--SwitchPreset
This is solely used in Dawnport in real Tibia when you switch professions (knight, paladin, druid, and sorcerer). It passes a single uint8_t value corresponding to the profession. I believe it's only used in the flash client.
--UnjustifiedPoints
This is for the Unjustified Points window in the client that shows your progress and skull. It passes seven uint8_t values as follows:
Check out the Unjustified Points window in the client to get a better understanding of each value.
--PvpSituations
I never used this packet in our server, or dug in to see what it's purpose was, but it passes a single uint8_t value.
--EditGuildMessage
This is what the server responds with when it receives the GuildMessage packet I mentioned above. It passes a string value containing the player's guild's current message of the day.
--PlayerObjects
This packet is the only way auto-equip will work. It contains the id and total count/charge of every single item the player has on them, inventory and backpack. It has to be sent to the client any time the player's inventory/backpack is changed in any way. If you put something in your backpack, send this packet. If you remove something from your backpack, send this packet. If you use a sudden death rune and it loses a charge, send this packet. You get the idea. The client stores this information, and, when you press an auto-equip hotkey, if it doesn't have that item stored it will not send the EquipObject packet to the server. I wrote my own function in game.cpp to iterate through the player cylinder and return a std::map<uint16_t, uint16_t> where first is item id and second is total count. When I say total count, I mean total count. If your player is carrying 12 stacks of 100 gold coins, and one stack of 35 gold coins, the total count would be 1235. Note that item ids have to be client ids, not server ids. So, like I said earlier, gold coin would be 3031 and not 2048.
--BasicData
Currently, TFS sends a zero-value uint16_t at the end of this packet. However, this is actually the number of spells the player knows followed by the ids of these spells. This is important if you want to get spell/rune hotkeys working in the flash client. And since most servers don't make players purchase/learn spells, and it doesn't matter which known spells are sent to the client, you can change msg.add<uint16_t>(0x00) to:
Since I, and the rest of the OX team, have no plans of returning to the Tibia community, or releasing any of our work, I decided to contribute somewhat to the Open Tibia community by giving you a full breakdown of Tibia's update to 10.76 since TFS is not currently 100%.
Login
-protocollogin.cpp
--ProtocolLogin::onRecvFirstMessage()
The last 128 bytes of this NetworkMessage needs to be RSA decrypted to get the authenticator token, and the stayLoggedInForSession value. This should be done after getting the accountName and password.
Code:
std::string accountName = msg.GetString();
std::string password = msg.GetString();
msg.setPosition(msg.getLength() - 128);
if (!RSA_decrypt(msg)) {
getConnection()->closeConnection();
return;
}
std::string authenticatorToken = msg.GetString();
bool stayLoggedInForSession = msg.GetByte() == 0x01;
This is where I generated an authenticator token and made sure the one read from the NetworkMessage matched it. If no match, send authenticator token failed to the client and close the connection.
Code:
output->AddByte(0x0D);
output->AddByte(0x00); //this has to be sent, and, from my tests, is always 0
OutputMessagePool::getInstance()->send(output);
getConnection()->closeConnection();
return;
Code:
output->AddByte(0x0C);
output->AddByte(0x00); //this has to be sent, and, from my test, is always 0
Now, personally, I don't like that TFS creates the session key out of the account name and password. Like real Tibia, TFS should generate a 30-character, alphanumeric string and use it as the session key. The whole point of the session key is to remove the account name and password from being stored in the client like before. But it's up to you guys as to what you want to do. I generated a random string, but if account name and password is fine with you then so be it.
Game
-protocolgame.cpp
--Parse Methods
0x1F = PerformanceMetrics
0x77 = EquipObject
0x9B = GuildMessage
0x9C = EditGuildMessage
0xF2 = RuleViolationReport
--PerformanceMetrics
I never used this information, but it could be handy to someone.
Code:
uint16_t objectCounterMinimum = msg.get<uint16_t>();
uint16_t objectCounterMaximum = msg.get<uint16_t>();
uint16_t objectCounterAverage = msg.get<uint16_t>();
uint16_t fpsCounterMinimum = msg.get<uint16_t>();
uint16_t fpsCounterMaximum = msg.get<uint16_t>();
uint16_t fpsCounterAverage = msg.get<uint16_t>();
uint16_t fpsLimit = msg.get<uint16_t>();
--EquipObject
Code:
uint16_t objectId = msg.get<uint16_t>();
uint8_t data = msg.get<uint8_t>();
--GuildMessage
This packet has no extra data. Basically, it just tells the server that the player wants to edit the guild message of the day in the guild channel.
--EditGuildMessage
Code:
const std::string text = msg.GetString();
--RuleViolationReport
Code:
uint8_t reportType = msg.GetByte();
uint8_t reason = msg.GetByte();
std::string playerName = msg.GetString();
std::string comment = msg.GetString();
std::string translation = "";
uint32_t statementId = 0;
if (reportType == REPORT_NAME) {
translation = msg.GetString();
} else if (reportType == REPORT_STATEMENT) {
translation = msg.GetString();
statementId = msg.get<uint32_t>();
}
Code:
enum ReportType : uint8_t {
REPORT_NAME = 0,
REPORT_STATEMENT = 1,
REPORT_BOT = 2
};
--Send Methods
0x9C = Blessings
0x9D = SwitchPreset
0xB7 = UnjustifiedPoints
0xB8 = PvpSituations
0xAE = EditGuildMessage
0xF5 = PlayerObjects
0x9F = BasicData
--Blessings
I never used this packet in our server, or dug in to see what it's purpose was, but it passes a single uint16_t value.
--SwitchPreset
This is solely used in Dawnport in real Tibia when you switch professions (knight, paladin, druid, and sorcerer). It passes a single uint8_t value corresponding to the profession. I believe it's only used in the flash client.
--UnjustifiedPoints
This is for the Unjustified Points window in the client that shows your progress and skull. It passes seven uint8_t values as follows:
Code:
progressDay
killsRemainingDay
progressWeek
killsRemainingWeek
progressMonth
killsRemainingMonth
skullDuration
--PvpSituations
I never used this packet in our server, or dug in to see what it's purpose was, but it passes a single uint8_t value.
--EditGuildMessage
This is what the server responds with when it receives the GuildMessage packet I mentioned above. It passes a string value containing the player's guild's current message of the day.
--PlayerObjects
This packet is the only way auto-equip will work. It contains the id and total count/charge of every single item the player has on them, inventory and backpack. It has to be sent to the client any time the player's inventory/backpack is changed in any way. If you put something in your backpack, send this packet. If you remove something from your backpack, send this packet. If you use a sudden death rune and it loses a charge, send this packet. You get the idea. The client stores this information, and, when you press an auto-equip hotkey, if it doesn't have that item stored it will not send the EquipObject packet to the server. I wrote my own function in game.cpp to iterate through the player cylinder and return a std::map<uint16_t, uint16_t> where first is item id and second is total count. When I say total count, I mean total count. If your player is carrying 12 stacks of 100 gold coins, and one stack of 35 gold coins, the total count would be 1235. Note that item ids have to be client ids, not server ids. So, like I said earlier, gold coin would be 3031 and not 2048.
Code:
std::map<uint16_t, uint16_t> items = g_game.getItemsFromCylinder(player);
msg.Add<uint16_t>(items.size() + 11);
//for whatever reason, and I don't know why, real Tibia always sends 11 1-count objects at the beginning.
for (uint16_t i = 1; i <= 11; i++) {
msg.Add<uint16_t>(i);
msg.AddByte(0); //always 0
msg.Add<uint16_t>(1); // always 1
}
for (const auto& it : items) {
msg.Add<uint16_t>(it.first);
msg.AddByte(0); //always 0
msg.Add<uint16_t>(it.second);
}
--BasicData
Currently, TFS sends a zero-value uint16_t at the end of this packet. However, this is actually the number of spells the player knows followed by the ids of these spells. This is important if you want to get spell/rune hotkeys working in the flash client. And since most servers don't make players purchase/learn spells, and it doesn't matter which known spells are sent to the client, you can change msg.add<uint16_t>(0x00) to:
Code:
msg.Add<uint16_t>(0xFF);
for (uint8_t i = 0; i < 0xFF; i++) {
msg.AddByte(i);
}
Last edited: