Building Lockf - A Lockette-like lock-your-*-with-signs plugin

I’m a huge fan of Lockette but I cannot find equivalent dedicated plugin for Sponge to lock my chests with a sign starting with “[Private]”.

I’m using Nucleus as the Essentials in Bukkit since I need /tpa and /home.
I don’t really need world protection or territory system other than chest locks…
So GriefPrevention and RedProtect seems too heavy for me…

Keys is the most similar plugin I want, but I don’t expect my users to lock their chests using command…
So I decide to do my best to make a fast plugin for my own server called “Lockf” based on Keys.

Lockf will lock every connecting “lockable” blocks when you place a sign.
It’s fun to realize that I can theoretically use Lockf to lock my territory by placing a sign on my floor after setting the floor material to lockable and extend the lockdown area to include every block sharing the same x y coordinate.

I create a table in the DB called “signs”, based on Keys, to store the signs:
CREATE TABLE IF NOT EXISTS signs (id INT PRIMARY KEY AUTO_INCREMENT, x INT, y INT, z INT, area INT)
And an actual locked area “areas”:
CREATE TABLE IF NOT EXISTS areas (id INT PRIMARY KEY AUTO_INCREMENT, sign_id INT, world UUID, x INT, y INT)
with indices:
CREATE INDEX IF NOT EXISTS location ON areas(world, x, y)
and:
CREATE INDEX IF NOT EXISTS sign ON areas(sign_id)

I use a Map<Vector2i, Integer> cachedSignIdMap = new HashMap<>() to cached the sign_id lookup.

To see if a block is locked, try to find the sign_id of the area (if no sign_id selected, mark cachedSignIdMap[?] to -1, not locked):
SELECT sign_id FROM areas WHERE world = ? AND x = ? AND y = ?
Find the coordinate of the sign (if no x, y, z selected, invalid sign_id, delete areas with sign_id):
SELECT x, y, z FROM signs WHERE id = ?
Then, check if the sign exists in the world (if no sign, invalid sign_id, delete sign and its areas):
signTypes.contains(block.getBlockType())
Then, check if the sign has the title curse (if no curse, invalid sign_id, delete sign and its areas):
curse.equals(Texts.toPlain(block.getTileEntity().get().getLine(0)))
Then, check if the player is in the remaining lines.

The lock remains as long as the sign still exists.

The first check (if the block is in some area) will be cached using a hashmap.
The size of the max connecting area is configurable.

I’m writing the plugin right now and happy to hear any suggestions.

Is there really any need for a DB? You need to call the DB on every interaction event; since these events happen rather often, you will slow down your server (besides, if you want to check if something exists in the DB, use EXISTS not SELECT).

I suppose you would need to cache DB data locally to speed things up. But if you are doing this, data can be simply stored in a plain text configuration file that might be easier to handle for you.

On a different node, depending on your feature set you might be able to go without any storage, if there is a defined position for the sign (e.g. directly on the chest). In this case, you could simply check if a sign exists upon interaction which is fast. However, this might not work for protected areas…

Thanks for pointing out!

Yeah, the DB thing is just for protected area… If the Lockf is just for the chests or doors, then no DB is fine (but that cannot bear the name Lockf)… xD
I use the select to get the sign_id of the area or x,y,z of the sign, and use a Map<Vector2i, Integer> to cache the signId. signId in the map will be -1 if not protected.

I’m thinking about a “NoSQL” implementation in which I keep everything in the memory and only use maps to do the lookup. Load from and save to a config file to get the “SQL” at the start and the end of the game.
That maybe is faster?

Better use Guava’s cache (CacheLoader could become handy to quietly load values from the DB).

Great advise!

I’ll use LoadingCache<Vector2i, Integer> cachedSignIdMap to cache the signId;
And LoadingCache<Integer, Vector3i> cachedSignCoordMap to cache the signCoord.

Actually, Caffeine’s cache would be a better idea (given that Sponge already includes it).

2 Likes