about summary refs log tree commit diff stats
path: root/tools/datapacker/main.cpp
Commit message (Expand)AuthorAgeFilesLines
* Added door groupsStar Rauchenberger2025-09-071-0/+31
* Added option for Daedalus roof access logicStar Rauchenberger2025-09-031-0/+5
* Added keyholder sanityStar Rauchenberger2025-09-021-0/+12
* Added progressive doorsStar Rauchenberger2025-09-011-2/+31
* Handled cyan doorsStar Rauchenberger2025-08-311-0/+4
* Changed how door location names are formattedStar Rauchenberger2025-08-301-1/+13
* Renamed Painting and Keyholder protosStar Rauchenberger2025-08-271-2/+2
* Added control_centerStar Rauchenberger2025-08-271-0/+4
* Maps have display names nowStar Rauchenberger2025-08-201-0/+17
* Added "endings" object typeStar Rauchenberger2025-08-201-0/+22
* Store IDs in a yaml fileStar Rauchenberger2025-08-191-2/+3
* Minor changes for compiling on WindowsStar Rauchenberger2025-08-161-1/+1
* Assigned IDs for the_galleryStar Rauchenberger2025-08-131-0/+7
* Converted to proto2Star Rauchenberger2025-08-121-8/+8
* Add gravity to paintings/portsStar Rauchenberger2025-08-111-2/+6
* Assigned IDs for the_congruentStar Rauchenberger2025-08-101-0/+43
* Assigned IDs for the_colorfulStar Rauchenberger2025-08-101-0/+9
* Added support for masteriesStar Rauchenberger2025-08-091-3/+48
* Propagate complete_at to packed datafileStar Rauchenberger2025-08-091-2/+6
* Added special IDsStar Rauchenberger2025-08-071-0/+5
* Assign AP IDs to doors and panelsStar Rauchenberger2025-08-071-0/+21
* Started apworldStar Rauchenberger2025-08-071-0/+8
* Process the rest of the defined protosStar Rauchenberger2025-08-071-1/+199
* Protobuf works! Parsing connectionsStar Rauchenberger2025-08-071-3/+193
* Trying out protobuf I guessStar Rauchenberger2025-08-071-0/+21
href='#n298'>298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
#include <google/protobuf/message.h>
#include <google/protobuf/text_format.h>

#include <cstdint>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <string>

#include "proto/human.pb.h"
#include "util/ids_yaml_format.h"
#include "util/naming.h"

namespace com::fourisland::lingo2_archipelago {
namespace {

template <typename T>
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 AssignIds {
 public:
  AssignIds(const std::string& mapdir) : mapdir_(mapdir) {}

  void Run() {
    std::filesystem::path datadir_path = mapdir_;
    std::filesystem::path ids_path = datadir_path / "ids.yaml";

    ReadIds(ids_path);

    ProcessMaps(datadir_path);
    ProcessSpecialIds();
    ProcessProgressivesFile(datadir_path / "progressives.txtpb");
    ProcessDoorGroupsFile(datadir_path / "door_groups.txtpb");

    WriteIds(ids_path);

    std::cout << "Next ID: " << next_id_ << std::endl;
  }

  void ReadIds(std::filesystem::path path) {
    if (!std::filesystem::exists(path)) {
      return;
    }

    id_mappings_ = ReadIdsFromYaml(path.string());

    for (const auto& [_, map] : id_mappings_.maps()) {
      UpdateNextId(map.doors());

      for (const auto& [_, room] : map.rooms()) {
        UpdateNextId(room.panels());
        UpdateNextId(room.masteries());
        UpdateNextId(room.keyholders());
      }
    }

    UpdateNextId(id_mappings_.special());
    UpdateNextId(id_mappings_.letters());
    UpdateNextId(id_mappings_.endings());
    UpdateNextId(id_mappings_.progressives());
    UpdateNextId(id_mappings_.door_groups());

    next_id_++;
  }

  void WriteIds(std::filesystem::path path) {
    WriteIdsAsYaml(output_, path.string());
  }

  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();

    ProcessDoorsFile(path / "doors.txtpb", map_name);
    ProcessRooms(path / "rooms", map_name);
  }

  void ProcessDoorsFile(std::filesystem::path path,
                        const std::string& current_map_name) {
    if (!std::filesystem::exists(path)) {
      return;
    }

    auto doors = ReadMessageFromFile<HumanDoors>(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) {
    if (h_door.type() == DoorType::EVENT) {
      return;
    }

    auto& maps = *output_.mutable_maps();
    auto& doors = *maps[current_map_name].mutable_doors();

    if (!id_mappings_.maps().contains(current_map_name) ||
        !id_mappings_.maps()
             .at(current_map_name)
             .doors()
             .contains(h_door.name())) {
      doors[h_door.name()] = next_id_++;
    } else {
      doors[h_door.name()] =
          id_mappings_.maps().at(current_map_name).doors().at(h_door.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<HumanRoom>(dir_entry.path().string());
      ProcessRoom(room, current_map_name);
    }
  }

  void ProcessRoom(const HumanRoom& h_room,
                   const std::string& current_map_name) {
    for (const HumanPanel& h_panel : h_room.panels()) {
      auto& maps = *output_.mutable_maps();
      auto& rooms = *maps[current_map_name].mutable_rooms();
      auto& panels = *rooms[h_room.name()].mutable_panels();

      if (!id_mappings_.maps().contains(current_map_name) ||
          !id_mappings_.maps()
               .at(current_map_name)
               .rooms()
               .contains(h_room.name()) ||
          !id_mappings_.maps()
               .at(current_map_name)
               .rooms()
               .at(h_room.name())
               .panels()
               .contains(h_panel.name())) {
        panels[h_panel.name()] = next_id_++;
      } else {
        panels[h_panel.name()] = id_mappings_.maps()
                                     .at(current_map_name)
                                     .rooms()
                                     .at(h_room.name())
                                     .panels()
                                     .at(h_panel.name());
      }
    }

    for (const HumanLetter& h_letter : h_room.letters()) {
      std::string lettername = GetLetterName(h_letter.key(), h_letter.level2());

      auto& letters = *output_.mutable_letters();
      if (!id_mappings_.letters().contains(lettername)) {
        letters[lettername] = next_id_++;
      } else {
        letters[lettername] = id_mappings_.letters().at(lettername);
      }
    }

    for (const HumanMastery& h_mastery : h_room.masteries()) {
      auto& maps = *output_.mutable_maps();
      auto& rooms = *maps[current_map_name].mutable_rooms();
      auto& masteries = *rooms[h_room.name()].mutable_masteries();

      if (!id_mappings_.maps().contains(current_map_name) ||
          !id_mappings_.maps()
               .at(current_map_name)
               .rooms()
               .contains(h_room.name()) ||
          !id_mappings_.maps()
               .at(current_map_name)
               .rooms()
               .at(h_room.name())
               .masteries()
               .contains(h_mastery.name())) {
        masteries[h_mastery.name()] = next_id_++;
      } else {
        masteries[h_mastery.name()] = id_mappings_.maps()
                                          .at(current_map_name)
                                          .rooms()
                                          .at(h_room.name())
                                          .masteries()
                                          .at(h_mastery.name());
      }
    }

    for (const HumanEnding& h_ending : h_room.endings()) {
      auto& endings = *output_.mutable_endings();

      if (!id_mappings_.endings().contains(h_ending.name())) {
        endings[h_ending.name()] = next_id_++;
      } else {
        endings[h_ending.name()] = id_mappings_.endings().at(h_ending.name());
      }
    }

    for (const HumanKeyholder& h_keyholder : h_room.keyholders()) {
      if (!h_keyholder.has_key()) {
        continue;
      }

      auto& maps = *output_.mutable_maps();
      auto& rooms = *maps[current_map_name].mutable_rooms();
      auto& keyholders = *rooms[h_room.name()].mutable_keyholders();

      if (!id_mappings_.maps().contains(current_map_name) ||
          !id_mappings_.maps()
               .at(current_map_name)
               .rooms()
               .contains(h_room.name()) ||
          !id_mappings_.maps()
               .at(current_map_name)
               .rooms()
               .at(h_room.name())
               .keyholders()
               .contains(h_keyholder.name())) {
        keyholders[h_keyholder.name()] = next_id_++;
      } else {
        keyholders[h_keyholder.name()] = id_mappings_.maps()
                                             .at(current_map_name)
                                             .rooms()
                                             .at(h_room.name())
                                             .keyholders()
                                             .at(h_keyholder.name());
      }
    }
  }

  void ProcessSpecialIds() {
    auto& specials = *output_.mutable_special();

    for (const auto& [special_name, ap_id] : id_mappings_.special()) {
      specials[special_name] = ap_id;
    }
  }

  void ProcessProgressivesFile(std::filesystem::path path) {
    if (!std::filesystem::exists(path)) {
      return;
    }

    auto h_progs = ReadMessageFromFile<HumanProgressives>(path.string());
    auto& progs = *output_.mutable_progressives();

    for (const HumanProgressive& h_prog : h_progs.progressives()) {
      if (!id_mappings_.progressives().contains(h_prog.name())) {
        progs[h_prog.name()] = next_id_++;
      } else {
        progs[h_prog.name()] = id_mappings_.progressives().at(h_prog.name());
      }
    }
  }

  void ProcessDoorGroupsFile(std::filesystem::path path) {
    if (!std::filesystem::exists(path)) {
      return;
    }

    auto h_groups = ReadMessageFromFile<HumanDoorGroups>(path.string());
    auto& groups = *output_.mutable_door_groups();

    for (const HumanDoorGroup& h_group : h_groups.door_groups()) {
      if (!id_mappings_.door_groups().contains(h_group.name())) {
        groups[h_group.name()] = next_id_++;
      } else {
        groups[h_group.name()] = id_mappings_.door_groups().at(h_group.name());
      }
    }
  }

 private:
  void UpdateNextId(const google::protobuf::Map<std::string, uint64_t>& ids) {
    for (const auto& [_, id] : ids) {
      if (id > next_id_) {
        next_id_ = id;
      }
    }
  }

  std::string mapdir_;

  uint64_t next_id_ = 1;

  IdMappings id_mappings_;
  IdMappings output_;
};

}  // namespace
}  // namespace com::fourisland::lingo2_archipelago

int main(int argc, char** argv) {
  if (argc != 2) {
    std::cout << "Incorrect argument count." << std::endl;
    std::cout << "Usage: assign_ids [path to map directory]" << std::endl;
    return 1;
  }

  std::string mapdir = argv[1];

  com::fourisland::lingo2_archipelago::AssignIds assign_ids(mapdir);
  assign_ids.Run();

  return 0;
}