summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattes D <github@xoft.cz>2019-01-24 09:48:30 +0100
committerMattes D <github@xoft.cz>2019-08-05 21:42:54 +0200
commitf48ac9f0c3fae1e5ea04768183e07823879a7d79 (patch)
treeddb7b405100ce3486136f85ac97c409ab600b373
parentBlockTypeRegistry: Initial skeleton (diff)
downloadcuberite-f48ac9f0c3fae1e5ea04768183e07823879a7d79.tar
cuberite-f48ac9f0c3fae1e5ea04768183e07823879a7d79.tar.gz
cuberite-f48ac9f0c3fae1e5ea04768183e07823879a7d79.tar.bz2
cuberite-f48ac9f0c3fae1e5ea04768183e07823879a7d79.tar.lz
cuberite-f48ac9f0c3fae1e5ea04768183e07823879a7d79.tar.xz
cuberite-f48ac9f0c3fae1e5ea04768183e07823879a7d79.tar.zst
cuberite-f48ac9f0c3fae1e5ea04768183e07823879a7d79.zip
-rw-r--r--src/BlockTypeRegistry.cpp85
-rw-r--r--src/BlockTypeRegistry.h62
-rw-r--r--tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp37
3 files changed, 181 insertions, 3 deletions
diff --git a/src/BlockTypeRegistry.cpp b/src/BlockTypeRegistry.cpp
index 45ad20082..cc6945e27 100644
--- a/src/BlockTypeRegistry.cpp
+++ b/src/BlockTypeRegistry.cpp
@@ -56,6 +56,33 @@ AString BlockInfo::hintValue(
+void BlockInfo::setHint(const AString & aHintKey, const AString & aHintValue)
+{
+ mHints[aHintKey] = aHintValue;
+
+ // Warn if the hint is already provided by a callback (aHintValue will be ignored when evaluating the hint):
+ auto itrC = mHintCallbacks.find(aHintKey);
+ if (itrC != mHintCallbacks.end())
+ {
+ LOGINFO("Setting a static hint %s for block type %s, but there's already a callback for that hint. The static hint will be ignored.",
+ aHintKey.c_str(), mBlockTypeName.c_str()
+ );
+ }
+}
+
+
+
+
+
+void BlockInfo::removeHint(const AString & aHintKey)
+{
+ mHints.erase(aHintKey);
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// BlockTypeRegistry:
@@ -123,6 +150,43 @@ void BlockTypeRegistry::removeAllByPlugin(const AString & aPluginName)
+void BlockTypeRegistry::setBlockTypeHint(
+ const AString & aBlockTypeName,
+ const AString & aHintKey,
+ const AString & aHintValue
+)
+{
+ cCSLock lock(mCSRegistry);
+ auto blockInfo = mRegistry.find(aBlockTypeName);
+ if (blockInfo == mRegistry.end())
+ {
+ throw NotRegisteredException(aBlockTypeName, aHintKey, aHintValue);
+ }
+ blockInfo->second->setHint(aHintKey, aHintValue);
+}
+
+
+
+
+
+void BlockTypeRegistry::removeBlockTypeHint(
+ const AString & aBlockTypeName,
+ const AString & aHintKey
+)
+{
+ cCSLock lock(mCSRegistry);
+ auto blockInfo = mRegistry.find(aBlockTypeName);
+ if (blockInfo == mRegistry.end())
+ {
+ return;
+ }
+ blockInfo->second->removeHint(aHintKey);
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// BlockTypeRegistry::AlreadyRegisteredException:
@@ -151,3 +215,24 @@ AString BlockTypeRegistry::AlreadyRegisteredException::message(
aPreviousRegistration->pluginName().c_str()
);
}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// BlockTypeRegistry::NotRegisteredException:
+
+BlockTypeRegistry::NotRegisteredException::NotRegisteredException(
+ const AString & aBlockTypeName,
+ const AString & aHintKey,
+ const AString & aHintValue
+):
+ Super(Printf(
+ "Attempting to set a hint of nonexistent BlockTypeName.\n\tBlockTypeName = %s\n\tHintKey = %s\n\tHintValue = %s",
+ aBlockTypeName.c_str(),
+ aHintKey.c_str(),
+ aHintValue.c_str()
+ ))
+{
+}
diff --git a/src/BlockTypeRegistry.h b/src/BlockTypeRegistry.h
index 6a24445c5..3fbcc44c2 100644
--- a/src/BlockTypeRegistry.h
+++ b/src/BlockTypeRegistry.h
@@ -40,7 +40,7 @@ public:
/** Retrieves the value associated with the specified hint for this specific BlockTypeName and BlockState.
- Queries callbacks first, then hints if a callback doesn't exist.
+ Queries hint callbacks first, then static hints if a callback doesn't exist.
Returns an empty string if hint not found at all. */
AString hintValue(
const AString & aHintName,
@@ -52,6 +52,15 @@ public:
const AString & blockTypeName() const { return mBlockTypeName; }
std::shared_ptr<cBlockHandler> handler() const { return mHandler; }
+ /** 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);
+
private:
@@ -64,10 +73,12 @@ private:
/** The callbacks to call for various interaction. */
std::shared_ptr<cBlockHandler> mHandler;
- /** Optional hints for any subsystem to use, such as "IsSnowable" -> "1". */
+ /** Optional static hints for any subsystem to use, such as "IsSnowable" -> "1".
+ Hint callbacks are of higher priority than mHints - if a hint is provided by a mHintCallback, its value in mHints is ignored. */
std::map<AString, AString> mHints;
- /** The callbacks for dynamic evaluation of hints, such as "LightValue" -> function(BlockTypeName, BlockState). */
+ /** The callbacks for dynamic evaluation of hints, such as "LightValue" -> function(BlockTypeName, BlockState).
+ Hint callbacks are of higher priority than mHints - if a hint is provided by a mHintCallback, its value in mHints is ignored. */
std::map<AString, HintCallback> mHintCallbacks;
};
@@ -86,6 +97,7 @@ class BlockTypeRegistry
public:
// fwd:
class AlreadyRegisteredException;
+ class NotRegisteredException;
/** Creates an empty new instance of the block type registry */
@@ -109,6 +121,22 @@ public:
/** Removes all registrations done by the specified plugin. */
void removeAllByPlugin(const AString & aPluginName);
+ /** 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
+ );
+
private:
@@ -156,3 +184,31 @@ private:
std::shared_ptr<BlockInfo> aNewRegistration
);
};
+
+
+
+
+
+/** 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:
+ const AString & blockTypeName() const { return mBlockTypeName; }
+
+
+private:
+
+ const AString mBlockTypeName;
+};
diff --git a/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp b/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp
index c2d8717e5..3479e55d7 100644
--- a/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp
+++ b/tests/BlockTypeRegistry/BlockTypeRegistryTest.cpp
@@ -64,6 +64,42 @@ static void testSimpleReg()
+/** Tests setting and removing a BlockType hint. */
+static void testHintSetRemove()
+{
+ LOGD("Testing hint addition and removal...");
+
+ // Register the block type:
+ BlockTypeRegistry reg;
+ AString blockTypeName("test:block1");
+ AString pluginName("testPlugin");
+ AString hint1("testHint1");
+ AString hint1Value("value1");
+ AString hint2("testHint2");
+ AString hint2Value("value2");
+ std::shared_ptr<cBlockHandler> handler(new cBlockHandler(0x12345678));
+ std::map<AString, AString> hints = {{hint1, hint1Value}};
+ std::map<AString, BlockInfo::HintCallback> hintCallbacks;
+ reg.registerBlockType(pluginName, blockTypeName, handler, hints, hintCallbacks);
+
+ // Modify the hints:
+ auto blockInfo = reg.blockInfo(blockTypeName);
+ reg.setBlockTypeHint(blockTypeName, hint2, hint2Value);
+ TEST_EQUAL(blockInfo->hintValue(hint2, BlockState()), hint2Value); // Was created successfully
+ reg.setBlockTypeHint(blockTypeName, hint1, "testValue2");
+ TEST_EQUAL(blockInfo->hintValue(hint1, BlockState()), "testValue2"); // Was updated successfully
+ reg.removeBlockTypeHint(blockTypeName, hint2);
+ TEST_EQUAL(blockInfo->hintValue(hint2, BlockState()), ""); // Was removed successfully
+
+ // Test the error reporting:
+ TEST_THROWS(reg.setBlockTypeHint("nonexistent", "hint", "value"), BlockTypeRegistry::NotRegisteredException);
+ reg.removeBlockTypeHint(blockTypeName, "nonexistent"); // Should fail silently
+}
+
+
+
+
+
/** Tests that the plugin-based information is used correctly for registration.
Registers two different block types with two different plugins, then tries to re-register them from a different plugin.
Finally removes the registration through removeAllByPlugin() and checks its success. */
@@ -190,6 +226,7 @@ static void testThreadLocking()
static void testBlockTypeRegistry()
{
testSimpleReg();
+ testHintSetRemove();
testPlugins();
testHintCallbacks();
testThreadLocking();