diff --git a/core/include/vf/Command.h b/core/include/vf/Command.h new file mode 100644 index 0000000..466d9a3 --- /dev/null +++ b/core/include/vf/Command.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "Container.h" +#include "Item.h" +#include "Math.h" +#include "Mob.h" +#include "StructureGen.h" +#include "Survival.h" +#include "TimeOfDay.h" +#include "Weather.h" +#include "World.h" + +namespace vf { + +enum class GameRuleType : uint8_t { Bool, Int }; + +struct GameRuleValue { + GameRuleType type = GameRuleType::Bool; + bool boolValue = false; + int intValue = 0; +}; + +class GameRules { +public: + GameRules(); + + bool has(const std::string& name) const; + const GameRuleValue* find(const std::string& name) const; + + bool boolValue(const std::string& name) const; + int intValue(const std::string& name) const; + + bool setBool(const std::string& name, bool value); + bool setInt(const std::string& name, int value); + + const std::vector& names() const { return order; } + +private: + void define(const std::string& name, const GameRuleValue& value); + + std::unordered_map rules; + std::vector order; +}; + +// Everything a command may read or mutate. References point at state owned by the +// caller so command effects outlive a single dispatch. The Weather state machine +// exposes no public setter, so a forced weather target is recorded on the context +// for the world simulation to honour instead of being written into Weather. +struct CommandContext { + World& world; + TimeOfDay& time; + Weather& weather; + Container& inventory; + SurvivalState& player; + std::vector& creatures; + GameRules& rules; + + Vec3 callerPos{0.0f, 0.0f, 0.0f}; + uint32_t seed = 0u; + + int worldMinY = 0; + int worldMaxY = 256; + int horizontalLimit = 30000000; + long long maxVolume = 32768; + int locateChunkRadius = 128; + + bool weatherForced = false; + WeatherState forcedWeather = WeatherState::Clear; + long long forcedWeatherDuration = 0; +}; + +struct CommandResult { + bool ok = false; + std::string message; + int affected = 0; + bool hasPosition = false; + Vec3i position{0, 0, 0}; +}; + +using CommandHandler = std::function&)>; + +class CommandDispatcher { +public: + CommandDispatcher(); + + void registerCommand(const std::string& name, CommandHandler handler); + bool hasCommand(const std::string& name) const; + std::vector commandNames() const; + + CommandResult execute(CommandContext& context, const std::string& line) const; + +private: + std::unordered_map handlers; +}; + +std::vector tokenizeCommand(const std::string& line); +bool parseIntArg(const std::string& token, int& out); +bool parseCoordArg(const std::string& token, int base, int& out); +bool parseBlockName(const std::string& token, Block& out); +bool parseItemName(const std::string& token, ItemId& out); +bool parseSpeciesName(const std::string& token, Species& out); +bool parseStructureName(const std::string& token, StructureGenKind& out); + +const char* blockDisplayName(Block block); +const char* itemDisplayName(ItemId item); +const char* speciesDisplayName(Species species); +const char* structureDisplayName(StructureGenKind kind); + +} // namespace vf