Files
dusklight/src/dusk/randomizer/generator/randomizer.cpp
T
CraftyBoss 6366ab61d1 add inventory resetting on server connect, properly handle getting new items from locations, integrate some of archi into new rando ui stuff
For the most part, solo archipelago runs seem to work fine now using the original TP apworld, but im sure there are plenty of weird issues still that need to be handled.
2026-06-19 17:07:42 -07:00

179 lines
6.2 KiB
C++

#include "randomizer.hpp"
#include "logic/entrance_shuffle.hpp"
#include "logic/fill.hpp"
#include "logic/flatten/flatten.hpp"
#include "logic/hints.hpp"
#include "logic/plandomizer.hpp"
#include "logic/search.hpp"
#include "logic/spoiler_log.hpp"
#include "logic/world.hpp"
#include "seedgen/config.hpp"
#include "seedgen/settings.hpp"
#include "utility/time.hpp"
#include <iostream>
#include "dusk/logging.h"
#include "dusk/archipelago/archipelago_context.hpp"
#include "dusk/ui/rando_config.hpp"
#include "dusk/randomizer/game/randomizer_context.hpp"
namespace randomizer
{
logic::world::World* Randomizer::GetWorld(int worldId /*= 1*/) {
auto worldIndex = worldId - 1;
if (worldIndex < this->_worlds.size()) {
return this->_worlds.at(worldIndex).get();
}
return nullptr;
}
std::optional<std::string> Randomizer::Generate()
{
try
{
GenerateWorlds();
}
catch(const std::exception& e)
{
std::cout << "============================================================" << std::endl;
std::cout << "The following exception occured: " << e.what() << std::endl;
return e.what();
}
return std::nullopt;
}
void Randomizer::GenerateTrackerWorld(bool useAntiSpoilerLog) {
auto contextHash = randomizer_GetContext().mHash;
if (!useAntiSpoilerLog) {
this->_config.LoadFromFile(GetConfigPath(), GetPrefPath());
this->_config.SetHash(contextHash);
}else {
if (contextHash.empty()) {
return;
}
std::filesystem::path seedSettings = dusk::ui::GetRandomizerSeedsPath() /
contextHash / (contextHash + " Anti-Spoiler Log.txt");
this->_config.LoadFromFile(seedSettings, GetPrefPath());
this->_config.SetHash(contextHash);
}
std::unique_ptr<logic::world::World> world = std::make_unique<logic::world::World>(1, this);
world->SetSettings(this->_config.GetSettingsList().front());
// Always use logic when building a tracker world
world->Setting("Logic Rules").SetCurrentOption("All Locations Reachable");
world->Build();
this->_worlds.emplace_back(std::move(world));
auto trackerWorld = this->_worlds.at(0).get();
trackerWorld->SetNonProgressLocations();
trackerWorld->SetTrackerNonProgressLocations();
trackerWorld->AssignAreaProperties();
trackerWorld->AssignGoalLocations();
// Cache exit form times. This *must* run before conducting the flattening search, otherwise
// the flattening search will pollute the exit timeform cache with a bunch of zeros
logic::fill::CacheExitTimeForms(this->_worlds);
// Set raw requirements for each location
FlattenSearch search = FlattenSearch(trackerWorld);
search.doSearch();
}
void Randomizer::GenerateWorlds()
{
utility::time::ScopedTimer<"Seed generation took ", std::chrono::milliseconds> timer;
this->_config.LoadFromFile(GetConfigPath(), GetPrefPath());
utility::platform::Log(std::string("Seed: ") + this->_config.GetSeed());
seedgen::config::SeedRNG(this->_config, true, false);
// Set the hash now before anything else random is decided. This allows us to show the hash for a seed
// before generating it later
auto hash = this->_config.GetHash();
utility::platform::Log(std::string("Hash: ") + hash);
// Build all worlds
int worldId = 1;
for (const auto& settings : this->_config.GetSettingsList())
{
std::unique_ptr<logic::world::World> world = std::make_unique<logic::world::World>(worldId++, this);
world->SetSettings(settings);
world->ResolveRandomSettings();
world->ResolveConflictingSettings();
world->Build();
this->_worlds.emplace_back(std::move(world));
}
// Process Plando Data for all worlds
if (this->_config.IsUsingPlandomizer())
{
try {
logic::plandomizer::LoadPlandomizerData(this->_worlds, this->_config.GetPlandomizerPath());
} catch (const std::runtime_error& e) {
throw std::runtime_error("Plandomizer Error: " + std::string(e.what()));
}
}
// Pre Entrance Shuffle Tasks
for (auto& world : this->_worlds)
{
world->PerformPreEntranceShuffleTasks();
}
utility::platform::Log("Shuffling Entrances...");
for (auto& world : this->_worlds)
{
logic::entrance_shuffle::ShuffleWorldEntrances(world.get());
}
// Post Entrance Shuffle Tasks
for (auto& world : this->_worlds)
{
world->PerformPostEntranceShuffleTasks();
}
logic::fill::CacheExitTimeForms(this->_worlds);
// Flattening isn't used for anything yet, but flattens down the requirements for
// each location and entrance into a single statement. This will be useful for hints and could potentially
// be used to speed up the fill algorithm (but the fill algorithm is already pretty fast, so we'd only gain maybe like
// 0.2 seconds back or something)
utility::platform::Log("Flattening...");
FlattenSearch search = FlattenSearch(this->_worlds.at(0).get());
search.doSearch();
utility::platform::Log("Filling Worlds...");
logic::fill::FillWorlds(this->_worlds);
// Post Fill Tasks
for (auto& world : this->_worlds)
{
world->PerformPostFillTasks();
}
// Generate Playthrough
logic::search::GeneratePlaythrough(this);
// Generate Hints
logic::hints::GenerateAllHints(this->_worlds);
// Write Logs
if (this->_config.IsGeneratingSpoilerLog())
{
logic::spoiler_log::GenerateSpoilerLog(this);
}
logic::spoiler_log::GenerateAntiSpoilerLog(this);
}
std::filesystem::path Randomizer::GetSeedOutputPath()
{
return this->_baseOutputPath / "seeds" / this->_config.GetHash();
}
} // namespace randomizer