void CGameServerPlayer::ProcessInitialHandshake(unsigned int clientId, const PacketData& subPacket) { if(m_sentInitialHandshake) return; const char* characterIdString = reinterpret_cast<const char*>(subPacket.data() + 0x14); uint32 characterId = atoi(characterIdString); CLog::GetInstance().LogDebug(LOG_NAME, "Initial handshake for clientId = %d and characterId = 0x%0.8X", clientId, characterId); if(clientId == 1) { //Put player in instance { auto playerActor = std::make_unique<CPlayerActor>(characterId); playerActor->SetId(PLAYER_ID); playerActor->RawPacketReady.connect([&] (const PacketData& packet) { m_currentComposite.AddPacket(packet); }); playerActor->LocalPacketReady.connect([&] (CActor* actor, const PacketPtr& packet) { QueueToCurrentComposite(actor, packet); }); playerActor->GlobalPacketReady.connect([&] (CActor* actor, const PacketPtr& packet) { QueueToCurrentComposite(actor, packet); }); m_instance.AddActor(std::move(playerActor)); } PrepareInitialPackets(); } else if(clientId == 2) { QueuePacket(PacketData(std::begin(g_client1_login1), std::end(g_client1_login1))); QueuePacket(PacketData(std::begin(g_client1_login2), std::end(g_client1_login2))); } m_sentInitialHandshake = true; }
bool Host::broadcast(ChannelID channel, PacketType type, const PacketData& data) { if (!isServer()) { logError("Only the server is allowed to broadcast"); return false; } uint32 flags = 0; if (type == RELIABLE) flags |= ENET_PACKET_FLAG_RELIABLE; else { if (type == UNSEQUENCED) flags |= ENET_PACKET_FLAG_UNSEQUENCED; flags |= ENET_PACKET_FLAG_NO_ALLOCATE; } ENetPacket* packet = enet_packet_create(data.data(), data.size(), flags); if (!packet) { logError("Failed to create ENet packet"); return false; } enet_host_broadcast((ENetHost*) m_object, channel, packet); return true; }
bool Peer::sendPacket(ChannelID channel, PacketType type, const PacketData& data) { uint32 flags = 0; if (type == RELIABLE) flags |= ENET_PACKET_FLAG_RELIABLE; else { if (type == UNSEQUENCED) flags |= ENET_PACKET_FLAG_UNSEQUENCED; flags |= ENET_PACKET_FLAG_NO_ALLOCATE; } ENetPacket* packet = enet_packet_create(data.data(), data.size(), flags); if (!packet) { logError("Failed to create ENet packet"); return false; } if (enet_peer_send((ENetPeer*) m_peer, channel, packet) < 0) { logError("Failed to send ENet packet to peer %s", m_name.c_str()); return false; } return true; }
PacketData CBasePacket::ToPacketData() const { assert(m_packetSize >= PACKET_HEADER_SIZE); assert(m_sourceId != 0); assert(m_targetId != 0); PacketData result; result.resize(m_packetSize); //Write subpacket header *reinterpret_cast<uint16*>(result.data() + 0x00) = m_packetSize; *reinterpret_cast<uint16*>(result.data() + 0x02) = 3; //Unknown *reinterpret_cast<uint32*>(result.data() + 0x04) = m_sourceId; *reinterpret_cast<uint32*>(result.data() + 0x08) = m_targetId; *reinterpret_cast<uint32*>(result.data() + 0x0C) = 0xFED2E000; //Unknown //Write command header *reinterpret_cast<uint16*>(result.data() + 0x10) = 0x14; //Unknown *reinterpret_cast<uint16*>(result.data() + 0x12) = m_commandId; *reinterpret_cast<uint32*>(result.data() + 0x14) = 0; *reinterpret_cast<uint32*>(result.data() + 0x18) = time(nullptr); *reinterpret_cast<uint32*>(result.data() + 0x1C) = 0; return result; }
SubPacketArray CPacketUtils::SplitPacketSubPacket(const PacketData& packet) { printf("%s", CPacketUtils::DumpPacket(packet).c_str()); SubPacketArray subPackets; if (packet.size() < sizeof(PACKETHEADER)) { CLog::GetInstance().LogError(LOG_NAME, "Packet to split is smaller than PACKETHEADER.\r\n"); return subPackets; } const uint8_t* packetData = packet.data(); PACKETHEADER header = *reinterpret_cast<const PACKETHEADER*>(packetData); assert(packet.size() == header.packetSize); uint32_t currentSize = header.packetSize - sizeof(PACKETHEADER); packetData += sizeof(PACKETHEADER); while (currentSize != 0) { SUBPACKETHEADER subHeader = *reinterpret_cast<const SUBPACKETHEADER*>(packetData); if (subHeader.subPacketSize == 0) { CLog::GetInstance().LogError(LOG_NAME, "Got zero sized subpacket. Stopping packet processing.\r\n"); break; } if (subHeader.subPacketSize > currentSize) { CLog::GetInstance().LogError(LOG_NAME, "Subpacket doesn't fit in packet. Stopping packet processing.\r\n"); break; } auto subPacket = PacketData(packetData, packetData + subHeader.subPacketSize); subPackets.push_back(subPacket); currentSize -= subHeader.subPacketSize; packetData += subHeader.subPacketSize; } return subPackets; }
uint16_t CPacketUtils::GetSubPacketCommand(const PacketData& subPacket) { SUBPACKETHEADER header = *reinterpret_cast<const SUBPACKETHEADER*>(subPacket.data()); return header.subCommandId; }
uint16_t send( const PacketData &packet ) { return send( packet.data(), packet.size() ); }
uint16 CPacketUtils::GetSubPacketCommand(const PacketData& subPacket) { return *reinterpret_cast<const uint16*>(subPacket.data() + 0x12); }
void CGameServerPlayer::ProcessScriptCommand(const PacketData& subPacket) { uint32 clientTime = *reinterpret_cast<const uint32*>(&subPacket[0x18]); uint32 sourceId = *reinterpret_cast<const uint32*>(&subPacket[0x20]); uint32 targetId = *reinterpret_cast<const uint32*>(&subPacket[0x24]); const char* commandName = reinterpret_cast<const char*>(subPacket.data()) + 0x31; CLog::GetInstance().LogDebug(LOG_NAME, "ProcessScriptCommand: %s Source Id = 0x%0.8X, Target Id = 0x%0.8X.", commandName, sourceId, targetId); auto playerActor = m_instance.GetActor<CPlayerActor>(PLAYER_ID); if(playerActor == nullptr) { CLog::GetInstance().LogError(LOG_NAME, "Failed to get player actor."); return; } if(!strcmp(commandName, "commandRequest")) { //commandRequest (emote, changing equipment, ...) playerActor->ProcessCommandRequest(targetId, subPacket); } else if(!strcmp(commandName, "commandContent")) { switch(targetId) { case 0xA0F05E9B: //Quit CLog::GetInstance().LogDebug(LOG_NAME, "Quit."); m_disconnect = true; break; case 0xA0F05E9C: //Teleport CLog::GetInstance().LogDebug(LOG_NAME, "Teleport."); m_disconnect = true; break; } } else if(!strcmp(commandName, "commandForced")) { playerActor->ProcessCommandForced(targetId); } else if(!strcmp(commandName, "commandDefault")) { playerActor->ProcessCommandDefault(targetId); } else if(!strcmp(commandName, "talkDefault")) { switch(targetId) { case 0x47A00007: //Talking to the door inside the room { static const uint8 commandRequestPacket[] = { 0x01, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x00, 0x52, 0xE2, 0xA4, 0xEE, 0x3B, 0x01, 0x00, 0x00, 0xb0, 0x00, 0x03, 0x00, 0x41, 0x29, 0x9b, 0x02, 0x41, 0x29, 0x9b, 0x02, 0x00, 0xe0, 0xd2, 0xfe, 0x14, 0x00, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xe9, 0xe0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x41, 0x29, 0x9b, 0x02, 0x07, 0x00, 0xa0, 0x47, 0x01, 0x74, 0x61, 0x6c, 0x6b, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x9b, 0x29, 0x41, 0x06, 0xa0, 0xf1, 0xaf, 0xcd, 0x02, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x54, 0x61, 0x6c, 0x6b, 0x57, 0x69, 0x74, 0x68, 0x49, 0x6e, 0x6e, 0x5f, 0x45, 0x78, 0x69, 0x74, 0x44, 0x6f, 0x6f, 0x72, 0x00, 0x05, 0x05, 0x05, 0x05, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xe8, 0x4e, 0x40, 0x00, 0x00, 0x00, }; QueuePacket(PacketData(std::begin(commandRequestPacket), std::end(commandRequestPacket))); } break; default: #if 0 //Talking Test (doesn't work) { static const uint8 commandRequestPacket[] = { 0x01, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x00, 0xD2, 0x16, 0x9E, 0xEE, 0x3B, 0x01, 0x00, 0x00, 0xB0, 0x00, 0x03, 0x00, 0x41, 0x29, 0x9B, 0x02, 0x41, 0x29, 0x9B, 0x02, 0x00, 0xE0, 0xD2, 0xFE, 0x14, 0x00, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0xED, 0xE0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x41, 0x29, 0x9B, 0x02, 0x82, 0x00, 0x70, 0x46, 0x01, 0x74, 0x61, 0x6C, 0x6B, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6E, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xA0, 0xF1, 0xAF, 0xCD, 0x06, 0xA0, 0xF1, 0xB4, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0xF1, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xB8, 0x45, 0x40, 0x00, 0x00, 0x00, }; QueuePacket(PacketData(std::begin(commandRequestPacket), std::end(commandRequestPacket))); } #endif m_disconnect = true; break; } } else { //Anything else will probably crash, so just bail m_disconnect = true; } }
void CGameServerPlayer::ProcessChat(const PacketData& subPacket) { const char* chatText = reinterpret_cast<const char*>(subPacket.data() + 0x3C); static std::map<std::string, uint32> weatherCommands; if(weatherCommands.empty()) { weatherCommands["weather_clear"] = CSetWeatherPacket::WEATHER_CLEAR; weatherCommands["weather_fine"] = CSetWeatherPacket::WEATHER_FINE; weatherCommands["weather_cloudy"] = CSetWeatherPacket::WEATHER_CLOUDY; weatherCommands["weather_foggy"] = CSetWeatherPacket::WEATHER_FOGGY; weatherCommands["weather_blustery"] = CSetWeatherPacket::WEATHER_BLUSTERY; weatherCommands["weather_rainy"] = CSetWeatherPacket::WEATHER_RAINY; weatherCommands["weather_stormy"] = CSetWeatherPacket::WEATHER_STORMY; weatherCommands["weather_sandy"] = CSetWeatherPacket::WEATHER_SANDY; weatherCommands["weather_gloomy"] = CSetWeatherPacket::WEATHER_GLOOMY; weatherCommands["weather_dalamud"] = CSetWeatherPacket::WEATHER_DALAMUD; } auto weatherCommandIterator = weatherCommands.find(chatText); if(weatherCommandIterator != std::end(weatherCommands)) { CCompositePacket result; { CSetWeatherPacket packet; packet.SetSourceId(PLAYER_ID); packet.SetTargetId(PLAYER_ID); packet.SetWeatherId(weatherCommandIterator->second); result.AddPacket(packet.ToPacketData()); } QueuePacket(result.ToPacketData()); } else if(!strcmp(chatText, "teleport_mordhona")) { SendTeleportSequence(CSetMapPacket::MAP_MORDHONA, CSetMusicPacket::MUSIC_MORDHONA, INITIAL_POSITION_MOR_DHONA); } else if(!strcmp(chatText, "teleport_coerthas")) { SendTeleportSequence(CSetMapPacket::MAP_COERTHAS, CSetMusicPacket::MUSIC_COERTHAS, INITIAL_POSITION_COERTHAS); } else if(!strcmp(chatText, "teleport_thanalan")) { SendTeleportSequence(CSetMapPacket::MAP_THANALAN, CSetMusicPacket::MUSIC_THANALAN, INITIAL_POSITION_THANALAN); } else if(!strcmp(chatText, "teleport_lanoscea")) { SendTeleportSequence(CSetMapPacket::MAP_NOSCEA, CSetMusicPacket::MUSIC_NOSCEA, INITIAL_POSITION_NOSCEA); } else if(!strcmp(chatText, "teleport_gridania")) { SendTeleportSequence(CSetMapPacket::MAP_BLACKSHROUD, CSetMusicPacket::MUSIC_GRIDANIA, INITIAL_POSITION_GRIDANIA_INN); } else if(!strcmp(chatText, "teleport_rivenroad")) { SendTeleportSequence(CSetMapPacket::MAP_RIVENROAD, CSetMusicPacket::MUSIC_MORDHONA, INITIAL_POSITION_RIVENROAD); } else if(!strcmp(chatText, "teleport_largeboat")) { SendTeleportSequence(CSetMapPacket::MAP_LARGEBOAT, CSetMusicPacket::MUSIC_NOSCEA, INITIAL_POSITION_LARGEBOAT); } else if(!strcmp(chatText, "teleport_smallboat")) { SendTeleportSequence(CSetMapPacket::MAP_SMALLBOAT, CSetMusicPacket::MUSIC_NOSCEA, INITIAL_POSITION_SMALLBOAT); } else if(!strcmp(chatText, "ride_chocobo")) { QueuePacket(PacketData(std::begin(g_chocoboRider1), std::end(g_chocoboRider1))); QueuePacket(PacketData(std::begin(g_chocoboRider2), std::end(g_chocoboRider2))); } // printf("%s\r\n", chatText); }