mirror of
https://github.com/BentoBoxWorld/CaveBlock.git
synced 2024-12-02 13:13:22 +01:00
Merge branch 'develop' of https://github.com/BentoBoxWorld/CaveBlock.git
into develop
This commit is contained in:
commit
4592043b4e
84
pom.xml
84
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>world.bentobox</groupId>
|
<groupId>world.bentobox</groupId>
|
||||||
<artifactId>caveblock</artifactId>
|
<artifactId>caveblock</artifactId>
|
||||||
<version>0.1.1</version>
|
<version>${revision}</version>
|
||||||
|
|
||||||
<name>CaveBlock</name>
|
<name>CaveBlock</name>
|
||||||
<description>CaveBlock is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like SkyBlock or AcidIsland.</description>
|
<description>CaveBlock is an add-on for BentoBox, an expandable Minecraft Bukkit plugin for island-type games like SkyBlock or AcidIsland.</description>
|
||||||
@ -44,9 +44,45 @@
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<powermock.version>1.7.4</powermock.version>
|
<!-- More visible way how to change dependency versions -->
|
||||||
|
<spigot.version>1.13.2-R0.1-SNAPSHOT</spigot.version>
|
||||||
|
<bentobox.version>1.4.0-SNAPSHOT</bentobox.version>
|
||||||
|
<!-- Revision variable removes warning about dynamic version -->
|
||||||
|
<revision>${build.version}</revision>
|
||||||
|
<!-- This allows to change between versions and snapshots. -->
|
||||||
|
<build.version>1.4.0-SNAPSHOT</build.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>develop</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>env.BUILD_NUMBER</name>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<!-- Override only if necessary -->
|
||||||
|
<revision>${build.version}-SNAPSHOT #${env.BUILD_NUMBER}</revision>
|
||||||
|
<!-- GIT_BRANCH -->
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>master</id>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>env.GIT_BRANCH</name>
|
||||||
|
<value>origin/master</value>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<!-- Override only if necessary -->
|
||||||
|
<revision>${build.version}</revision>
|
||||||
|
<!-- GIT_BRANCH -->
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spigot-repo</id>
|
<id>spigot-repo</id>
|
||||||
@ -62,31 +98,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.13.2-R0.1-SNAPSHOT</version>
|
<version>${spigot.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-all</artifactId>
|
|
||||||
<version>1.10.19</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.powermock</groupId>
|
|
||||||
<artifactId>powermock-module-junit4</artifactId>
|
|
||||||
<version>${powermock.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.powermock</groupId>
|
|
||||||
<artifactId>powermock-api-mockito</artifactId>
|
|
||||||
<version>${powermock.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>world.bentobox</groupId>
|
<groupId>world.bentobox</groupId>
|
||||||
<artifactId>bentobox</artifactId>
|
<artifactId>bentobox</artifactId>
|
||||||
<version>1.4.0-SNAPSHOT</version>
|
<version>${bentobox.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@ -199,28 +217,6 @@
|
|||||||
<artifactId>maven-deploy-plugin</artifactId>
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
<version>2.8.2</version>
|
<version>2.8.2</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.jacoco</groupId>
|
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
|
||||||
<version>0.8.1</version>
|
|
||||||
<configuration>
|
|
||||||
<append>true</append>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>pre-unit-test</id>
|
|
||||||
<goals>
|
|
||||||
<goal>prepare-agent</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>post-unit-test</id>
|
|
||||||
<goals>
|
|
||||||
<goal>report</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
@ -13,7 +13,6 @@ import world.bentobox.bentobox.api.configuration.WorldSettings;
|
|||||||
import world.bentobox.caveblock.commands.AdminCommand;
|
import world.bentobox.caveblock.commands.AdminCommand;
|
||||||
import world.bentobox.caveblock.commands.IslandCommand;
|
import world.bentobox.caveblock.commands.IslandCommand;
|
||||||
import world.bentobox.caveblock.generators.ChunkGeneratorWorld;
|
import world.bentobox.caveblock.generators.ChunkGeneratorWorld;
|
||||||
import world.bentobox.caveblock.listeners.BeaconEnabler;
|
|
||||||
import world.bentobox.caveblock.listeners.CustomHeightLimitations;
|
import world.bentobox.caveblock.listeners.CustomHeightLimitations;
|
||||||
|
|
||||||
|
|
||||||
@ -163,7 +162,6 @@ public class CaveBlock extends GameModeAddon
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.getServer().getPluginManager().registerEvents(new CustomHeightLimitations(this), this.getPlugin());
|
this.getServer().getPluginManager().registerEvents(new CustomHeightLimitations(this), this.getPlugin());
|
||||||
this.getServer().getPluginManager().registerEvents(new BeaconEnabler(this), this.getPlugin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -798,6 +798,26 @@ public class Settings implements DataObject, WorldSettings
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the islandCommand value.
|
||||||
|
* @return the value of islandCommand.
|
||||||
|
*/
|
||||||
|
public String getIslandCommand()
|
||||||
|
{
|
||||||
|
return islandCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the adminCommand value.
|
||||||
|
* @return the value of adminCommand.
|
||||||
|
*/
|
||||||
|
public String getAdminCommand()
|
||||||
|
{
|
||||||
|
return adminCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Section: Setters
|
// Section: Setters
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
@ -1565,10 +1585,45 @@ public class Settings implements DataObject, WorldSettings
|
|||||||
this.debug = debug;
|
this.debug = debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the islandCommand value.
|
||||||
|
* @param islandCommand the islandCommand new value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setIslandCommand(String islandCommand)
|
||||||
|
{
|
||||||
|
this.islandCommand = islandCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the adminCommand value.
|
||||||
|
* @param adminCommand the adminCommand new value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setAdminCommand(String adminCommand)
|
||||||
|
{
|
||||||
|
this.adminCommand = adminCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Section: Variables
|
// Section: Variables
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/* Commands */
|
||||||
|
@ConfigComment("Cave Command. What command users will run to access their cave.")
|
||||||
|
@ConfigComment("To define alias, just separate commands with white space.")
|
||||||
|
@ConfigEntry(path = "cave.command.island")
|
||||||
|
private String islandCommand = "cave cb";
|
||||||
|
|
||||||
|
@ConfigComment("The Cave admin command.")
|
||||||
|
@ConfigComment("To define alias, just separate commands with white space.")
|
||||||
|
@ConfigEntry(path = "cave.command.admin")
|
||||||
|
private String adminCommand = "cbadmin cba";
|
||||||
|
|
||||||
/* WORLD */
|
/* WORLD */
|
||||||
@ConfigComment("Friendly name for this world. Used in admin commands. Must be a single word")
|
@ConfigComment("Friendly name for this world. Used in admin commands. Must be a single word")
|
||||||
@ConfigEntry(path = "world.friendly-name")
|
@ConfigEntry(path = "world.friendly-name")
|
||||||
|
@ -21,7 +21,9 @@ import world.bentobox.caveblock.CaveBlock;
|
|||||||
public class AdminCommand extends CompositeCommand {
|
public class AdminCommand extends CompositeCommand {
|
||||||
|
|
||||||
public AdminCommand(CaveBlock addon) {
|
public AdminCommand(CaveBlock addon) {
|
||||||
super(addon, "cbadmin", "cba");
|
super(addon,
|
||||||
|
addon.getSettings().getAdminCommand().split(" ")[0],
|
||||||
|
addon.getSettings().getAdminCommand().split(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -62,6 +64,12 @@ public class AdminCommand extends CompositeCommand {
|
|||||||
new AdminReloadCommand(this);
|
new AdminReloadCommand(this);
|
||||||
// Spawn
|
// Spawn
|
||||||
new AdminSetspawnCommand(this);
|
new AdminSetspawnCommand(this);
|
||||||
|
// Reset flags
|
||||||
|
new AdminResetFlagsCommand(this);
|
||||||
|
// Trash
|
||||||
|
new AdminTrashCommand(this);
|
||||||
|
new AdminEmptyTrashCommand(this);
|
||||||
|
new AdminSwitchtoCommand(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,7 +15,9 @@ import world.bentobox.caveblock.CaveBlock;
|
|||||||
public class IslandCommand extends CompositeCommand {
|
public class IslandCommand extends CompositeCommand {
|
||||||
|
|
||||||
public IslandCommand(CaveBlock addon) {
|
public IslandCommand(CaveBlock addon) {
|
||||||
super(addon, "cave", "cb");
|
super(addon,
|
||||||
|
addon.getSettings().getIslandCommand().split(" ")[0],
|
||||||
|
addon.getSettings().getIslandCommand().split(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
@ -1,203 +0,0 @@
|
|||||||
package world.bentobox.caveblock.listeners;
|
|
||||||
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
|
||||||
import org.bukkit.event.block.BlockDamageEvent;
|
|
||||||
import org.bukkit.event.block.BlockExplodeEvent;
|
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
|
||||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
|
||||||
|
|
||||||
import world.bentobox.bentobox.util.Util;
|
|
||||||
import world.bentobox.caveblock.CaveBlock;
|
|
||||||
import world.bentobox.caveblock.Settings;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class allows to enable beacon in CaveBlock, if cave roof is made of bedrock.
|
|
||||||
* It will replace Bedrock with black glass.
|
|
||||||
*/
|
|
||||||
public class BeaconEnabler implements Listener
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Constructor BeaconEnabler creates a new BeaconEnabler instance.
|
|
||||||
*
|
|
||||||
* @param addon of type CaveBlock
|
|
||||||
*/
|
|
||||||
public BeaconEnabler(CaveBlock addon)
|
|
||||||
{
|
|
||||||
this.addon = addon;
|
|
||||||
this.settings = addon.getSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method onBlockPlacement detects if beacon is placed and replace roof bedrock with black glass.
|
|
||||||
*
|
|
||||||
* @param event of type BlockPlaceEvent
|
|
||||||
*/
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void onBlockPlacement(BlockPlaceEvent event)
|
|
||||||
{
|
|
||||||
World world = event.getPlayer().getWorld();
|
|
||||||
|
|
||||||
if (!Util.sameWorld(this.addon.getOverWorld(), world) ||
|
|
||||||
!this.settings.isBeaconAllowed() ||
|
|
||||||
!this.isRoofEnabled(world) ||
|
|
||||||
!event.getBlock().getType().equals(Material.BEACON))
|
|
||||||
{
|
|
||||||
// This should work only if it is cave block world or world has roof from bedrock. Otherwise,
|
|
||||||
// players can dig till top themself.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Block roofBlock = world.getBlockAt(event.getBlock().getX(), this.settings.getWorldDepth() - 1, event.getBlock().getZ());
|
|
||||||
|
|
||||||
if (roofBlock.getType().equals(Material.BEDROCK))
|
|
||||||
{
|
|
||||||
// Replace only bedrock.
|
|
||||||
roofBlock.setType(Material.BLACK_STAINED_GLASS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method onBlockBreak detects if beacon is destroyed and replace roof black glass with bedrock.
|
|
||||||
*
|
|
||||||
* @param event of type BlockBreakEvent
|
|
||||||
*/
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void onBlockBreak(BlockBreakEvent event)
|
|
||||||
{
|
|
||||||
World world = event.getPlayer().getWorld();
|
|
||||||
|
|
||||||
if (!Util.sameWorld(this.addon.getOverWorld(), world) ||
|
|
||||||
!this.isRoofEnabled(world) ||
|
|
||||||
!this.settings.isBeaconAllowed() ||
|
|
||||||
!event.getBlock().getType().equals(Material.BEACON))
|
|
||||||
{
|
|
||||||
// This should work only if it is cave block world or world has roof from bedrock.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block roofBlock = world.getBlockAt(event.getBlock().getX(), this.settings.getWorldDepth() - 1, event.getBlock().getZ());
|
|
||||||
|
|
||||||
if (roofBlock.getType().equals(Material.BLACK_STAINED_GLASS))
|
|
||||||
{
|
|
||||||
// Replace only black glass.
|
|
||||||
roofBlock.setType(Material.BEDROCK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method onBlockDamage detects if user tries to destroy black glass on roof and disable it.
|
|
||||||
*
|
|
||||||
* @param event of type BlockDamageEvent
|
|
||||||
*/
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void onBlockDamage(BlockDamageEvent event)
|
|
||||||
{
|
|
||||||
World world = event.getPlayer().getWorld();
|
|
||||||
|
|
||||||
if (!Util.sameWorld(this.addon.getOverWorld(), world) ||
|
|
||||||
!this.isRoofEnabled(world) ||
|
|
||||||
!this.settings.isBeaconAllowed() ||
|
|
||||||
event.getBlock().getY() != this.settings.getWorldDepth() - 1)
|
|
||||||
{
|
|
||||||
// This should work only if it is cave block world or world has roof from bedrock.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel break event if it is black glass.
|
|
||||||
event.setCancelled(event.getBlock().getType().equals(Material.BLACK_STAINED_GLASS));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method onBlockExplode detects if explosion tries to destroy black glass on roof and disable it.
|
|
||||||
*
|
|
||||||
* @param event of type BlockExplodeEvent
|
|
||||||
*/
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void onBlockExplode(BlockExplodeEvent event)
|
|
||||||
{
|
|
||||||
World world = event.getBlock().getWorld();
|
|
||||||
|
|
||||||
if (!Util.sameWorld(this.addon.getOverWorld(), world) ||
|
|
||||||
!this.isRoofEnabled(world) ||
|
|
||||||
!this.settings.isBeaconAllowed() ||
|
|
||||||
event.getBlock().getY() < this.settings.getWorldDepth() - 9)
|
|
||||||
{
|
|
||||||
// This should work only if it is cave block world or world has roof from bedrock.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int blockY = this.settings.getWorldDepth() - 1;
|
|
||||||
|
|
||||||
// Remove all black stained glass from explosion block list if it is on the roof.
|
|
||||||
event.blockList().removeIf(block ->
|
|
||||||
block.getY() == blockY && block.getType().equals(Material.BLACK_STAINED_GLASS));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method onEntityExplode detects if explosion tries to destroy black glass on roof and disable it.
|
|
||||||
*
|
|
||||||
* @param event of type EntityExplodeEvent
|
|
||||||
*/
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void onEntityExplode(EntityExplodeEvent event)
|
|
||||||
{
|
|
||||||
World world = event.getLocation().getWorld();
|
|
||||||
|
|
||||||
if (!Util.sameWorld(this.addon.getOverWorld(), world) ||
|
|
||||||
!this.isRoofEnabled(world) ||
|
|
||||||
!this.settings.isBeaconAllowed() ||
|
|
||||||
event.getLocation().getY() < this.settings.getWorldDepth() - 9)
|
|
||||||
{
|
|
||||||
// This should work only if it is cave block world or world has roof from bedrock.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int blockY = this.settings.getWorldDepth() - 1;
|
|
||||||
|
|
||||||
// Remove all black stained glass from explosion block list if it is on the roof.
|
|
||||||
event.blockList().removeIf(block ->
|
|
||||||
block.getY() == blockY && block.getType().equals(Material.BLACK_STAINED_GLASS));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method checks if in given world bedrock roof is enabled.
|
|
||||||
* @param world World that must be checked.
|
|
||||||
* @return <code>true</code> - bedrock roof is enabled, otherwise <code>false</code>
|
|
||||||
*/
|
|
||||||
private boolean isRoofEnabled(World world)
|
|
||||||
{
|
|
||||||
return world.getEnvironment().equals(World.Environment.NORMAL) && this.settings.isNormalRoof() ||
|
|
||||||
world.getEnvironment().equals(World.Environment.NETHER) && this.settings.isNetherRoof() ||
|
|
||||||
world.getEnvironment().equals(World.Environment.THE_END) && this.settings.isEndRoof();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// Section: Variables
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CaveBlock addon.
|
|
||||||
*/
|
|
||||||
private CaveBlock addon;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Addon settings.
|
|
||||||
*/
|
|
||||||
private Settings settings;
|
|
||||||
}
|
|
@ -2,6 +2,14 @@
|
|||||||
# This config file is dynamic and saved when the server is shutdown.
|
# This config file is dynamic and saved when the server is shutdown.
|
||||||
# If you edit it while the server is running use /cbadmin reload
|
# If you edit it while the server is running use /cbadmin reload
|
||||||
# otherwise your settings will be lost.
|
# otherwise your settings will be lost.
|
||||||
|
caveblock:
|
||||||
|
command:
|
||||||
|
# Cave Command. What command users will run to access their cave.
|
||||||
|
# To define alias, just separate commands with white space.
|
||||||
|
island: cave cb
|
||||||
|
# The Cave admin command.
|
||||||
|
# To define alias, just separate commands with white space.
|
||||||
|
admin: cbadmin cba
|
||||||
world:
|
world:
|
||||||
# Friendly name for this world. Used in admin commands. Must be a single word
|
# Friendly name for this world. Used in admin commands. Must be a single word
|
||||||
friendly-name: CaveBlock
|
friendly-name: CaveBlock
|
||||||
|
Loading…
Reference in New Issue
Block a user