Untitled
unknown
plain_text
2 years ago
25 kB
7
Indexable
#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;
}
}
Editor is loading...