#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, const std::string& current_room_name) { uint64_t port_id = container_.FindOrAddPort(current_map_name, current_room_name, h_port.name(), std::nullopt, std::nullopt); Port& port = *container_.all_objects().mutable_ports(port_id); port.set_path(h_port.path()); port.set_orientation(h_port.orientation()); // Setting this explicitly because the Godot protobuf doesn't support // custom defaults. port.set_gravity(h_port.gravity()); if (h_port.has_required_door()) { std::optional map_name = h_port.required_door().has_map() ? std::optional(h_port.required_door().map()) : std::nullopt; port.set_required_door(container_.FindOrAddDoor( map_name, h_port.required_door().name(), current_map_name)); } return port_id; } uint64_t ProcessLetter(const HumanLetter& h_letter, const std::string& current_map_name, const std::string& current_room_name) { uint64_t letter_id = container_.FindOrAddLetter(h_letter.key(), h_letter.level2()); Letter& letter = *container_.all_objects().mutable_letters(letter_id); letter.set_room_id(container_.FindOrAddRoom( current_map_name, current_room_name, std::nullopt)); letter.set_path(h_letter.path()); return letter_id; } uint64_t ProcessMastery(const HumanMastery& h_mastery, const std::string& current_map_name, const std::string& current_room_name) { uint64_t mastery_id = container_.FindOrAddMastery( current_map_name, current_room_name, h_mastery.name(), std::nullopt, std::nullopt); Mastery& mastery = *container_.all_objects().mutable_masteries(mastery_id); mastery.set_path(h_mastery.path()); return mastery_id; } uint64_t ProcessKeyholder(const HumanKeyholder& h_keyholder, const std::string& current_map_name, const std::string& current_room_name) { uint64_t keyholder_id = container_.FindOrAddKeyholder( current_map_name, current_room_name, h_keyholder.name(), std::nullopt, std::nullopt); Keyholder& keyholder = *container_.all_objects().mutable_keyholders(keyholder_id); keyholder.set_path(h_keyholder.path()); return keyholder_id; } void ProcessDoorsFile(std::filesystem::path path, const std::string& current_map_name) { if (!std::filesystem::exists(path)) { return; } auto doors = ReadMessageFromFile(path.string()); for (const HumanDoor& door : doors.doors()) { ProcessDoor(door, current_map_name); } } void ProcessDoor(const HumanDoor& h_door, const std::string& current_map_name) { uint64_t door_id = container_.FindOrAddDoor(current_map_name, h_door.name(), std::nullopt); Door& door = *container_.all_objects().mutable_doors(door_id); if (h_door.has_location_room()) { door.set_room_id(container_.FindOrAddRoom( current_map_name, h_door.location_room(), std::nullopt)); Room& room = *container_.all_objects().mutable_rooms(door.room_id()); room.add_doors(door_id); } std::copy( h_door.receivers().begin(), h_door.receivers().end(), google::protobuf::RepeatedFieldBackInserter(door.mutable_receivers())); std::copy( h_door.switches().begin(), h_door.switches().end(), google::protobuf::RepeatedFieldBackInserter(door.mutable_switches())); for (const PaintingIdentifier& pi : h_door.move_paintings()) { std::optional map_name = pi.has_map() ? std::optional(pi.map()) : std::nullopt; door.add_move_paintings(container_.FindOrAddPainting( map_name, pi.room(), pi.name(), current_map_name, std::nullopt)); } for (const PanelIdentifier& pi : h_door.panels()) { ProxyIdentifier* proxy = door.add_panels(); std::optional map_name = pi.has_map() ? std::optional(pi.map()) : std::nullopt; proxy->set_panel(container_.FindOrAddPanel( map_name, pi.room(), pi.name(), current_map_name, std::nullopt)); if (pi.has_answer()) { proxy->set_answer(pi.answer()); } } for (const KeyholderIdentifier& ki : h_door.keyholders()) { KeyholderAnswer* answer = door.add_keyholders(); std::optional map_name = ki.has_map() ? std::optional(ki.map()) : std::nullopt; answer->set_keyholder(container_.FindOrAddKeyholder( map_name, ki.room(), ki.name(), current_map_name, std::nullopt)); if (ki.has_key()) { answer->set_key(ki.key()); } } for (const RoomIdentifier& ri : h_door.rooms()) { std::optional map_name = ri.has_map() ? std::optional(ri.map()) : std::nullopt; door.add_rooms( container_.FindOrAddRoom(map_name, ri.name(), current_map_name)); } for (const DoorIdentifier& di : h_door.doors()) { std::optional map_name = di.has_map() ? std::optional(di.map()) : std::nullopt; door.add_doors( container_.FindOrAddDoor(map_name, di.name(), current_map_name)); } if (h_door.has_control_center_color()) { door.set_control_center_color(h_door.control_center_color()); } if (h_door.has_complete_at()) { door.set_complete_at(h_door.complete_at()); } door.set_type(h_door.type()); } void ProcessConnectionsFile(std::filesystem::path path, std::optional current_map_name) { if (!std::filesystem::exists(path)) { return; } auto connections = ReadMessageFromFile(path.string()); for (const HumanConnection& connection : connections.connections()) { ProcessConnection(connection, current_map_name); } } void ProcessConnection(const HumanConnection& human_connection, const std::optional& current_map_name) { Connection f_connection; if (human_connection.has_from_room()) { f_connection.set_from_room(container_.FindOrAddRoom( std::nullopt, human_connection.from_room(), current_map_name)); } else if (human_connection.has_from()) { ProcessSingleConnection(human_connection.from(), current_map_name, f_connection); } Connection r_connection; r_connection.set_to_room(f_connection.from_room()); if (human_connection.has_to_room()) { r_connection.set_from_room(container_.FindOrAddRoom( std::nullopt, human_connection.to_room(), current_map_name)); } else if (human_connection.has_to()) { ProcessSingleConnection(human_connection.to(), current_map_name, r_connection); } f_connection.set_to_room(r_connection.from_room()); if (human_connection.has_door()) { std::optional map_name = human_connection.door().has_map() ? std::optional(human_connection.door().map()) : std::nullopt; uint64_t door_id = container_.FindOrAddDoor( map_name, human_connection.door().name(), current_map_name); f_connection.set_required_door(door_id); r_connection.set_required_door(door_id); } container_.AddConnection(f_connection); if (!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; }