Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
331efa9ffd | ||
|
|
7424d6b929 | ||
|
|
a18a6b0dca |
No files matched your search
@@ -11,6 +11,7 @@ version '1.0-SNAPSHOT'
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url = 'https://mvn.everbuild.org/public' }
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -38,6 +39,9 @@ dependencies {
|
|||||||
|
|
||||||
//PvP
|
//PvP
|
||||||
implementation 'io.github.togar2:MinestomPvP:2026.05.30-26.1.1'
|
implementation 'io.github.togar2:MinestomPvP:2026.05.30-26.1.1'
|
||||||
|
|
||||||
|
//Block placement
|
||||||
|
implementation 'org.everbuild.blocksandstuff:blocksandstuff-blocks:1.10.2-SNAPSHOT'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
|||||||
+49
-9
@@ -11,8 +11,10 @@ import net.minestom.server.coordinate.Pos;
|
|||||||
import net.minestom.server.entity.GameMode;
|
import net.minestom.server.entity.GameMode;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.player.PlayerBlockBreakEvent;
|
import net.minestom.server.event.player.PlayerBlockBreakEvent;
|
||||||
|
import net.minestom.server.event.player.PlayerBlockInteractEvent;
|
||||||
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
|
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
|
||||||
import net.minestom.server.event.player.PlayerUseItemEvent;
|
import net.minestom.server.event.player.PlayerUseItemEvent;
|
||||||
|
import net.minestom.server.event.player.PlayerUseItemOnBlockEvent;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.item.Material;
|
import net.minestom.server.item.Material;
|
||||||
import net.minestom.server.timer.TaskSchedule;
|
import net.minestom.server.timer.TaskSchedule;
|
||||||
@@ -60,7 +62,12 @@ public class BuildBattle extends StatelessGame {
|
|||||||
super(Dimension.THE_END.key, "BuildBattle", new PointsWinScore());
|
super(Dimension.THE_END.key, "BuildBattle", new PointsWinScore());
|
||||||
this.seconds = seconds;
|
this.seconds = seconds;
|
||||||
this.setGenerator(new BuildBattleChunkgenerator(height));
|
this.setGenerator(new BuildBattleChunkgenerator(height));
|
||||||
|
BuildBattleBlockRules.register();
|
||||||
this.eventNode().addListener(PlayerUseItemEvent.class, this::onRatingItemUse);
|
this.eventNode().addListener(PlayerUseItemEvent.class, this::onRatingItemUse);
|
||||||
|
this.eventNode().addListener(PlayerUseItemOnBlockEvent.class, e -> FluidFlowHelper.onBucketUse(e, p -> this.isInArea(p, e.getPlayer())));
|
||||||
|
this.eventNode().addListener(PlayerBlockInteractEvent.class, e -> {
|
||||||
|
if (this.isInArea(e.getBlockPosition(), e.getPlayer())) BuildBattleBlockRules.onInteract(e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,6 +83,21 @@ public class BuildBattle extends StatelessGame {
|
|||||||
this.getPlayers().forEach(player -> player.setGameMode(GameMode.CREATIVE));
|
this.getPlayers().forEach(player -> player.setGameMode(GameMode.CREATIVE));
|
||||||
|
|
||||||
this.scheduler().scheduleTask(this::endBuildPhase, TaskSchedule.seconds(this.seconds), TaskSchedule.stop());
|
this.scheduler().scheduleTask(this::endBuildPhase, TaskSchedule.seconds(this.seconds), TaskSchedule.stop());
|
||||||
|
this.scheduleCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleCountdown() {
|
||||||
|
int[] marks = {30, 10, 5, 4, 3, 2, 1};
|
||||||
|
for (int m : marks) {
|
||||||
|
if (this.seconds <= m) continue;
|
||||||
|
int remaining = m;
|
||||||
|
this.scheduler().scheduleTask(() -> {
|
||||||
|
NamedTextColor color = remaining <= 5 ? NamedTextColor.RED : (remaining <= 10 ? NamedTextColor.GOLD : NamedTextColor.YELLOW);
|
||||||
|
this.sendMessage(Component.text("Noch ", NamedTextColor.GRAY)
|
||||||
|
.append(Component.text(remaining, color))
|
||||||
|
.append(Component.text(" Sekunde" + (remaining == 1 ? "" : "n") + " Bauzeit!", NamedTextColor.GRAY)));
|
||||||
|
}, TaskSchedule.seconds(this.seconds - m), TaskSchedule.stop());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void endBuildPhase() {
|
private void endBuildPhase() {
|
||||||
@@ -109,12 +131,32 @@ public class BuildBattle extends StatelessGame {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent event) {
|
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent event) {
|
||||||
event.setCancelled(!this.isInArea(event.getBlockPosition(), event.getPlayer()));
|
if (!this.isInArea(event.getBlockPosition(), event.getPlayer())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FluidFlowHelper.onBreak(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent event) {
|
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent event) {
|
||||||
event.setCancelled(!this.isInArea(event.getBlockPosition(), event.getPlayer()));
|
if (!this.isInArea(event.getBlockPosition(), event.getPlayer())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FluidFlowHelper.onPlace(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pos safeSpawn(Player owner) {
|
||||||
|
Pos center = this.spawnPositions.get(owner);
|
||||||
|
int topY = center.blockY();
|
||||||
|
for (int y = 300; y >= center.blockY(); y--) {
|
||||||
|
if (!this.getBlock(center.blockX(), y, center.blockZ()).isAir()) {
|
||||||
|
topY = y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Pos(center.x(), topY + 3, center.z()).withView(center.yaw(), center.pitch());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rating() {
|
private void rating() {
|
||||||
@@ -136,7 +178,7 @@ public class BuildBattle extends StatelessGame {
|
|||||||
this.currentOwner = owner;
|
this.currentOwner = owner;
|
||||||
this.currentVotes.clear();
|
this.currentVotes.clear();
|
||||||
|
|
||||||
Pos plot = this.spawnPositions.get(owner).add(0, 1.5, 0);
|
Pos plot = this.safeSpawn(owner);
|
||||||
this.sendMessage(Component.text("Bewerte das Grundstück von " + owner.getUsername() + "!"));
|
this.sendMessage(Component.text("Bewerte das Grundstück von " + owner.getUsername() + "!"));
|
||||||
this.getPlayers().forEach(p -> {
|
this.getPlayers().forEach(p -> {
|
||||||
p.teleport(plot);
|
p.teleport(plot);
|
||||||
@@ -176,11 +218,9 @@ public class BuildBattle extends StatelessGame {
|
|||||||
|
|
||||||
private boolean isInArea(Point block, Player player) {
|
private boolean isInArea(Point block, Player player) {
|
||||||
Pos center = this.spawnPositions.get(player);
|
Pos center = this.spawnPositions.get(player);
|
||||||
double dx = block.x() - center.x();
|
if (center == null) return false;
|
||||||
double dy = block.y() - center.y();
|
Pos min = new Pos(center.x() - plotHalf, center.y() + 1, center.z() - plotHalf);
|
||||||
double dz = block.z() - center.z();
|
Pos max = new Pos(center.x() + plotHalf - 1, 300, center.z() + plotHalf - 1);
|
||||||
return dx >= -plotHalf && dx < plotHalf
|
return eu.mhsl.minenet.minigames.util.Position.isInArea(block, min, max);
|
||||||
&& dy >= 1 && dy <= 300
|
|
||||||
&& dz >= -plotHalf && dz < plotHalf;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle;
|
||||||
|
|
||||||
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.event.player.PlayerBlockInteractEvent;
|
||||||
|
import net.minestom.server.instance.block.Block;
|
||||||
|
import net.minestom.server.instance.block.BlockHandler;
|
||||||
|
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||||
|
import org.everbuild.blocksandstuff.blocks.group.VanillaBlockBehaviour;
|
||||||
|
import org.everbuild.blocksandstuff.blocks.group.VanillaPlacementRules;
|
||||||
|
import org.everbuild.blocksandstuff.blocks.group.behaviour.BehaviourGroup;
|
||||||
|
import org.everbuild.blocksandstuff.blocks.group.placement.PlacementGroup;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class BuildBattleBlockRules {
|
||||||
|
private BuildBattleBlockRules() {}
|
||||||
|
|
||||||
|
private static final ThreadLocal<Boolean> interactingInBuildBattle = ThreadLocal.withInitial(() -> false);
|
||||||
|
private static final Map<Integer, BlockHandler> behaviours = new HashMap<>();
|
||||||
|
private static boolean registered = false;
|
||||||
|
|
||||||
|
public static synchronized void register() {
|
||||||
|
if (registered) return;
|
||||||
|
registered = true;
|
||||||
|
|
||||||
|
var blockManager = MinecraftServer.getBlockManager();
|
||||||
|
for (PlacementGroup group : VanillaPlacementRules.INSTANCE.getALL()) {
|
||||||
|
for (Block block : group.getBlockGroup().allMatching()) {
|
||||||
|
blockManager.registerBlockPlacementRule(new BuildBattleOnlyRule(group.createRule(block)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BehaviourGroup group : VanillaBlockBehaviour.INSTANCE.getALL()) {
|
||||||
|
for (Block block : group.getBlockGroup().allMatching()) {
|
||||||
|
behaviours.put(block.id(), group.createHandler(block));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MinecraftServer.getGlobalEventHandler().addListener(PlayerBlockInteractEvent.class,
|
||||||
|
e -> interactingInBuildBattle.set(e.getInstance() instanceof BuildBattle));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onInteract(PlayerBlockInteractEvent event) {
|
||||||
|
BlockHandler handler = behaviours.get(event.getBlock().id());
|
||||||
|
if (handler == null) return;
|
||||||
|
boolean continueItemUse = handler.onInteract(new BlockHandler.Interaction(
|
||||||
|
event.getBlock(), event.getInstance(), event.getBlockFace(), event.getBlockPosition(),
|
||||||
|
event.getCursorPosition(), event.getPlayer(), event.getHand()
|
||||||
|
));
|
||||||
|
if (!continueItemUse) event.setBlockingItemUse(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class BuildBattleOnlyRule extends BlockPlacementRule {
|
||||||
|
private final BlockPlacementRule delegate;
|
||||||
|
|
||||||
|
private BuildBattleOnlyRule(BlockPlacementRule delegate) {
|
||||||
|
super(delegate.getBlock());
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Block blockPlace(PlacementState placementState) {
|
||||||
|
if (!(placementState.instance() instanceof BuildBattle)) return placementState.block();
|
||||||
|
return this.delegate.blockPlace(placementState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Block blockUpdate(UpdateState updateState) {
|
||||||
|
if (!(updateState.instance() instanceof BuildBattle)) return updateState.currentBlock();
|
||||||
|
return this.delegate.blockUpdate(updateState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSelfReplaceable(Replacement replacement) {
|
||||||
|
return interactingInBuildBattle.get() && this.delegate.isSelfReplaceable(replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int maxUpdateDistance() {
|
||||||
|
return this.delegate.maxUpdateDistance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+267
@@ -0,0 +1,267 @@
|
|||||||
|
package eu.mhsl.minenet.minigames.instance.game.stateless.types.buildBattle;
|
||||||
|
|
||||||
|
import net.minestom.server.coordinate.BlockVec;
|
||||||
|
import net.minestom.server.coordinate.Point;
|
||||||
|
import net.minestom.server.event.player.PlayerBlockBreakEvent;
|
||||||
|
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
|
||||||
|
import net.minestom.server.event.player.PlayerUseItemOnBlockEvent;
|
||||||
|
import net.minestom.server.instance.Instance;
|
||||||
|
import net.minestom.server.instance.block.Block;
|
||||||
|
import net.minestom.server.item.Material;
|
||||||
|
import net.minestom.server.timer.TaskSchedule;
|
||||||
|
import net.minestom.server.utils.Direction;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public final class FluidFlowHelper {
|
||||||
|
private FluidFlowHelper() {}
|
||||||
|
|
||||||
|
private static final int WATER_TICK = 5;
|
||||||
|
private static final int LAVA_TICK = 30;
|
||||||
|
private static final int WATER_RANGE = 7;
|
||||||
|
private static final int LAVA_RANGE = 3;
|
||||||
|
private static final int FALLING = 8;
|
||||||
|
|
||||||
|
public static void onBucketUse(PlayerUseItemOnBlockEvent event, Predicate<Point> inArea) {
|
||||||
|
Material m = event.getItemStack().material();
|
||||||
|
Instance inst = event.getPlayer().getInstance();
|
||||||
|
if (inst == null) return;
|
||||||
|
Point hit = event.getPosition();
|
||||||
|
var face = event.getBlockFace();
|
||||||
|
BlockVec placePos = new BlockVec(
|
||||||
|
hit.blockX() + face.toDirection().normalX(),
|
||||||
|
hit.blockY() + face.toDirection().normalY(),
|
||||||
|
hit.blockZ() + face.toDirection().normalZ()
|
||||||
|
);
|
||||||
|
if (!inArea.test(placePos)) return;
|
||||||
|
|
||||||
|
if (m == Material.WATER_BUCKET) {
|
||||||
|
inst.setBlock(placePos, Block.WATER.withProperty("level", "0"));
|
||||||
|
scheduleFlow(inst, placePos, true);
|
||||||
|
} else if (m == Material.LAVA_BUCKET) {
|
||||||
|
inst.setBlock(placePos, Block.LAVA.withProperty("level", "0"));
|
||||||
|
scheduleFlow(inst, placePos, false);
|
||||||
|
} else if (m == Material.BUCKET) {
|
||||||
|
Block existing = inst.getBlock(placePos);
|
||||||
|
if (isWater(existing) || isLava(existing)) inst.setBlock(placePos, Block.AIR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onPlace(PlayerBlockPlaceEvent event) {
|
||||||
|
Block b = event.getBlock();
|
||||||
|
if (isWater(b) || isLava(b)) {
|
||||||
|
Instance inst = event.getInstance();
|
||||||
|
BlockVec pos = event.getBlockPosition();
|
||||||
|
scheduleFlow(inst, pos, isWater(b));
|
||||||
|
}
|
||||||
|
triggerNeighbors(event.getInstance(), event.getBlockPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onBreak(PlayerBlockBreakEvent event) {
|
||||||
|
triggerNeighbors(event.getInstance(), event.getBlockPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void triggerNeighbors(Instance inst, BlockVec pos) {
|
||||||
|
for (Direction d : Direction.values()) {
|
||||||
|
BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY() + d.normalY(), pos.blockZ() + d.normalZ());
|
||||||
|
Block nb = inst.getBlock(np);
|
||||||
|
if (isWater(nb) || isLava(nb)) scheduleFlow(inst, np, isWater(nb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void scheduleFlow(Instance inst, BlockVec pos, boolean water) {
|
||||||
|
int delay = water ? WATER_TICK : LAVA_TICK;
|
||||||
|
inst.scheduler().buildTask(() -> step(inst, pos, water)).delay(TaskSchedule.tick(delay)).schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void step(Instance inst, BlockVec pos, boolean water) {
|
||||||
|
Block self = inst.getBlock(pos);
|
||||||
|
if (water ? !isWater(self) : !isLava(self)) return;
|
||||||
|
|
||||||
|
int level = parseLevel(self);
|
||||||
|
boolean source = level == 0;
|
||||||
|
boolean falling = level >= FALLING;
|
||||||
|
int flowLevel = source ? 1 : (falling ? 1 : level + 1);
|
||||||
|
int maxRange = water ? WATER_RANGE : LAVA_RANGE;
|
||||||
|
|
||||||
|
if (!source && !falling) {
|
||||||
|
int newLevel = computeIncomingLevel(inst, pos, water, maxRange);
|
||||||
|
if (newLevel == -1) {
|
||||||
|
inst.setBlock(pos, Block.AIR);
|
||||||
|
triggerNeighbors(inst, pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newLevel != level) {
|
||||||
|
inst.setBlock(pos, (water ? Block.WATER : Block.LAVA).withProperty("level", String.valueOf(newLevel)));
|
||||||
|
level = newLevel;
|
||||||
|
flowLevel = level + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (water && !source && countAdjacentSources(inst, pos, true) >= 2
|
||||||
|
&& hasSolidBelow(inst, pos)) {
|
||||||
|
inst.setBlock(pos, Block.WATER.withProperty("level", "0"));
|
||||||
|
scheduleFlow(inst, pos, true);
|
||||||
|
triggerNeighbors(inst, pos);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockVec below = new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ());
|
||||||
|
Block belowBlock = inst.getBlock(below);
|
||||||
|
if (isReplaceable(belowBlock) || (water ? isWater(belowBlock) : isLava(belowBlock))) {
|
||||||
|
if (handleFluidCollision(inst, below, water)) {
|
||||||
|
triggerNeighbors(inst, below);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Block target = (water ? Block.WATER : Block.LAVA).withProperty("level", String.valueOf(FALLING));
|
||||||
|
if (!belowBlock.compare(target) || !target.getProperty("level").equals(belowBlock.getProperty("level"))) {
|
||||||
|
if (!(isWater(belowBlock) && parseLevel(belowBlock) == 0)
|
||||||
|
&& !(isLava(belowBlock) && parseLevel(belowBlock) == 0)) {
|
||||||
|
inst.setBlock(below, target);
|
||||||
|
scheduleFlow(inst, below, water);
|
||||||
|
triggerNeighbors(inst, below);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasSolidBelow(inst, pos) && !source) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flowLevel > maxRange) return;
|
||||||
|
|
||||||
|
Set<Direction> targets = findFlowTargets(inst, pos, water, maxRange - (source ? 0 : level));
|
||||||
|
for (Direction d : Direction.HORIZONTAL) {
|
||||||
|
if (!targets.contains(d)) continue;
|
||||||
|
BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ());
|
||||||
|
Block nb = inst.getBlock(np);
|
||||||
|
if (handleFluidCollision(inst, np, water)) continue;
|
||||||
|
if (!isReplaceable(nb) && !(water ? isWater(nb) : isLava(nb))) continue;
|
||||||
|
int existingLevel = (water ? isWater(nb) : isLava(nb)) ? parseLevel(nb) : Integer.MAX_VALUE;
|
||||||
|
if (existingLevel == 0) continue;
|
||||||
|
if (flowLevel < existingLevel) {
|
||||||
|
inst.setBlock(np, (water ? Block.WATER : Block.LAVA).withProperty("level", String.valueOf(flowLevel)));
|
||||||
|
scheduleFlow(inst, np, water);
|
||||||
|
triggerNeighbors(inst, np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int computeIncomingLevel(Instance inst, BlockVec pos, boolean water, int maxRange) {
|
||||||
|
int min = Integer.MAX_VALUE;
|
||||||
|
BlockVec above = new BlockVec(pos.blockX(), pos.blockY() + 1, pos.blockZ());
|
||||||
|
Block ab = inst.getBlock(above);
|
||||||
|
if ((water ? isWater(ab) : isLava(ab))) return FALLING;
|
||||||
|
for (Direction d : Direction.HORIZONTAL) {
|
||||||
|
BlockVec np = new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ());
|
||||||
|
Block nb = inst.getBlock(np);
|
||||||
|
if (water ? isWater(nb) : isLava(nb)) {
|
||||||
|
int nl = parseLevel(nb);
|
||||||
|
if (nl >= FALLING) nl = 0;
|
||||||
|
if (nl < min) min = nl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (min == Integer.MAX_VALUE) return -1;
|
||||||
|
int result = min + 1;
|
||||||
|
if (result > maxRange) return -1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<Direction> findFlowTargets(Instance inst, BlockVec pos, boolean water, int remaining) {
|
||||||
|
Set<Direction> result = new HashSet<>();
|
||||||
|
if (remaining <= 0) return result;
|
||||||
|
int bestDist = Integer.MAX_VALUE;
|
||||||
|
int[] dist = new int[4];
|
||||||
|
Direction[] dirs = {Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST};
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
BlockVec np = new BlockVec(pos.blockX() + dirs[i].normalX(), pos.blockY(), pos.blockZ() + dirs[i].normalZ());
|
||||||
|
Block nb = inst.getBlock(np);
|
||||||
|
if (!isReplaceable(nb) && !(water ? isWater(nb) : isLava(nb))) { dist[i] = Integer.MAX_VALUE; continue; }
|
||||||
|
dist[i] = bfsDownhill(inst, np, water, remaining);
|
||||||
|
if (dist[i] < bestDist) bestDist = dist[i];
|
||||||
|
}
|
||||||
|
if (bestDist == Integer.MAX_VALUE) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (dist[i] < Integer.MAX_VALUE) result.add(dirs[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (dist[i] == bestDist) result.add(dirs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int bfsDownhill(Instance inst, BlockVec start, boolean water, int remaining) {
|
||||||
|
ArrayDeque<int[]> queue = new ArrayDeque<>();
|
||||||
|
Set<Long> visited = new HashSet<>();
|
||||||
|
queue.add(new int[]{start.blockX(), start.blockY(), start.blockZ(), 0});
|
||||||
|
visited.add(key(start.blockX(), start.blockY(), start.blockZ()));
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
int[] c = queue.poll();
|
||||||
|
BlockVec cp = new BlockVec(c[0], c[1], c[2]);
|
||||||
|
Block below = inst.getBlock(new BlockVec(c[0], c[1] - 1, c[2]));
|
||||||
|
if (isReplaceable(below) && !(water ? isWater(below) : isLava(below))) return c[3];
|
||||||
|
if (c[3] >= remaining) continue;
|
||||||
|
for (Direction d : Direction.HORIZONTAL) {
|
||||||
|
int nx = c[0] + d.normalX(), nz = c[2] + d.normalZ();
|
||||||
|
long k = key(nx, c[1], nz);
|
||||||
|
if (visited.contains(k)) continue;
|
||||||
|
Block nb = inst.getBlock(new BlockVec(nx, c[1], nz));
|
||||||
|
if (!isReplaceable(nb) && !(water ? isWater(nb) : isLava(nb))) continue;
|
||||||
|
visited.add(k);
|
||||||
|
queue.add(new int[]{nx, c[1], nz, c[3] + 1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long key(int x, int y, int z) {
|
||||||
|
return ((long) x & 0x3FFFFFFL) | (((long) z & 0x3FFFFFFL) << 26) | (((long) y & 0xFFFL) << 52);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countAdjacentSources(Instance inst, BlockVec pos, boolean water) {
|
||||||
|
int c = 0;
|
||||||
|
for (Direction d : Direction.HORIZONTAL) {
|
||||||
|
Block nb = inst.getBlock(new BlockVec(pos.blockX() + d.normalX(), pos.blockY(), pos.blockZ() + d.normalZ()));
|
||||||
|
if ((water ? isWater(nb) : isLava(nb)) && parseLevel(nb) == 0) c++;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasSolidBelow(Instance inst, BlockVec pos) {
|
||||||
|
Block below = inst.getBlock(new BlockVec(pos.blockX(), pos.blockY() - 1, pos.blockZ()));
|
||||||
|
return below.isSolid();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean handleFluidCollision(Instance inst, BlockVec pos, boolean incomingIsWater) {
|
||||||
|
Block target = inst.getBlock(pos);
|
||||||
|
if (incomingIsWater && isLava(target)) {
|
||||||
|
boolean lavaSource = parseLevel(target) == 0;
|
||||||
|
inst.setBlock(pos, lavaSource ? Block.OBSIDIAN : Block.COBBLESTONE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!incomingIsWater && isWater(target)) {
|
||||||
|
inst.setBlock(pos, Block.STONE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isReplaceable(Block b) {
|
||||||
|
if (b.isAir()) return true;
|
||||||
|
String p = b.key().value();
|
||||||
|
return p.equals("short_grass") || p.equals("tall_grass") || p.equals("fern") || p.equals("large_fern")
|
||||||
|
|| p.equals("dead_bush") || p.equals("seagrass") || p.equals("tall_seagrass") || p.equals("vine")
|
||||||
|
|| p.equals("snow") || p.equals("fire") || p.equals("soul_fire");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isWater(Block b) { return b.compare(Block.WATER); }
|
||||||
|
private static boolean isLava(Block b) { return b.compare(Block.LAVA); }
|
||||||
|
|
||||||
|
private static int parseLevel(Block b) {
|
||||||
|
String s = b.getProperty("level");
|
||||||
|
if (s == null) return 0;
|
||||||
|
try { return Integer.parseInt(s); } catch (NumberFormatException e) { return 0; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-13
@@ -9,7 +9,6 @@ import io.github.togar2.pvp.events.FinalAttackEvent;
|
|||||||
import io.github.togar2.pvp.events.PrepareAttackEvent;
|
import io.github.togar2.pvp.events.PrepareAttackEvent;
|
||||||
import io.github.togar2.pvp.feature.CombatFeatures;
|
import io.github.togar2.pvp.feature.CombatFeatures;
|
||||||
import io.github.togar2.pvp.feature.knockback.KnockbackSettings;
|
import io.github.togar2.pvp.feature.knockback.KnockbackSettings;
|
||||||
import net.minestom.server.ServerFlag;
|
|
||||||
import net.minestom.server.coordinate.Pos;
|
import net.minestom.server.coordinate.Pos;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.instance.InstanceTickEvent;
|
import net.minestom.server.event.instance.InstanceTickEvent;
|
||||||
@@ -52,18 +51,15 @@ class HighGround extends StatelessGame {
|
|||||||
|
|
||||||
this.eventNode().addListener(
|
this.eventNode().addListener(
|
||||||
EntityKnockbackEvent.class,
|
EntityKnockbackEvent.class,
|
||||||
entityKnockbackEvent -> {
|
entityKnockbackEvent -> entityKnockbackEvent.setSettings(
|
||||||
double tps = ServerFlag.SERVER_TICKS_PER_SECOND;
|
KnockbackSettings.builder()
|
||||||
entityKnockbackEvent.setSettings(
|
.horizontal(1.1)
|
||||||
KnockbackSettings.builder()
|
.vertical(KnockbackSettings.DEFAULT.vertical())
|
||||||
.horizontal(1.1)
|
.verticalLimit(KnockbackSettings.DEFAULT.verticalLimit())
|
||||||
.vertical(KnockbackSettings.DEFAULT.vertical() / tps)
|
.extraHorizontal(KnockbackSettings.DEFAULT.extraHorizontal())
|
||||||
.verticalLimit(KnockbackSettings.DEFAULT.verticalLimit() / tps)
|
.extraVertical(KnockbackSettings.DEFAULT.extraVertical())
|
||||||
.extraHorizontal(KnockbackSettings.DEFAULT.extraHorizontal() / tps)
|
.build()
|
||||||
.extraVertical(KnockbackSettings.DEFAULT.extraVertical() / tps)
|
)
|
||||||
.build()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.eventNode().addListener(InstanceTickEvent.class, instanceTickEvent -> {
|
this.eventNode().addListener(InstanceTickEvent.class, instanceTickEvent -> {
|
||||||
|
|||||||
+2
-1
@@ -147,10 +147,10 @@ class Tetris extends StatelessGame {
|
|||||||
|
|
||||||
TetrisGame tetrisGame = this.tetrisGames.get(p);
|
TetrisGame tetrisGame = this.tetrisGames.get(p);
|
||||||
|
|
||||||
|
p.teleport(tetrisGame.getPlayerSpawnPosition());
|
||||||
tetrisGame.sidebar.addViewer(p);
|
tetrisGame.sidebar.addViewer(p);
|
||||||
|
|
||||||
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
||||||
p.teleport(tetrisGame.getPlayerSpawnPosition());
|
|
||||||
Entity ghostBlock = new Entity(EntityType.BLOCK_DISPLAY);
|
Entity ghostBlock = new Entity(EntityType.BLOCK_DISPLAY);
|
||||||
((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(Block.AIR);
|
((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(Block.AIR);
|
||||||
ghostBlock.setNoGravity(true);
|
ghostBlock.setNoGravity(true);
|
||||||
@@ -159,6 +159,7 @@ class Tetris extends StatelessGame {
|
|||||||
return TaskSchedule.stop();
|
return TaskSchedule.stop();
|
||||||
}, TaskSchedule.nextTick());
|
}, TaskSchedule.nextTick());
|
||||||
|
|
||||||
|
|
||||||
return super.onPlayerJoin(p);
|
return super.onPlayerJoin(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -92,7 +92,7 @@ public class TetrisGame {
|
|||||||
int standardTickDelay = 40;
|
int standardTickDelay = 40;
|
||||||
if(this.isFast) standardTickDelay = 20;
|
if(this.isFast) standardTickDelay = 20;
|
||||||
|
|
||||||
TaskSchedule nextTick = TaskSchedule.tick(Math.max(Math.round((float) standardTickDelay / this.level), 1));
|
TaskSchedule nextTick = TaskSchedule.tick(Math.round((float) standardTickDelay / this.level));
|
||||||
if(this.paused) return nextTick;
|
if(this.paused) return nextTick;
|
||||||
this.tick();
|
this.tick();
|
||||||
return nextTick;
|
return nextTick;
|
||||||
|
|||||||
@@ -44,4 +44,17 @@ public class Position {
|
|||||||
public static boolean hasPositionChanged(Pos oldPos, Pos newPos) {
|
public static boolean hasPositionChanged(Pos oldPos, Pos newPos) {
|
||||||
return !oldPos.withView(0, 0).equals(newPos.withView(0, 0));
|
return !oldPos.withView(0, 0).equals(newPos.withView(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isInArea(Point point, Point pos1, Point pos2) {
|
||||||
|
double minX = Math.min(pos1.x(), pos2.x());
|
||||||
|
double maxX = Math.max(pos1.x(), pos2.x());
|
||||||
|
double minY = Math.min(pos1.y(), pos2.y());
|
||||||
|
double maxY = Math.max(pos1.y(), pos2.y());
|
||||||
|
double minZ = Math.min(pos1.z(), pos2.z());
|
||||||
|
double maxZ = Math.max(pos1.z(), pos2.z());
|
||||||
|
|
||||||
|
return point.x() >= minX && point.x() <= maxX
|
||||||
|
&& point.y() >= minY && point.y() <= maxY
|
||||||
|
&& point.z() >= minZ && point.z() <= maxZ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user