Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,10 @@ public final class SettingKey implements SettingHolder {
public static final RoseSetting<Boolean> SPAWNER_SILK_TOUCH_PROTECT = create("global-spawner-settings.silk-touch-protect", BOOLEAN, false, "Should spawners be protected from being destroyed without silk touch?", "A message will be sent to the player explaining why it cannot be broken");
public static final RoseSetting<Integer> SPAWNER_AUTO_STACK_RANGE = create("global-spawner-settings.auto-stack-range", INTEGER, -1, "How close should spawners have to be placed to auto stack together?", "A value of -1 will disable this setting", "This value is measured in blocks");
public static final RoseSetting<Boolean> SPAWNER_AUTO_STACK_CHUNK = create("global-spawner-settings.auto-stack-chunk", BOOLEAN, false, "Should spawners in the same chunk auto stack together?", "This overrides the auto-stack-range setting");
public static final RoseSetting<Boolean> SPAWNER_AUTO_STACK_PREVENT_SAME_TYPE_IN_RANGE = create("global-spawner-settings.auto-stack-prevent-same-type-in-range", BOOLEAN, false, "Should only one spawner block per mob type be allowed within the auto stack range?", "This will prevent placing spawners within range of another spawner of the same type");
public static final RoseSetting<Boolean> SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE = create("global-spawner-settings.auto-stack-prevent-multiple-in-range", BOOLEAN, false, "Should only one spawner block be allowed within the auto stack range?", "This will prevent placing any spawners within range of another spawner");
public static final RoseSetting<Boolean> SPAWNER_AUTO_STACK_PREVENT_SAME_TYPE_IN_RANGE = create("global-spawner-settings.auto-stack-prevent-same-type-in-range", BOOLEAN, false, "Should only one (by default) spawner block per mob type be allowed within the auto stack range?", "This will prevent placing spawners within range of another spawner of the same type", "See auto-stack-prevent-same-type-in-range-limit to adjust the limit from the default of one");
public static final RoseSetting<Integer> SPAWNER_AUTO_STACK_PREVENT_SAME_TYPE_IN_RANGE_LIMIT = create("global-spawner-settings.auto-stack-prevent-same-type-in-range-limit", INTEGER, 1, "How many spawner blocks of the same mob type should be allowed within the auto stack range?", "Only used when auto-stack-prevent-same-type-in-range is enabled");
public static final RoseSetting<Boolean> SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE = create("global-spawner-settings.auto-stack-prevent-multiple-in-range", BOOLEAN, false, "Should only one (by default) spawner block be allowed within the auto stack range?", "This will prevent placing any spawners within range of another spawner of any type", "See auto-stack-prevent-multiple-in-range-limit to adjust the limit from the default of one");
public static final RoseSetting<Integer> SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE_LIMIT = create("global-spawner-settings.auto-stack-prevent-multiple-in-range-limit", INTEGER, 1, "How many spawner blocks of any mob type should be allowed within the auto stack range?", "Only used when auto-stack-prevent-multiple-in-range is enabled");
public static final RoseSetting<Boolean> SPAWNER_AUTO_STACK_PARTICLES = create("global-spawner-settings.auto-stack-particles", BOOLEAN, true, "Should particles be displayed when auto stacking spawners together?", "Useful for letting the player know where their spawner just went");
public static final RoseSetting<Boolean> SPAWNER_CONVERT_REQUIRE_SAME_AMOUNT = create("global-spawner-settings.convert-require-same-amount", BOOLEAN, false, "Should the same number of spawn eggs as the spawner stack be required for conversion?");
public static final RoseSetting<Boolean> SPAWNER_CONVERT_ONLY_EMPTY = create("global-spawner-settings.convert-only-empty", BOOLEAN, false, "Should only empty spawners be able to be converted with spawn eggs?");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -613,17 +613,19 @@ public void onBlockPlace(BlockPlaceEvent event) {
if (useAutoStack && spawnerType != null) {
boolean preventSameTypeInRange = SettingKey.SPAWNER_AUTO_STACK_PREVENT_SAME_TYPE_IN_RANGE.get();
boolean preventMultipleInRange = SettingKey.SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE.get();
int sameTypeLimit = Math.max(1, SettingKey.SPAWNER_AUTO_STACK_PREVENT_SAME_TYPE_IN_RANGE_LIMIT.get());
int multipleLimit = Math.max(1, SettingKey.SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE_LIMIT.get());

SearchNearbySpawnersResult result = searchNearbySpawners(block, stackAmount, spawnerType, this.stackManager);
SearchNearbySpawnersResult result = searchNearbySpawners(block, stackAmount, spawnerType, this.stackManager, sameTypeLimit, multipleLimit);

if (result.nearest() != null) {
against = result.nearest().getBlock();
isAdditiveStack = true;
isDistanceStack = true;
} else if (result.spawnerSameType() != null && preventSameTypeInRange) {
} else if (preventSameTypeInRange && result.sameTypeNearbyAmount() >= sameTypeLimit) {
event.setCancelled(true);
return;
} else if (result.anyNearby() && preventMultipleInRange) {
} else if (preventMultipleInRange && result.nearbyAmount() >= multipleLimit) {
event.setCancelled(true);
return;
}
Expand Down Expand Up @@ -923,55 +925,98 @@ private boolean isBlockOrSpawnerStack(Block block) {
return this.stackManager.isBlockStacked(block) || this.stackManager.isSpawnerStacked(block);
}

public static SearchNearbySpawnersResult searchNearbySpawners(Block block, int stackAmount, SpawnerType spawnerType, StackManager stackManager) {
public static SearchNearbySpawnersResult searchNearbySpawners(Block block, int stackAmount, SpawnerType spawnerType, StackManager stackManager, int sameTypeLimit, int multipleLimit) {
int autoStackRange = SettingKey.SPAWNER_AUTO_STACK_RANGE.get();
boolean autoStackChunk = SettingKey.SPAWNER_AUTO_STACK_CHUNK.get();
boolean preventMultipleInRange = SettingKey.SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE.get();

StackedSpawner spawnerSameType = null;
StackedSpawner nearest = null;
boolean anyNearby = false;
int sameTypeNearbyAmount = 0;
int nearbyAmount = 0;
List<StackedSpawner> spawners = new ArrayList<>(stackManager.getStackingThread(block.getWorld()).getStackedSpawners().values());
if (!autoStackChunk) {
double closestDistance = autoStackRange * autoStackRange;
double rangeSquared = autoStackRange * autoStackRange;
double closestDistance = rangeSquared;
for (StackedSpawner spawner : spawners) {
if (spawner.getBlock().equals(block))
continue;

if (!spawner.isPlacedByPlayer())
continue;

double distance = spawner.getLocation().distanceSquared(block.getLocation());
if (distance < closestDistance && spawner.isPlacedByPlayer()) {
boolean sameType = spawner.getSpawnerTile().getSpawnerType().equals(spawnerType);
if (sameType)
spawnerSameType = spawner;
anyNearby |= preventMultipleInRange || sameType;
if (sameType && spawner.getStackSize() + stackAmount <= spawner.getStackSettings().getMaxStackSize()) {
closestDistance = distance;
nearest = spawner;
}
if (distance >= rangeSquared)
continue;

nearbyAmount++;

boolean sameType = spawner.getSpawnerTile().getSpawnerType().equals(spawnerType);
if (sameType) {
spawnerSameType = spawner;
sameTypeNearbyAmount++;
}

if (sameType && distance < closestDistance && spawner.getStackSize() + stackAmount <= spawner.getStackSettings().getMaxStackSize()) {
closestDistance = distance;
nearest = spawner;
}

if (shouldReturnNearbySpawnersResult(block, nearest, sameTypeNearbyAmount, nearbyAmount, sameTypeLimit, multipleLimit)) {
return new SearchNearbySpawnersResult(spawnerSameType, nearest, sameTypeNearbyAmount, nearbyAmount);
}
}
} else {
int blockChunkX = block.getLocation().getBlockX() >> 4;
int blockChunkZ = block.getLocation().getBlockZ() >> 4;
for (StackedSpawner spawner : spawners) {
Block spawnerBlock = spawner.getBlock();
if (spawnerBlock.getX() >> 4 == blockChunkX && spawnerBlock.getZ() >> 4 == blockChunkZ && spawner.isPlacedByPlayer()) {
boolean sameType = spawner.getSpawnerTile().getSpawnerType().equals(spawnerType);
if (sameType)
spawnerSameType = spawner;
anyNearby |= preventMultipleInRange || sameType;
if (sameType && spawner.getStackSize() + stackAmount <= spawner.getStackSettings().getMaxStackSize()) {
nearest = spawner;
break;
}
if (spawnerBlock.equals(block))
continue;

if (!spawner.isPlacedByPlayer())
continue;

if (spawnerBlock.getX() >> 4 != blockChunkX || spawnerBlock.getZ() >> 4 != blockChunkZ)
continue;

nearbyAmount++;

boolean sameType = spawner.getSpawnerTile().getSpawnerType().equals(spawnerType);
if (sameType) {
spawnerSameType = spawner;
sameTypeNearbyAmount++;
}

if (sameType && nearest == null && spawner.getStackSize() + stackAmount <= spawner.getStackSettings().getMaxStackSize()) {
nearest = spawner;
}

if (shouldReturnNearbySpawnersResult(block, nearest, sameTypeNearbyAmount, nearbyAmount, sameTypeLimit, multipleLimit)) {
return new SearchNearbySpawnersResult(spawnerSameType, nearest, sameTypeNearbyAmount, nearbyAmount);
}
}
}

return new SearchNearbySpawnersResult(spawnerSameType, nearest, anyNearby);
return new SearchNearbySpawnersResult(spawnerSameType, nearest, sameTypeNearbyAmount, nearbyAmount);
}

private static boolean shouldReturnNearbySpawnersResult(Block block, StackedSpawner nearest, int sameTypeNearbyAmount, int nearbyAmount, int sameTypeLimit, int multipleLimit) {
boolean sameTypeLimitReached = sameTypeLimit > 0 && sameTypeNearbyAmount >= sameTypeLimit;
boolean multipleLimitReached = multipleLimit > 0 && nearbyAmount >= multipleLimit;
if (!sameTypeLimitReached && !multipleLimitReached)
return false;

if (block != null || nearest != null)
return true;

return sameTypeLimitReached;
}

public record SearchNearbySpawnersResult(
StackedSpawner spawnerSameType,
StackedSpawner nearest,
boolean anyNearby
int sameTypeNearbyAmount,
int nearbyAmount
) {}

}
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,17 @@ public void onInteract(PlayerInteractEvent event) {
boolean autoStackChunk = SettingKey.SPAWNER_AUTO_STACK_CHUNK.get();
boolean preventSameTypeInRange = SettingKey.SPAWNER_AUTO_STACK_PREVENT_SAME_TYPE_IN_RANGE.get();
boolean preventMultipleInRange = SettingKey.SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE.get();
int sameTypeLimit = Math.max(1, SettingKey.SPAWNER_AUTO_STACK_PREVENT_SAME_TYPE_IN_RANGE_LIMIT.get());
int multipleLimit = Math.max(1, SettingKey.SPAWNER_AUTO_STACK_PREVENT_MULTIPLE_IN_RANGE_LIMIT.get());
boolean useAutoStack = autoStackRange > 0 || autoStackChunk;
if (useAutoStack && (preventSameTypeInRange || preventMultipleInRange)) { // Prevent converting if another spawner of the same type is nearby
BlockListener.SearchNearbySpawnersResult searchResult = BlockListener.searchNearbySpawners(clickedBlock, 0, newType, stackManager);
BlockListener.SearchNearbySpawnersResult searchResult = BlockListener.searchNearbySpawners(clickedBlock, 0, newType, stackManager, sameTypeLimit, multipleLimit);

if (searchResult.spawnerSameType() != null && preventSameTypeInRange) {
if (preventSameTypeInRange && searchResult.sameTypeNearbyAmount() >= sameTypeLimit) {
event.setCancelled(true);
stackedSpawner.getWorld().spawnParticle(VersionUtils.SMOKE, clickedBlock.getLocation().clone().add(0.5, 0.5, 0.5), 50, 0.5, 0.5, 0.5, 0);
return;
} else if (searchResult.anyNearby() && preventMultipleInRange) {
} else if (preventMultipleInRange && searchResult.nearbyAmount() >= multipleLimit) {
event.setCancelled(true);
stackedSpawner.getWorld().spawnParticle(VersionUtils.SMOKE, clickedBlock.getLocation().clone().add(0.5, 0.5, 0.5), 50, 0.5, 0.5, 0.5, 0);
return;
Expand Down