2019-01-23 14:54:29 -05:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <map>
|
2019-08-06 04:13:18 -04:00
|
|
|
#include <functional>
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fwd:
|
2020-04-03 02:57:01 -04:00
|
|
|
class cBlockHandler;
|
2019-01-23 14:54:29 -05:00
|
|
|
class BlockState;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Complete information about a single block type.
|
|
|
|
The BlockTypeRegistry uses this structure to store the registered information. */
|
|
|
|
class BlockInfo
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
/** Callback is used to query block hints dynamically, based on the current BlockState.
|
|
|
|
Useful for example for redstone lamps that can be turned on or off. */
|
|
|
|
using HintCallback = std::function<AString(const AString & aTypeName, const BlockState & aBlockState)>;
|
|
|
|
|
|
|
|
|
|
|
|
/** Creates a new instance with the specified BlockTypeName and handler / hints / callbacks.
|
|
|
|
aPluginName specifies the name of the plugin to associate with the block type (to allow unload / reload). */
|
|
|
|
BlockInfo(
|
|
|
|
const AString & aPluginName,
|
|
|
|
const AString & aBlockTypeName,
|
|
|
|
std::shared_ptr<cBlockHandler> aHandler,
|
|
|
|
const std::map<AString, AString> & aHints = std::map<AString, AString>(),
|
|
|
|
const std::map<AString, HintCallback> & aHintCallbacks = std::map<AString, HintCallback>()
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/** Retrieves the value associated with the specified hint for this specific BlockTypeName and BlockState.
|
2019-01-24 03:48:30 -05:00
|
|
|
Queries hint callbacks first, then static hints if a callback doesn't exist.
|
2019-01-23 14:54:29 -05:00
|
|
|
Returns an empty string if hint not found at all. */
|
|
|
|
AString hintValue(
|
|
|
|
const AString & aHintName,
|
|
|
|
const BlockState & aBlockState
|
|
|
|
);
|
|
|
|
|
|
|
|
// Simple getters:
|
2020-05-08 21:38:17 -04:00
|
|
|
const AString & pluginName() const { return m_PluginName; }
|
|
|
|
const AString & blockTypeName() const { return m_BlockTypeName; }
|
|
|
|
std::shared_ptr<cBlockHandler> handler() const { return m_Handler; }
|
2019-01-23 14:54:29 -05:00
|
|
|
|
2019-01-24 03:48:30 -05:00
|
|
|
/** Sets (creates or updates) a static hint.
|
|
|
|
Hints provided by callbacks are unaffected by this - callbacks are "higher priority", they overwrite anything set here.
|
|
|
|
Logs an info message if the hint is already provided by a hint callback. */
|
|
|
|
void setHint(const AString & aHintKey, const AString & aHintValue);
|
|
|
|
|
|
|
|
/** Removes a hint.
|
|
|
|
Silently ignored if the hint hasn't been previously set. */
|
|
|
|
void removeHint(const AString & aHintKey);
|
|
|
|
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/** The name of the plugin that registered the block. */
|
2020-05-08 21:38:17 -04:00
|
|
|
AString m_PluginName;
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
/** The name of the block type, such as "minecraft:redstone_lamp" */
|
2020-05-08 21:38:17 -04:00
|
|
|
AString m_BlockTypeName;
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
/** The callbacks to call for various interaction. */
|
2020-05-08 21:38:17 -04:00
|
|
|
std::shared_ptr<cBlockHandler> m_Handler;
|
2019-01-23 14:54:29 -05:00
|
|
|
|
2019-01-24 03:48:30 -05:00
|
|
|
/** Optional static hints for any subsystem to use, such as "IsSnowable" -> "1".
|
2020-05-08 21:38:17 -04:00
|
|
|
Hint callbacks are of higher priority than m_Hints - if a hint is provided by a m_HintCallback, its value in m_Hints is ignored. */
|
|
|
|
std::map<AString, AString> m_Hints;
|
2019-01-23 14:54:29 -05:00
|
|
|
|
2019-01-24 03:48:30 -05:00
|
|
|
/** The callbacks for dynamic evaluation of hints, such as "LightValue" -> function(BlockTypeName, BlockState).
|
2020-05-08 21:38:17 -04:00
|
|
|
Hint callbacks are of higher priority than m_Hints - if a hint is provided by a m_HintCallback, its value in m_Hints is ignored. */
|
|
|
|
std::map<AString, HintCallback> m_HintCallbacks;
|
2019-01-23 14:54:29 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Stores information on all known block types.
|
|
|
|
Can dynamically add and remove block types.
|
|
|
|
Block types are identified using BlockTypeName.
|
|
|
|
Supports unregistering and re-registering the same type by the same plugin.
|
|
|
|
Stores the name of the plugin that registered the type, for better plugin error messages ("already registered in X")
|
|
|
|
and so that we can unload and reload plugins. */
|
|
|
|
class BlockTypeRegistry
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// fwd:
|
|
|
|
class AlreadyRegisteredException;
|
2019-01-24 03:48:30 -05:00
|
|
|
class NotRegisteredException;
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
|
|
|
|
/** Creates an empty new instance of the block type registry */
|
|
|
|
BlockTypeRegistry() = default;
|
|
|
|
|
|
|
|
/** Registers the specified block type.
|
|
|
|
If the block type already exists and the plugin is the same, updates the registration.
|
|
|
|
If the block type already exists and the plugin is different, throws an AlreadyRegisteredException. */
|
|
|
|
void registerBlockType(
|
|
|
|
const AString & aPluginName,
|
|
|
|
const AString & aBlockTypeName,
|
|
|
|
std::shared_ptr<cBlockHandler> aHandler,
|
|
|
|
const std::map<AString, AString> & aHints = std::map<AString, AString>(),
|
|
|
|
const std::map<AString, BlockInfo::HintCallback> & aHintCallbacks = std::map<AString, BlockInfo::HintCallback>()
|
|
|
|
);
|
|
|
|
|
|
|
|
/** Returns the registration information for the specified BlockTypeName.
|
|
|
|
Returns nullptr if BlockTypeName not found. */
|
|
|
|
std::shared_ptr<BlockInfo> blockInfo(const AString & aBlockTypeName);
|
|
|
|
|
|
|
|
/** Removes all registrations done by the specified plugin. */
|
|
|
|
void removeAllByPlugin(const AString & aPluginName);
|
|
|
|
|
2019-01-24 03:48:30 -05:00
|
|
|
/** Sets (adds or overwrites) a single Hint value for a BlockType.
|
|
|
|
Throws NotRegisteredException if the BlockTypeName is not registered. */
|
|
|
|
void setBlockTypeHint(
|
|
|
|
const AString & aBlockTypeName,
|
|
|
|
const AString & aHintKey,
|
|
|
|
const AString & aHintValue
|
|
|
|
);
|
|
|
|
|
|
|
|
/** Removes a previously registered single Hint value for a BlockType.
|
|
|
|
Throws NotRegisteredException if the BlockTypeName is not registered.
|
|
|
|
Silently ignored if the Hint hasn't been previously set. */
|
|
|
|
void removeBlockTypeHint(
|
|
|
|
const AString & aBlockTypeName,
|
|
|
|
const AString & aHintKey
|
|
|
|
);
|
|
|
|
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/** The actual block type registry.
|
|
|
|
Maps the BlockTypeName to the BlockInfo instance. */
|
2020-05-08 21:38:17 -04:00
|
|
|
std::map<AString, std::shared_ptr<BlockInfo>> m_Registry;
|
2019-01-23 14:54:29 -05:00
|
|
|
|
2020-05-08 21:38:17 -04:00
|
|
|
/** The CS that protects m_Registry against multithreaded access. */
|
|
|
|
cCriticalSection m_CSRegistry;
|
2019-01-23 14:54:29 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** The exception thrown from BlockTypeRegistry::registerBlockType() if the same block type is being registered from a different plugin. */
|
|
|
|
class BlockTypeRegistry::AlreadyRegisteredException: public std::runtime_error
|
|
|
|
{
|
|
|
|
using Super = std::runtime_error;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/** Creates a new instance of the exception that provides info on both the original registration and the newly attempted
|
|
|
|
registration that caused the failure. */
|
|
|
|
AlreadyRegisteredException(
|
2020-05-14 18:15:35 -04:00
|
|
|
const std::shared_ptr<BlockInfo> & aPreviousRegistration,
|
|
|
|
const std::shared_ptr<BlockInfo> & aNewRegistration
|
2019-01-23 14:54:29 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
// Simple getters:
|
2020-05-08 21:38:17 -04:00
|
|
|
std::shared_ptr<BlockInfo> previousRegistration() const { return m_PreviousRegistration; }
|
|
|
|
std::shared_ptr<BlockInfo> newRegistration() const { return m_NewRegistration; }
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
2020-05-08 21:38:17 -04:00
|
|
|
std::shared_ptr<BlockInfo> m_PreviousRegistration;
|
|
|
|
std::shared_ptr<BlockInfo> m_NewRegistration;
|
2019-01-23 14:54:29 -05:00
|
|
|
|
|
|
|
|
|
|
|
/** Returns the general exception message formatted by the two registrations.
|
|
|
|
The output is used when logging. */
|
|
|
|
static AString message(
|
2020-05-14 18:15:35 -04:00
|
|
|
const std::shared_ptr<BlockInfo> & aPreviousRegistration,
|
|
|
|
const std::shared_ptr<BlockInfo> & aNewRegistration
|
2019-01-23 14:54:29 -05:00
|
|
|
);
|
|
|
|
};
|
2019-01-24 03:48:30 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** The exception thrown from BlockTypeRegistry::setBlockTypeHint() if the block type has not been registered before. */
|
|
|
|
class BlockTypeRegistry::NotRegisteredException: public std::runtime_error
|
|
|
|
{
|
|
|
|
using Super = std::runtime_error;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/** Creates a new instance of the exception that provides info on both the original registration and the newly attempted
|
|
|
|
registration that caused the failure. */
|
|
|
|
NotRegisteredException(
|
|
|
|
const AString & aBlockTypeName,
|
|
|
|
const AString & aHintKey,
|
|
|
|
const AString & aHintValue
|
|
|
|
);
|
|
|
|
|
|
|
|
// Simple getters:
|
2020-05-08 21:38:17 -04:00
|
|
|
const AString & blockTypeName() const { return m_BlockTypeName; }
|
2019-01-24 03:48:30 -05:00
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
2020-05-08 21:38:17 -04:00
|
|
|
const AString m_BlockTypeName;
|
2019-01-24 03:48:30 -05:00
|
|
|
};
|