Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
25 kB
1
Indexable
Never
#include <database/item/item_core.hpp>

#include <constants/config.hpp>

#include <database/item/flags.hpp>
#include <database/item/types.hpp>
#include <database/item/playmods.hpp>

#include <utils/io.hpp>
#include <utils/text.hpp>
#include <utils/binary_reader.hpp>
#include <utils/binary_writer.hpp>

#include <proton/gametankpacket.hpp>
#include <proton/gameupdatepacket.hpp>
#include <proton/tools.hpp>

#include <fstream>
#include <stdexcept>
#include <exception>
#include <algorithm>
#include <filesystem>

#include <stdint.h>

#include <fmt/core.h>

namespace growxyz
{
    item_database::~item_database()
    {
        free(m_data);
    }

    void item_database::interface__kill()
    {
        free(m_data);
        m_items.clear();
    }
    void item_database::interface__init(const std::filesystem::path& path)
    {
        if (std::filesystem::exists(path))
        {
            uint64_t data_size = std::filesystem::file_size(path);
            m_data = new uint8_t[data_size];

            std::ifstream file(path, std::ios::binary);
            if (file.bad())
                return;
            file.read(reinterpret_cast<char*>(m_data), data_size);
            file.close();

            m_hash = tools::hash(m_data, data_size);
            binary_reader br = binary_reader(m_data);
            m_version = br.read_short();
            m_item_count = br.read_int();
            fmt::print("items.dat initailized, version: {}, total items: {}\n", m_version, m_item_count);
            for (uint32_t i = 0; i < m_item_count; i++)
            {
                item item;
                item.m_id = br.read_int();

                item.m_editable_type = br.read_byte();
                item.m_item_category = br.read_byte();
                item.m_action_type = br.read_byte();
                item.m_hit_sound_type = br.read_byte();

                item.m_name = br.read_item_name(item.m_id);
                item.m_texture = br.read_string();

                item.m_texture_hash = br.read_int();
                item.m_item_kind = br.read_byte();
                item.m_val1 = br.read_int();
                item.m_texture_x = br.read_byte();
                item.m_texture_y = br.read_byte();
                item.m_spread_type = br.read_byte();
                item.m_is_stripey_wallpaper = br.read_byte();
                item.m_collision_type = br.read_byte();
                item.m_break_hits = br.read_byte() / 6;
                item.m_reset_time = br.read_int();
                item.m_clothing_type = br.read_byte();
                item.m_rarity = br.read_short();
                item.m_max_amount = br.read_byte();

                item.m_extra_file = br.read_string();

                item.m_extra_file_hash = br.read_int();
                item.m_audio_volume = br.read_int();

                item.m_pet_name = br.read_string();
                item.m_pet_prefix = br.read_string();
                item.m_pet_suffix = br.read_string();
                item.m_pet_ability = br.read_string();

                item.m_seed_base = br.read_byte();
                item.m_seed_overlay = br.read_byte();
                item.m_tree_base = br.read_byte();
                item.m_tree_leaves = br.read_byte();
                item.m_seed_color = br.read_int();
                item.m_seed_overlay_color = br.read_int();
                item.m_ingredient = br.read_int();
                item.m_grow_time = br.read_int();
                item.m_val2 = br.read_short();
                item.m_rayman = br.read_short();

                item.m_extra_options = br.read_string();
                item.m_texture2 = br.read_string();
                item.m_extra_options2 = br.read_string();
                br.skip(80); // reversed bytes
                
                item.m_punch_options = br.read_string();
                item.m_val3 = br.read_int();
                for (auto index = 0; index < 9; index++)
                    item.m_bodypart[index] = br.read_byte();
                item.m_val4 = br.read_int();
                item.m_val5 = br.read_int();

                item.m_punch_id = -1;

                if (i != item.m_id)
                    fmt::print("items are unordered: {}/{}\n", i, item.m_id);

                switch (item.m_action_type)
                {
                case ITEMTYPE_DOOR:
                case ITEMTYPE_LOCK:
                case ITEMTYPE_SIGN:
                case ITEMTYPE_MAIN_DOOR:
                case ITEMTYPE_SEED:
                case ITEMTYPE_PORTAL:
                case ITEMTYPE_MAILBOX:
                case ITEMTYPE_BULLETIN:
                case ITEMTYPE_DICE:
                case ITEMTYPE_PROVIDER:
                case ITEMTYPE_ACHIEVEMENT:
                case ITEMTYPE_SUNGATE:
                case ITEMTYPE_HEART_MONITOR:
                case ITEMTYPE_DONATION_BOX:
                case ITEMTYPE_TOYBOX:
                case ITEMTYPE_MANNEQUIN:
                case ITEMTYPE_SECURITY_CAMERA:
                case ITEMTYPE_MAGIC_EGG:
                case ITEMTYPE_GAME_RESOURCES:
                case ITEMTYPE_GAME_GENERATOR:
                case ITEMTYPE_XENONITE:
                case ITEMTYPE_DRESSUP:
                case ITEMTYPE_CRYSTAL:
                case ITEMTYPE_BURGLAR:
                case ITEMTYPE_SPOTLIGHT:
                case ITEMTYPE_DISPLAY_BLOCK:
                case ITEMTYPE_VENDING_MACHINE:
                case ITEMTYPE_FISHTANK:
                case ITEMTYPE_SOLAR:
                case ITEMTYPE_FORGE:
                case ITEMTYPE_GIVING_TREE:
                case ITEMTYPE_GIVING_TREE_STUMP:
                case ITEMTYPE_STEAM_ORGAN:
                case ITEMTYPE_TAMAGOTCHI:
                case ITEMTYPE_SWING:
                case ITEMTYPE_FLAG:
                case ITEMTYPE_LOBSTER_TRAP:
                case ITEMTYPE_ART_CANVAS:
                case ITEMTYPE_BATTLE_CAGE:
                case ITEMTYPE_PET_TRAINER:
                case ITEMTYPE_STEAM_ENGINE:
                case ITEMTYPE_LOCKBOT:
                case ITEMTYPE_WEATHER_SPECIAL:
                case ITEMTYPE_SPIRIT_STORAGE:
                case ITEMTYPE_DISPLAY_SHELF:
                case ITEMTYPE_VIP_ENTRANCE:
                case ITEMTYPE_CHALLENGE_TIMER:
                case ITEMTYPE_CHALLENGE_FLAG:
                case ITEMTYPE_FISH_MOUNT:
                case ITEMTYPE_PORTRAIT:
                case ITEMTYPE_WEATHER_SPECIAL2:
                case ITEMTYPE_FOSSIL_PREP:
                case ITEMTYPE_DNA_MACHINE:
                case ITEMTYPE_BLASTER:
                case ITEMTYPE_CHEMTANK:
                case ITEMTYPE_STORAGE:
                case ITEMTYPE_OVEN:
                case ITEMTYPE_SUPER_MUSIC:
                case ITEMTYPE_GEIGER_CHARGER:
                case ITEMTYPE_ADVENTURE_RESET:
                case ITEMTYPE_TOMB_ROBBER:
                case ITEMTYPE_FACTION:
                case ITEMTYPE_RED_FACTION:
                case ITEMTYPE_GREEN_FACTION:
                case ITEMTYPE_BLUE_FACTION:
                case ITEMTYPE_FISHGOTCHI_TANK:
                case ITEMTYPE_ITEM_SUCKER:
                case ITEMTYPE_ROBOT:
                case ITEMTYPE_TICKET:
                case ITEMTYPE_STATS_BLOCK:
                case ITEMTYPE_FIELD_NODE:
                case ITEMTYPE_OUIJA_BOARD:
                case ITEMTYPE_AUTO_ACTION_BREAK:
                case ITEMTYPE_AUTO_ACTION_HARVEST:
                case ITEMTYPE_AUTO_ACTION_HARVEST_SUCK:
                case ITEMTYPE_LIGHTNING_IF_ON:
                case ITEMTYPE_PHASED_BLOCK:
                case ITEMTYPE_PASSWORD_STORAGE:
                case ITEMTYPE_PHASED_BLOCK_2:
                case ITEMTYPE_WEATHER_INFINITY:
                case ITEMTYPE_KRANKENS_BLOCK:
                case ITEMTYPE_FRIENDS_ENTRANCE:
                case 30:
                case 133:
                {
                    item.m_has_extra = true;
                    break;
                }
                }
                /*std::string name = item.m_name;
                std::transform(name.begin(), name.end(), name.begin(), ::toupper);
                utils::text::replace(name, " ", "_");
                fmt::print("{} = {},\n", name, item.m_id);*/
                m_items.push_back(std::move(item));
            }

            m_packet = static_cast<gametextpacket_t*>(malloc(sizeof(gametextpacket_t) + sizeof(gameupdatepacket_t) + data_size));
            gameupdatepacket_t* update_packet = static_cast<gameupdatepacket_t*>(malloc(sizeof(gameupdatepacket_t) + data_size));
            if (m_packet && update_packet) {
                memset(update_packet, 0, sizeof(gameupdatepacket_t) + data_size);
                memset(m_packet, 0, sizeof(gametextpacket_t) + sizeof(gameupdatepacket_t) + data_size);
                m_packet->m_type = NET_MESSAGE_GAME_PACKET;

                update_packet->m_type = (uint8_t)PACKET_SEND_ITEM_DATABASE_DATA;
                update_packet->m_net_id = -1;
                update_packet->m_flags |= PACKET_FLAGS_EXTENDED;
                update_packet->m_data_size = (uint32_t)data_size;
                memcpy(&update_packet->m_data, m_data, data_size);
                memcpy(&m_packet->m_data, update_packet, sizeof(gameupdatepacket_t) + data_size);
                m_packet_size = sizeof(gametextpacket_t) + sizeof(gameupdatepacket_t) + (uint32_t)data_size;

                free(update_packet);
            }
        }
        else
            fmt::print("items.dat doesn't exists\n");
    }
    void item_database::interface__encode(const std::filesystem::path& path)
    {
        uint32_t pos = 0;
        size_t size = m_items.size() * sizeof(item) * 10;
        uint8_t* data = static_cast<uint8_t*>(malloc(size));

        if (!data)
        {
            fmt::print("failed to allocate enough data for encoding items.dat\n");
            return;
        }

        auto write_string = [&](const std::string& str)
        {
            uint16_t strsize = static_cast<uint16_t>(str.size());
            memcpy(data + pos, &strsize, 2);
            pos += 2;
            for (int i = 0; i < strsize; ++i)
                data[pos++] = static_cast<uint8_t>(str[i]);
        };

        auto write_string_encrypted = [&](int id, const std::string& str)
        {
            uint16_t strsize = static_cast<uint16_t>(str.size());
            memcpy(data + pos, &strsize, 2);
            pos += 2;

            std::string encrypted = tools::cypher(str, id);

            for (int i = 0; i < strsize; ++i)
                data[pos++] = static_cast<uint8_t>(encrypted[i]);
        };

        memset(data, 0, size);
        memcpy(data + pos, &m_version, 2);
        memcpy(data + pos + 2, &m_item_count, 4);
        pos += 6;


        for (const item& item : m_items)
        {
            uint32_t id = item.m_id;

            memcpy(data + pos, &id, 4);
            pos += 4;
            memcpy(data + pos, &item.m_editable_type, 1);
            pos += 1;
            memcpy(data + pos, &item.m_item_category, 1);
            pos += 1;
            memcpy(data + pos, &item.m_action_type, 1);
            pos += 1;
            memcpy(data + pos, &item.m_hit_sound_type, 1);
            pos += 1;

            write_string_encrypted(item.m_id, item.m_name);
            write_string(item.m_texture);

            memcpy(data + pos, &item.m_texture_hash, 4);
            pos += 4;
            memcpy(data + pos, &item.m_item_kind, 1);
            pos += 1;
            memcpy(data + pos, &item.m_val1, 4);
            pos += 4;
            memcpy(data + pos, &item.m_texture_x, 1);
            pos += 1;
            memcpy(data + pos, &item.m_texture_y, 1);
            pos += 1;
            memcpy(data + pos, &item.m_spread_type, 1);
            pos += 1;
            memcpy(data + pos, &item.m_is_stripey_wallpaper, 1);
            pos += 1;
            memcpy(data + pos, &item.m_collision_type, 1);
            pos += 1;

            uint8_t breakHits = item.m_break_hits * 6;
            memcpy(data + pos, &breakHits, 1);
            pos += 1;

            memcpy(data + pos, &item.m_reset_time, 4);
            pos += 4;
            memcpy(data + pos, &item.m_clothing_type, 1);
            pos += 1;
            memcpy(data + pos, &item.m_rarity, 2);
            pos += 2;
            memcpy(data + pos, &item.m_max_amount, 1);
            pos += 1;

            write_string(item.m_extra_file);

            memcpy(data + pos, &item.m_extra_file_hash, 4);
            pos += 4;
            memcpy(data + pos, &item.m_audio_volume, 4);
            pos += 4;

            write_string(item.m_pet_name);
            write_string(item.m_pet_prefix);
            write_string(item.m_pet_suffix);
            write_string(item.m_pet_ability);

            memcpy(data + pos, &item.m_seed_base, 1);
            pos += 1;
            memcpy(data + pos, &item.m_seed_overlay, 1);
            pos += 1;
            memcpy(data + pos, &item.m_tree_base, 1);
            pos += 1;
            memcpy(data + pos, &item.m_tree_leaves, 1);
            pos += 1;
            memcpy(data + pos, &item.m_seed_color, 4);
            pos += 4;
            memcpy(data + pos, &item.m_seed_overlay_color, 4);
            pos += 4;
            memcpy(data + pos, &item.m_ingredient, 4);
            pos += 4;
            memcpy(data + pos, &item.m_grow_time, 4);
            pos += 4;
            memcpy(data + pos, &item.m_val2, 2);
            pos += 2;
            memcpy(data + pos, &item.m_rayman, 2);
            pos += 2;

            write_string(item.m_extra_options);
            write_string(item.m_texture2);
            write_string(item.m_extra_options2);

            memcpy(data + pos, item.m_reserved, 80);
            pos += 80;

            if (m_version >= 11)
            {
                write_string(item.m_punch_options);
            }

            if (m_version >= 12)
            {
                memcpy(data + pos, &item.m_val3, 4);
                pos += 4;
                memcpy(data + pos, item.m_bodypart, 9);
                pos += 9;
            }

            if (m_version >= 13)
            {
                memcpy(data + pos, &item.m_val4, 4);
                pos += 4;
            }
            if (m_version >= 15) {
                pos += 25;
                uint16_t l = 0;
                memcpy(data + pos, &l, 2);
                pos += 2 + l;
                
            }
        }
        std::ofstream fs(path, std::ios::binary);
        fs.write(reinterpret_cast<char*>(data), pos);
        fs.close();

        free(data);
    }
    void item_database::interface__punch_data_init(const std::filesystem::path& path)
    {
        if (std::filesystem::exists(path))
        {
            uint64_t data_size = std::filesystem::file_size(path);
            uint8_t* m_punch_data = (uint8_t*)malloc(data_size);

            std::ifstream file(path, std::ios::binary);
            if (file.bad())
                return;
            file.read(reinterpret_cast<char*>(m_punch_data), data_size);
            file.close();

            binary_reader br = binary_reader(m_punch_data);
            uint8_t punch_data_version = br.read_byte();
            uint32_t punch_data_count = br.read_uint();

            for (auto index = 0; index < punch_data_count; index++) {
                uint32_t item_id = br.read_uint();
                uint16_t punch_id = br.read_short();
                m_items[item_id].m_punch_id = punch_id;
            }
            fmt::print("punch_data.dat initailized, version: {}, total effects: {}\n", punch_data_version, punch_data_count);
        }
        else
            fmt::print("punch_data.dat doesn't exists\n");
    }
    void item_database::interface__seed_data_init(const std::filesystem::path& path)
    {
        if (!std::filesystem::exists(path)) {
            fmt::print("seed_data.dat doesn't exists\n");
            return;
        }
        uint64_t data_size = std::filesystem::file_size(path);
        uint8_t* m_seed_data = (uint8_t*)malloc(data_size);

        std::ifstream file(path, std::ios::binary);
        if (file.bad())
            return;
        file.read(reinterpret_cast<char*>(m_seed_data), data_size);
        file.close();

        binary_reader br = binary_reader(m_seed_data);
        uint32_t seed_data_count = br.read_uint();

        for (auto index = 0; index < seed_data_count; index++) {
            uint32_t id_ = br.read_uint(),
                first_item = br.read_uint(),
                second_item = br.read_uint();
            seed_info.insert_or_assign(id_ + 1, splice_data{ first_item, second_item });
        }
        fmt::print("seed_data.dat initailized, total splice recipes: {}\n", seed_data_count);
    }
    void item_database::interface__playmods_init(const std::filesystem::path& path)
    {
        if (std::filesystem::exists(path))
        {
            uint64_t data_size = std::filesystem::file_size(path);
            uint8_t* m_playmods_data = (uint8_t*)malloc(data_size);

            std::ifstream file(path, std::ios::binary);
            if (file.bad())
                return;
            file.read(reinterpret_cast<char*>(m_playmods_data), data_size);
            file.close();

            binary_reader br = binary_reader(m_playmods_data);
            if (br.read_string() != "GrowXYZ")
                return;
            int playmods_count = br.read_int();
            for (auto index = 0; index < playmods_count; index++) {
                uint32_t item_id = br.read_uint();
                for (auto index = 0; index < 30; index++)
                    m_items[item_id].m_mods_cloth1[index] = br.read_int();
                for (auto index = 0; index < 30; index++)
                    m_items[item_id].m_mods_cloth2[index] = br.read_int();
                for (auto index = 0; index < 26; index++)
                    m_items[item_id].m_mods_consumable[index] = br.read_int();
            }
            fmt::print("items_playmod.dat initailized, total playmods: {}\n", playmods_count);
        }
        else
            fmt::print("items_playmod.dat doesn't exists\n");
    }
    void item_database::interface__description_init(const std::filesystem::path& path)
    {
        if (!std::filesystem::exists(path)) {
            fmt::print("items_description.dat doesn't exists\n");
            return;
        }
        uint64_t data_size = std::filesystem::file_size(path);
        uint8_t* m_description_data = (uint8_t*)malloc(data_size);

        std::ifstream file(path, std::ios::binary);
        if (file.bad())
            return;
        file.read(reinterpret_cast<char*>(m_description_data), data_size);
        file.close();

        binary_reader br = binary_reader(m_description_data);
        if (br.read_string() != "GrowXYZ")
            return;
        int descriptions_count = br.read_int();

        for (auto index = 0; index < descriptions_count; index++) {
            uint32_t item_id = br.read_uint();
            m_items[item_id].m_description = br.read_string();
        }
        fmt::print("items_description.dat initailized, total descriptions: {}\n", descriptions_count);
    }
    void item_database::interface__pet_abilities_init(const std::filesystem::path& path) {
        if (!std::filesystem::exists(path)) {
            fmt::print("items_description.dat doesn't exists\n");
            return;
        }
        uint64_t data_size = std::filesystem::file_size(path);
        uint8_t* m_description_data = (uint8_t*)malloc(data_size);

        std::ifstream file(path, std::ios::binary);
        if (file.bad())
            return;
        file.read(reinterpret_cast<char*>(m_description_data), data_size);
        file.close();

        binary_reader br = binary_reader(m_description_data);
        if (br.read_string() != "GrowXYZ")
            return;
        int pet_abilities = br.read_int();
        for (auto index = 0; index < pet_abilities; index++) {
            uint32_t item_id = br.read_uint();
            item::pet_ability pet;
            pet.m_element = br.read_byte();
            pet.m_ability = br.read_string();
            pet.m_cooldown_effect = br.read_string();
            pet.m_cooldown = std::chrono::seconds(br.read_long_long());
            pet.m_suffix = br.read_string();
            m_items[item_id].m_pet_battle = pet;
            m_items[item_id].m_has_battle_data = true;
        }
        fmt::print("pet_abilities.dat initailized, total abilities: {}\n", pet_abilities);
    }

    const item& item_database::interface__get_item(uint32_t id) const
    {
        if (id > m_items.size() || id < 0)
            return m_items.at(0);

        return m_items.at(id);
    }
    const item& item_database::interface__get_item(item_component id) const
    {
        if ((uint32_t)id > m_items.size())
            return m_items.at(0);

        return m_items.at((uint32_t)id);
    }
    item& item_database::interface__get_item_unsafe(uint32_t id)
    {
        return m_items.at(id);
    }

    const item& item_database::interface__get_item(const std::string& name) const
    {
        for (auto& item : m_items)
        {
            if (item.m_name == name)
                return item;
        }
        return m_items.at(0);
    }
    std::vector<item> item_database::interface__get_items_matching(const std::string& name) const
    {
        std::vector<item> items;

        std::string lower_name = name;
        std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
            [](unsigned char c) { return std::tolower(c); });

        for (auto& item : m_items)
        {
            std::string lower_case = item.m_name;
            std::transform(lower_case.begin(), lower_case.end(), lower_case.begin(),
                [](unsigned char c) { return std::tolower(c); });
            if (lower_case.find(lower_name) != std::string::npos) {
                if (item.m_id % 2 == 1)
                    continue;
                items.push_back(item);
            }
        }
        return items;
    }

    const std::vector<item>& item_database::interface__get_items()
    {
        return m_items;
    }

    uint32_t item_database::interface__get_hash() const
    {
        return m_hash;
    }
    uint8_t* item_database::interface__get_data()
    {
        return m_data;
    }
    gametextpacket_t* item_database::interface__get_packet()
    {
        return m_packet;
    }
    uint32_t item_database::interface__get_packet_size() const
    {
        return m_packet_size;
    }

    uint32_t item_database::inteface__modify_item(uint32_t id, const item& item)
    {
        growxyz::item it = m_items.at(id);

        if (it.m_name.find("null_item") == std::string::npos && it.m_name != item.m_name)
        {
            m_items.at(id) = item;
            m_items.at(id).m_id = id;

            it.m_id = m_items.size();
            m_items.push_back(it);

            m_item_count += 1;
        }
        else
        {
            m_items.at(id) = item;
            m_items.at(id).m_id = id;
        }

        if (!it.m_texture.empty())
        {
            uintmax_t filesize = 0;
            std::string file = fmt::format("data/cache/{}", m_items.at(id).m_texture);

            void* data = NULL;

            if (std::filesystem::exists(file))
                data = utils::io::read_all_bytes(file, filesize);

            if (!data) {}
            else
            {
                m_items.at(id).m_texture_hash = tools::hash(data, filesize);
                free(data);
            }
        }
        if (!it.m_extra_file.empty())
        {
            uintmax_t filesize = 0;
            std::string file = fmt::format("data/cache/{}", m_items.at(id).m_extra_file);

            void* data = NULL;

            if (std::filesystem::exists(file))
                data = utils::io::read_all_bytes(file, filesize);

            if (!data) {}
            else
            {
                m_items.at(id).m_extra_file_hash = tools::hash(data, filesize);
                free(data);
            }
        }
        return id;
    }

    bool item_is_world_lock(const item& item_)
    {
        return item_.m_id != (uint32_t)item_component::SMALL_LOCK &&
            item_.m_id != (uint32_t)item_component::BIG_LOCK &&
            item_.m_id != (uint32_t)item_component::HUGE_LOCK &&
            item_.m_id != (uint32_t)item_component::BUILDER_LOCK;
    }
    bool item_is_background(const item& item_)
    {
        return item_.m_action_type == ITEMTYPE_BACKGROUND ||
            item_.m_action_type == ITEMTYPE_BACK_BOOMBOX ||
            item_.m_action_type == ITEMTYPE_MUSIC_NOTE;
    }
}