#include "validator.h" #include #include "proto/human.pb.h" #include "structs.h" #include "util/identifiers.h" namespace com::fourisland::lingo2_archipelago { namespace { class Validator { public: explicit Validator(const CollectedInfo& info) : info_(info) {} void Validate() const { for (const auto& [map_name, map_info] : info_.maps) { ValidateMap(map_name, map_info); } for (const auto& [room_identifier, room_info] : info_.rooms) { ValidateRoom(room_identifier, room_info); } for (const auto& [door_identifier, door_info] : info_.doors) { ValidateDoor(door_identifier, door_info); } for (const auto& [port_identifier, port_info] : info_.ports) { ValidatePort(port_identifier, port_info); } for (const auto& [painting_identifier, painting_info] : info_.paintings) { ValidatePainting(painting_identifier, painting_info); } for (const auto& [panel_identifier, panel_info] : info_.panels) { ValidatePanel(panel_identifier, panel_info); } for (const auto& [keyholder_identifier, keyholder_info] : info_.keyholders) { ValidateKeyholder(keyholder_identifier, keyholder_info); } for (const auto& [letter_identifier, letter_info] : info_.letters) { ValidateLetter(letter_identifier, letter_info); } for (const auto& [ending_name, ending_info] : info_.endings) { ValidateEnding(ending_name, ending_info); } for (const auto& [panel_name, panel_info] : info_.panel_names) { ValidatePanelName(panel_name, panel_info); } } private: void ValidateMap(const std::string& map_name, const MapInfo& map_info) const { for (const auto& [node_path, node_info] : map_info.game_nodes) { if (node_info.uses > 1) { std::cout << "Map " << map_name << " node " << node_path << " is used in multiple places." << std::endl; } else if (node_info.uses == 0) { std::cout << "Map " << map_name << " node " << node_path << " is not used." << std::endl; } if (!node_info.defined) { std::cout << "Map " << map_name << " node " << node_path << " is not defined in the game file." << std::endl; } } } void ValidateRoom(const RoomIdentifier& room_identifier, const RoomInfo& room_info) const { if (room_info.definitions.empty()) { std::cout << "Room " << room_identifier.ShortDebugString() << " has no definition, but was referenced:" << std::endl; for (const DoorIdentifier& door_identifier : room_info.doors_referenced_by) { std::cout << " DOOR " << door_identifier.ShortDebugString() << std::endl; } for (const PanelIdentifier& panel_identifier : room_info.panels_referenced_by) { std::cout << " PANEL " << panel_identifier.ShortDebugString() << std::endl; } for (const HumanConnection& connection : room_info.connections_referenced_by) { std::cout << " CONNECTION " << connection.ShortDebugString() << std::endl; } } else if (room_info.definitions.size() > 1) { std::cout << "Room " << room_identifier.ShortDebugString() << " was defined multiple times." << std::endl; } } bool DoesDoorNeedLocationName(const HumanDoor& h_door, const std::string& map_name) const { if (h_door.type() != DoorType::STANDARD) { return false; } if (h_door.keyholders_size() > 0 || h_door.endings_size() > 0) { return true; } if (h_door.panels_size() > 4) { return true; } std::set map_areas; for (const PanelIdentifier& pi : h_door.panels()) { auto full_pi = GetCompletePanelIdentifierWithoutAnswer(pi, map_name, std::nullopt); if (full_pi) { auto panel_info_it = info_.panels.find(*full_pi); if (panel_info_it != info_.panels.end()) { const PanelInfo& panel_info = panel_info_it->second; map_areas.insert(panel_info.map_area_name); } } } if (map_areas.size() > 1) { return true; } return false; } void ValidateDoor(const DoorIdentifier& door_identifier, const DoorInfo& door_info) const { if (door_info.definitions.empty()) { std::cout << "Door " << door_identifier.ShortDebugString() << " has no definition, but was referenced:" << std::endl; for (const DoorIdentifier& other_door_identifier : door_info.doors_referenced_by) { std::cout << " DOOR " << other_door_identifier.ShortDebugString() << std::endl; } for (const PanelIdentifier& panel_identifier : door_info.panels_referenced_by) { std::cout << " PANEL " << panel_identifier.ShortDebugString() << std::endl; } for (const PaintingIdentifier& painting_identifier : door_info.paintings_referenced_by) { std::cout << " PAINTING " << painting_identifier.ShortDebugString() << std::endl; } for (const PortIdentifier& port_identifier : door_info.ports_referenced_by) { std::cout << " PORT " << port_identifier.ShortDebugString() << std::endl; } for (const HumanConnection& connection : door_info.connections_referenced_by) { std::cout << " CONNECTION " << connection.ShortDebugString() << std::endl; } } else if (door_info.definitions.size() > 1) { std::cout << "Door " << door_identifier.ShortDebugString() << " was defined multiple times." << std::endl; } if (door_info.malformed_identifiers.HasAny()) { std::cout << "Door " << door_identifier.ShortDebugString() << " has malformed identifiers:" << std::endl; for (const PaintingIdentifier& painting_identifier : door_info.malformed_identifiers.paintings) { std::cout << " PAINTING " << painting_identifier.ShortDebugString() << std::endl; } for (const PanelIdentifier& panel_identifier : door_info.malformed_identifiers.panels) { std::cout << " PANEL " << panel_identifier.ShortDebugString() << std::endl; } for (const KeyholderIdentifier& keyholder_identifier : door_info.malformed_identifiers.keyholders) { std::cout << " KEYHOLDER " << keyholder_identifier.ShortDebugString() << std::endl; } } for (const HumanDoor& h_door : door_info.definitions) { if (DoesDoorNeedLocationName(h_door, door_identifier.map()) && !h_door.has_location_name()) { std::cout << "Door " << door_identifier.ShortDebugString() << " needs an explicit location name." << std::endl; } } } void ValidatePort(const PortIdentifier& port_identifier, const PortInfo& port_info) const { if (port_info.definitions.empty()) { std::cout << "Port " << port_identifier.ShortDebugString() << " has no definition, but was referenced:" << std::endl; for (const HumanConnection& connection : port_info.connections_referenced_by) { std::cout << " CONNECTION " << connection.ShortDebugString() << std::endl; } } else if (port_info.definitions.size() > 1) { std::cout << "Port " << port_identifier.ShortDebugString() << " was defined multiple times." << std::endl; } } void ValidatePainting(const PaintingIdentifier& painting_identifier, const PaintingInfo& painting_info) const { if (painting_info.definitions.empty()) { std::cout << "Painting " << painting_identifier.ShortDebugString() << " has no definition, but was referenced:" << std::endl; for (const DoorIdentifier& door_identifier : painting_info.doors_referenced_by) { std::cout << " DOOR " << door_identifier.ShortDebugString() << std::endl; } for (const HumanConnection& connection : painting_info.connections_referenced_by) { std::cout << " CONNECTION " << connection.ShortDebugString() << std::endl; } } else if (painting_info.definitions.size() > 1) { std::cout << "Painting " << painting_identifier.ShortDebugString() << " was defined multiple times." << std::endl; } } void ValidatePanel(const PanelIdentifier& panel_identifier, const PanelInfo& panel_info) const { if (panel_identifier.name().empty()) { std::cout << "Panel " << panel_identifier.ShortDebugString() << " has no name." << std::endl; } if (panel_info.definitions.empty()) { std::cout << "Panel " << panel_identifier.ShortDebugString() << " has no definition, but was referenced:" << std::endl; for (const DoorIdentifier& door_identifier : panel_info.doors_referenced_by) { std::cout << " DOOR " << door_identifier.ShortDebugString() << std::endl; } for (const HumanConnection& connection : panel_info.connections_referenced_by) { std::cout << " CONNECTION " << connection.ShortDebugString() << std::endl; } } else if (panel_info.definitions.size() > 1) { std::cout << "Panel " << panel_identifier.ShortDebugString() << " was defined multiple times." << std::endl; } for (const auto& [answer, proxy_info] : panel_info.proxies) { if (proxy_info.definitions.empty()) { std::cout << "Panel " << panel_identifier.ShortDebugString() << " with answer \"" << answer << "\" has no definition, but was referenced:" << std::endl; for (const DoorIdentifier& door_identifier : proxy_info.doors_referenced_by) { std::cout << " DOOR " << door_identifier.ShortDebugString() << std::endl; } for (const HumanConnection& connection : proxy_info.connections_referenced_by) { std::cout << " CONNECTION " << connection.ShortDebugString() << std::endl; } } else if (proxy_info.definitions.size() > 1) { std::cout << "Panel " << panel_identifier.ShortDebugString() << " with answer \"" << answer << "\" was defined multiple times." << std::endl; } } } void ValidateKeyholder(const KeyholderIdentifier& keyholder_identifier, const KeyholderInfo& keyholder_info) const { if (keyholder_info.definitions.empty()) { std::cout << "Keyholder " << keyholder_identifier.ShortDebugString() << " has no definition, but was referenced:" << std::endl; for (const DoorIdentifier& door_identifier : keyholder_info.doors_referenced_by) { std::cout << " DOOR " << door_identifier.ShortDebugString() << std::endl; } } else if (keyholder_info.definitions.size() > 1) { std::cout << "Keyholder " << keyholder_identifier.ShortDebugString() << " was defined multiple times." << std::endl; } } void ValidateLetter(const LetterIdentifier& letter_identifier, const LetterInfo& letter_info) const { std::string letter_name = std::string(1, std::get<0>(letter_identifier)) + (std::get<1>(letter_identifier) ? "2" : "1"); if (letter_info.defined_in.size() > 1) { std::cout << "Letter " << letter_name << " was defined in multiple places:" << std::endl; for (const RoomIdentifier& room_identifier : letter_info.defined_in) { std::cout << " " << room_identifier.ShortDebugString() << std::endl; } } } void ValidateEnding(const std::string& ending_name, const EndingInfo& ending_info) const { if (ending_info.defined_in.empty()) { std::cout << "Ending " << ending_name << " has no definition, but was referenced:" << std::endl; for (const DoorIdentifier& door_identifier : ending_info.doors_referenced_by) { std::cout << " DOOR " << door_identifier.ShortDebugString() << std::endl; } } else if (ending_info.defined_in.size() > 1) { std::cout << "Ending " << ending_name << " was defined in multiple places:" << std::endl; for (const RoomIdentifier& room_identifier : ending_info.defined_in) { std::cout << " " << room_identifier.ShortDebugString() << std::endl; } } } void ValidatePanelName(const std::string& panel_name, const PanelNameInfo& panel_info) const { if (panel_info.panels_used_by.size() > 1) { std::cout << "The location name \"" << panel_name << "\" is used by multiple panels:" << std::endl; for (const PanelIdentifier& panel_identifier : panel_info.panels_used_by) { std::cout << " PANEL " << panel_identifier.ShortDebugString() << std::endl; } } } const CollectedInfo& info_; }; } // namespace void ValidateCollectedInfo(const CollectedInfo& info) { Validator validator(info); validator.Validate(); } } // namespace com::fourisland::lingo2_archipelago