#include #include #include #include #include #include #include #include #include #include #include #include "container.h" #include "proto/data.pb.h" #include "proto/human.pb.h" namespace com::fourisland::lingo2_archipelago { namespace { template T ReadMessageFromFile(const std::string& path) { std::cout << "Processing " << path << std::endl; std::ifstream file(path); std::stringstream buffer; buffer << file.rdbuf(); T message; google::protobuf::TextFormat::ParseFromString(buffer.str(), &message); return message; } class DataPacker { public: DataPacker(const std::string& mapdir, const std::string& outputpath) : mapdir_(mapdir), outputpath_(outputpath) {} void Run() { std::filesystem::path datadir_path = mapdir_; ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt); ProcessMaps(datadir_path); ProcessIdsFile(datadir_path / "ids.txtpb"); { std::ofstream outputfile(outputpath_); container_.all_objects().SerializeToOstream(&outputfile); } /*std::string output; google::protobuf::TextFormat::PrintToString(container_.all_objects(), &output); std::cout << output << std::endl;*/ } private: void ProcessMaps(std::filesystem::path path) { std::filesystem::path maps_dir = path / "maps"; for (auto const& dir_entry : std::filesystem::directory_iterator(maps_dir)) { ProcessMap(dir_entry.path()); } } void ProcessMap(std::filesystem::path path) { std::string map_name = path.filename().string(); ProcessConnectionsFile(path / "connections.txtpb", map_name); ProcessDoorsFile(path / "doors.txtpb", map_name); ProcessRooms(path / "rooms", map_name); } void ProcessRooms(std::filesystem::path path, const std::string& current_map_name) { for (auto const& dir_entry : std::filesystem::directory_iterator(path)) { auto room = ReadMessageFromFile(dir_entry.path().string()); ProcessRoom(room, current_map_name); } } void ProcessRoom(const HumanRoom& h_room, const std::string& current_map_name) { uint64_t room_id = container_.FindOrAddRoom(current_map_name, h_room.name(), std::nullopt); Room& room = *container_.all_objects().mutable_rooms(room_id); room.set_display_name(h_room.display_name()); for (const HumanPanel& h_panel : h_room.panels()) { room.add_panels(ProcessPanel(h_panel, current_map_name, room.name())); } for (const HumanPainting& h_painting : h_room.paintings()) { room.add_paintings( ProcessPainting(h_painting, current_map_name, room.name())); } for (const HumanPort& h_port : h_room.ports()) { room.add_ports(ProcessPort(h_port, current_map_name, room.name())); } for (const HumanLetter& h_letter : h_room.letters()) { room.add_letters(ProcessLetter(h_letter, current_map_name, room.name())); } for (const HumanMastery& h_mastery : h_room.masteries()) { room.add_masteries( ProcessMastery(h_mastery, current_map_name, room.name())); } for (const HumanKeyholder& h_keyholder : h_room.keyholders()) { room.add_keyholders( ProcessKeyholder(h_keyholder, current_map_name, room.name())); } } uint64_t ProcessPanel(const HumanPanel& h_panel, const std::string& current_map_name, const std::string& current_room_name) { uint64_t panel_id = container_.FindOrAddPanel(current_map_name, current_room_name, h_panel.name(), std::nullopt, std::nullopt); PanelData& panel = *container_.all_objects().mutable_panels(panel_id); panel.set_path(h_panel.path()); panel.set_clue(h_panel.clue()); panel.set_answer(h_panel.answer()); std::copy( h_panel.symbols().begin(), h_panel.symbols().end(), google::protobuf::RepeatedFieldBackInserter(panel.mutable_symbols())); std::copy( h_panel.proxies().begin(), h_panel.proxies().end(), google::protobuf::RepeatedFieldBackInserter(panel.mutable_proxies())); if (h_panel.has_required_door()) { std::optional map_name = h_panel.required_door().has_map() ? std::optional(h_panel.required_door().map()) : std::nullopt; panel.set_required_door(container_.FindOrAddDoor( map_name, h_panel.required_door().name(), current_map_name)); } if (h_panel.has_required_room()) { std::optional map_name = h_panel.required_room().has_map() ? std::optional(h_panel.required_room().map()) : std::nullopt; panel.set_required_room(container_.FindOrAddRoom( map_name, h_panel.required_room().name(), current_map_name)); } return panel_id; } uint64_t ProcessPainting(const HumanPainting& h_painting, const std::string& current_map_name, const std::string& current_room_name) { uint64_t painting_id = container_.FindOrAddPainting( current_map_name, current_room_name, h_painting.name(), std::nullopt, std::nullopt); Painting& painting = *container_.all_objects().mutable_paintings(painting_id); painting.set_path(h_painting.path()); painting.set_display_name(h_painting.display_name()); painting.set_orientation(h_painting.orientation()); // Setting this explicitly because the Godot protobuf doesn't support // custom defaults. painting.set_gravity(h_painting.gravity()); if (h_painting.has_move()) { painting.set_move(h_painting.move()); } if (h_painting.has_enter_only()) { painting.set_enter_only(h_painting.enter_only()); } if (h_painting.has_exit_only()) { painting.set_exit_only(h_painting.exit_only()); } if (h_painting.has_required_door()) { std::optional map_name = h_painting.required_door().has_map() ? std::optional(h_painting.required_door().map()) : std::nullopt; painting.set_required_door(container_.FindOrAddDoor( map_name, h_painting.required_door().name(), current_map_name)); } return painting_id; } uint64_t ProcessPort(const HumanPort& h_port, const std::string& current_map_name,
name: "Book Room"
panel_display_name: "Southwest Area"
panels {
  name: "BOOK (1)"
  path: "Panels/Book Room/book_1"
  clue: "book"
  answer: "comic"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (2)"
  path: "Panels/Book Room/book_2"
  clue: "book"
  answer: "check"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (3)"
  path: "Panels/Book Room/book_3"
  clue: "book"
  answer: "cook"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (4)"
  path: "Panels/Book Room/book_4"
  clue: "book"
  answer: "story"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (5)"
  path: "Panels/Book Room/book_5"
  clue: "book"
  answer: "text"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (6)"
  path: "Panels/Book Room/book_6"
  clue: "book"
  answer: "year"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (7)"
  path: "Panels/Book Room/book_7"
  clue: "book"
  answer: "guide"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (8)"
  path: "Panels/Book Room/book_8"
  clue: "book"
  answer: "log"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (9)"
  path: "Panels/Book Room/book_9"
  clue: "book"
  answer: "guest"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (10)"
  path: "Panels/Book Room/book_10"
  clue: "book"
  answer: "scrap"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (11)"
  path: "Panels/Book Room/book_11"
  clue: "book"
  answer: "sketch"
  symbols: EXAMPLE
}
panels {
  name: "BOOK (12)"
  path: "Panels/Book Room/book_12"
  clue: "book"
  answer: "school"
  symbols: EXAMPLE
}
(!human_connection.oneway()) { container_.AddConnection(r_connection); } } void ProcessSingleConnection( const HumanConnection::Endpoint& endpoint, const std::optional& current_map_name, Connection& connection) { if (endpoint.has_room()) { std::optional map_name = endpoint.room().has_map() ? std::optional(endpoint.room().map()) : std::nullopt; connection.set_from_room(container_.FindOrAddRoom( map_name, endpoint.room().name(), current_map_name)); } else if (endpoint.has_painting()) { std::optional map_name = endpoint.painting().has_map() ? std::optional(endpoint.painting().map()) : std::nullopt; std::string room_name; if (!endpoint.painting().has_room()) { std::cout << "Missing room name for painting " << endpoint.painting().name() << std::endl; room_name = "default"; } else { room_name = endpoint.painting().room(); } connection.set_from_room( container_.FindOrAddRoom(map_name, room_name, current_map_name)); connection.set_painting(container_.FindOrAddPainting( map_name, room_name, endpoint.painting().name(), current_map_name, std::nullopt)); } else if (endpoint.has_port()) { std::optional map_name = endpoint.port().has_map() ? std::optional(endpoint.port().map()) : std::nullopt; std::string room_name; if (!endpoint.port().has_room()) { std::cout << "Missing room name for port " << endpoint.port().name() << std::endl; room_name = "default"; } else { room_name = endpoint.port().room(); } connection.set_from_room( container_.FindOrAddRoom(map_name, room_name, current_map_name)); connection.set_port( container_.FindOrAddPort(map_name, room_name, endpoint.port().name(), current_map_name, std::nullopt)); } else if (endpoint.has_panel()) { std::optional map_name = endpoint.panel().has_map() ? std::optional(endpoint.panel().map()) : std::nullopt; std::string room_name; if (!endpoint.panel().has_room()) { std::cout << "Missing room name for panel " << endpoint.panel().name() << std::endl; room_name = "default"; } else { room_name = endpoint.panel().room(); } connection.set_from_room( container_.FindOrAddRoom(map_name, room_name, current_map_name)); connection.mutable_panel()->set_panel(container_.FindOrAddPanel( map_name, room_name, endpoint.panel().name(), current_map_name, std::nullopt)); if (endpoint.panel().has_answer()) { connection.mutable_panel()->set_answer(endpoint.panel().answer()); } } } void ProcessIdsFile(std::filesystem::path path) { auto ids = ReadMessageFromFile(path.string()); for (const auto& [map_name, map] : ids.maps()) { for (const auto& [door_name, ap_id] : map.doors()) { uint64_t door_id = container_.FindOrAddDoor(map_name, door_name, std::nullopt); container_.all_objects().mutable_doors(door_id)->set_ap_id(ap_id); } for (const auto& [room_name, room] : map.rooms()) { for (const auto& [panel_name, ap_id] : room.panels()) { uint64_t panel_id = container_.FindOrAddPanel( map_name, room_name, panel_name, std::nullopt, std::nullopt); container_.all_objects().mutable_panels(panel_id)->set_ap_id(ap_id); } for (const auto& [mastery_name, ap_id] : room.masteries()) { uint64_t mastery_id = container_.FindOrAddMastery( map_name, room_name, mastery_name, std::nullopt, std::nullopt); container_.all_objects() .mutable_masteries(mastery_id) ->set_ap_id(ap_id); } } } auto& specials = *container_.all_objects().mutable_special_ids(); for (const auto& [tag, id] : ids.special()) { specials[tag] = id; } for (const auto& [letter_name, ap_id] : ids.letters()) { uint64_t letter_id = container_.FindLetterByName(letter_name); container_.all_objects().mutable_letters(letter_id)->set_ap_id(ap_id); } } std::string mapdir_; std::string outputpath_; Container container_; }; } // namespace } // namespace com::fourisland::lingo2_archipelago int main(int argc, char** argv) { if (argc != 3) { std::cout << "Incorrect argument count." << std::endl; std::cout << "Usage: datapacker [path to map directory] [output file]" << std::endl; return 1; } std::string mapdir = argv[1]; std::string outputpath = argv[2]; com::fourisland::lingo2_archipelago::DataPacker data_packer(mapdir, outputpath); data_packer.Run(); return 0; }