mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-02 14:38:26 +01:00
hollow-cube/placement-rule-improvement
* improve placement rule api and remove existing vanilla rules * readme changes
This commit is contained in:
parent
197371a35e
commit
b0b640ccd7
36
.github/README.md
vendored
36
.github/README.md
vendored
@ -3,9 +3,9 @@
|
||||
|
||||
# Minestom
|
||||
|
||||
[![license](https://img.shields.io/github/license/Minestom/Minestom?style=for-the-badge&color=b2204c)](../LICENSE)
|
||||
[![license](https://img.shields.io/github/license/hollow-cube/minestom-ce?style=for-the-badge&color=b2204c)](../LICENSE)
|
||||
[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=for-the-badge)](https://github.com/RichardLitt/standard-readme)
|
||||
[![javadocs](https://img.shields.io/badge/documentation-javadocs-4d7a97?style=for-the-badge)](https://minestom.github.io/Minestom/)
|
||||
[![javadocs](https://img.shields.io/badge/documentation-javadocs-4d7a97?style=for-the-badge)](https://javadoc.minestom.net)
|
||||
[![wiki](https://img.shields.io/badge/documentation-wiki-74aad6?style=for-the-badge)](https://wiki.minestom.net/)
|
||||
[![discord-banner](https://img.shields.io/discord/706185253441634317?label=discord&style=for-the-badge&color=7289da)](https://discord.gg/pkFRvqB)
|
||||
|
||||
@ -16,6 +16,10 @@ However, we have a complete API which is designed to allow you to make anything
|
||||
|
||||
This is a developer API not meant to be used by end-users. Replacing Bukkit/Forge/Sponge with this **will not work** since we do not implement any of their APIs.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> `minestom-ce` is a fork with breaking changes from `Minestom/Minestom`. The list of changes can be found [here](/CHANGELOG.md).
|
||||
|
||||
# Table of contents
|
||||
- [Install](#install)
|
||||
- [Usage](#usage)
|
||||
@ -31,16 +35,34 @@ Minestom is not installed like Bukkit/Forge/Sponge.
|
||||
As Minestom is a Java library, it must be loaded the same way any other Java library may be loaded.
|
||||
This means you need to add Minestom as a dependency, add your code and compile by yourself.
|
||||
|
||||
For adding the required repositories and dependencies, [check this out](https://wiki.minestom.net/setup/dependencies)
|
||||
`minestom-ce` is available on [Maven Central](https://central.sonatype.com/artifact/dev.hollowcube/minestom-ce),
|
||||
and can be installed like the following (Gradle/Groovy):
|
||||
|
||||
The newest version can be found [here: ![](https://jitpack.io/v/Minestom/Minestom.svg)](https://jitpack.io/#Minestom/Minestom)
|
||||
```groovy
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
> Our own WIP implementation for Vanilla can be found [here](https://github.com/Minestom/VanillaReimplementation).
|
||||
dependencies {
|
||||
implementation 'dev.hollowcube:minestom-ce:<first 10 chars of commit hash>'
|
||||
}
|
||||
```
|
||||
|
||||
# Usage
|
||||
An example of how to use the Minestom library is available [here](/demo).
|
||||
Alternatively you can check the official [wiki](https://wiki.minestom.net/) or the [javadocs](https://minestom.github.io/Minestom/).
|
||||
|
||||
# What is `minestom-ce`?
|
||||
`minestom-ce` is a fork of `Minestom/Minestom` with some controversial/breaking changes. It was originally started as @mworzala's
|
||||
personal fork for making changes, but has since been used by a number of others and aims to be relatively stable. The high
|
||||
level goal of many changes are to make Minestom more of a library and less of a server implementation. For example:
|
||||
* Removing extensions
|
||||
* Removing logging & terminal implementations
|
||||
|
||||
The name "community edition" is not a reflection of an intentional rift between the two projects, it was just a joke between
|
||||
a few people that stuck. I (@mworzala) am very happy for changes in `minestom-ce` to be merged back to `Minestom/Minestom`, I
|
||||
just do not necessarily have the time to do so myself.
|
||||
|
||||
# Why Minestom?
|
||||
Minecraft has evolved a lot since its release, most of the servers today do not take advantage of vanilla features and even have to struggle because of them.
|
||||
Our target audience is those who want to make a server that benefits little from vanilla features. e.g. creative, kitpvp.
|
||||
@ -90,7 +112,7 @@ It is a field where Minecraft evolved a lot, inventories are now used a lot as c
|
||||
Commands are the simplest way of communication between clients and server. Since 1.13 Minecraft has incorporated a new library denominated "Brigadier", we then integrated an API designed to use the full potential of args types.
|
||||
|
||||
# Credits
|
||||
* The [contributors](https://github.com/Minestom/Minestom/graphs/contributors) of the project
|
||||
* The [contributors](https://github.com/hollow-cube/minestom-ce/graphs/contributors) of the project
|
||||
* [The Minecraft Coalition](https://wiki.vg/) and [`#mcdevs`](https://github.com/mcdevs) -
|
||||
protocol and file formats research.
|
||||
* [The Minecraft Wiki](https://minecraft.gamepedia.com/Minecraft_Wiki) for all their useful info
|
||||
@ -102,5 +124,3 @@ All WIP features are previewed as Draft PRs
|
||||
|
||||
# License
|
||||
This project is licensed under the [Apache License Version 2.0](../LICENSE).
|
||||
|
||||
|
||||
|
@ -4,14 +4,13 @@ Some of these are pending, some deserve PRs, others are just minor tweaks
|
||||
|
||||
* **breaking** Delete extensions (`mworzala/Minestom` @ `no_more_extensions`)
|
||||
* **breaking** Block face in digging events (`mworzala/Minestom` @ `block_break_face`)
|
||||
* **breaking** Add cursor position to block place and neighbor updates (`Moulberry/Minestom` @ `block_placement_rewrite_2`)
|
||||
* Change `Entity#getInstance` to @UnknownNullability
|
||||
* Support custom component translator for serverside translation
|
||||
* **breaking** Replace permission system with a simple user pluggable alternative
|
||||
* **breaking** Remove tinylog and MinestomTerminal implementation
|
||||
* Add `Tag.Transient`
|
||||
* Optionally allow multiple parents in event nodes
|
||||
* **breaking** Add sender to argument parsing chain
|
||||
* This allows for argument parsing based on the sender, such as in argument map. This was already present for suggestions, but not for parsing.
|
||||
* This is a breaking change because it changes the signature of `Argument#parse`, but most use cases should not be affected.
|
||||
Support has been maintained for the old argument map signature, so only completely custom arguments will be affected.
|
||||
Support has been maintained for the old argument map signature, so only completely custom arguments will be affected.
|
||||
* **breaking** [Placement rule api changes](https://github.com/hollow-cube/minestom-ce/pull/20)
|
||||
|
@ -13,7 +13,6 @@ import net.minestom.server.extras.lan.OpenToLAN;
|
||||
import net.minestom.server.extras.lan.OpenToLANConfig;
|
||||
import net.minestom.server.extras.optifine.OptifineSupport;
|
||||
import net.minestom.server.instance.block.BlockManager;
|
||||
import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule;
|
||||
import net.minestom.server.ping.ResponseData;
|
||||
import net.minestom.server.utils.identity.NamedAndIdentified;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
@ -27,8 +26,6 @@ public class Main {
|
||||
|
||||
BlockManager blockManager = MinecraftServer.getBlockManager();
|
||||
|
||||
blockManager.registerBlockPlacementRule(new RedstonePlacementRule());
|
||||
|
||||
CommandManager commandManager = MinecraftServer.getCommandManager();
|
||||
commandManager.register(new TestCommand());
|
||||
commandManager.register(new EntitySelectorCommand());
|
||||
|
@ -1,54 +0,0 @@
|
||||
package net.minestom.server.extras;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockManager;
|
||||
import net.minestom.server.instance.block.rule.vanilla.AxisPlacementRule;
|
||||
import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule;
|
||||
import net.minestom.server.instance.block.rule.vanilla.WallPlacementRule;
|
||||
|
||||
public final class PlacementRules {
|
||||
|
||||
public static void init() {
|
||||
BlockManager blockManager = MinecraftServer.getBlockManager();
|
||||
blockManager.registerBlockPlacementRule(new RedstonePlacementRule());
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.BONE_BLOCK));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.HAY_BLOCK));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.OAK_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.SPRUCE_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.BIRCH_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.JUNGLE_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.ACACIA_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.DARK_OAK_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.CRIMSON_STEM));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.WARPED_STEM));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_OAK_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_SPRUCE_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_BIRCH_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_JUNGLE_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_ACACIA_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_DARK_OAK_LOG));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_CRIMSON_STEM));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_WARPED_STEM));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.PURPUR_PILLAR));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.QUARTZ_PILLAR));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.OAK_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.SPRUCE_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.BIRCH_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.JUNGLE_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.ACACIA_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.DARK_OAK_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.CRIMSON_STEM));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.WARPED_STEM));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_OAK_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_SPRUCE_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_BIRCH_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_JUNGLE_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_ACACIA_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_DARK_OAK_WOOD));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_CRIMSON_STEM));
|
||||
blockManager.registerBlockPlacementRule(new AxisPlacementRule(Block.STRIPPED_WARPED_STEM));
|
||||
blockManager.registerBlockPlacementRule(new WallPlacementRule(Block.COBBLESTONE_WALL));
|
||||
blockManager.registerBlockPlacementRule(new WallPlacementRule(Block.MOSSY_COBBLESTONE_WALL));
|
||||
}
|
||||
}
|
@ -131,7 +131,7 @@ public class InstanceContainer extends Instance {
|
||||
// Change id based on neighbors
|
||||
final BlockPlacementRule blockPlacementRule = MinecraftServer.getBlockManager().getBlockPlacementRule(block);
|
||||
if (blockPlacementRule != null) {
|
||||
block = blockPlacementRule.blockUpdate(this, blockPosition, block);
|
||||
block = blockPlacementRule.blockUpdate(new BlockPlacementRule.UpdateState(this, blockPosition, block));
|
||||
}
|
||||
|
||||
// Set the block
|
||||
@ -614,8 +614,8 @@ public class InstanceContainer extends Instance {
|
||||
if (neighborBlockPlacementRule == null) continue;
|
||||
|
||||
final Vec neighborPosition = new Vec(neighborX, neighborY, neighborZ);
|
||||
final Block newNeighborBlock = neighborBlockPlacementRule.blockUpdate(this,
|
||||
neighborPosition, neighborBlock);
|
||||
final Block newNeighborBlock = neighborBlockPlacementRule.blockUpdate(new BlockPlacementRule.UpdateState(this,
|
||||
neighborPosition, neighborBlock));
|
||||
if (neighborBlock != newNeighborBlock) {
|
||||
setBlock(neighborPosition, newNeighborBlock);
|
||||
}
|
||||
|
@ -32,4 +32,32 @@ public enum BlockFace {
|
||||
case EAST -> WEST;
|
||||
};
|
||||
}
|
||||
|
||||
public boolean isSimilar(@NotNull BlockFace other) {
|
||||
return this == other || this == other.getOppositeFace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the horizontal BlockFace from the given yaw angle
|
||||
*
|
||||
* @param yaw the yaw angle
|
||||
* @return a horizontal BlockFace
|
||||
*/
|
||||
public static BlockFace fromYaw(float yaw) {
|
||||
float degrees = (yaw - 90) % 360;
|
||||
if (degrees < 0) {
|
||||
degrees += 360;
|
||||
}
|
||||
if (0 <= degrees && degrees < 45) {
|
||||
return BlockFace.WEST;
|
||||
} else if (45 <= degrees && degrees < 135) {
|
||||
return BlockFace.NORTH;
|
||||
} else if (135 <= degrees && degrees < 225) {
|
||||
return BlockFace.EAST;
|
||||
} else if (225 <= degrees && degrees < 315) {
|
||||
return BlockFace.SOUTH;
|
||||
} else { // 315 <= degrees && degrees < 360
|
||||
return BlockFace.WEST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,63 @@
|
||||
package net.minestom.server.instance.block.rule;
|
||||
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockFace;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.item.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class BlockPlacementRule {
|
||||
private final Block block;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public BlockPlacementRule(@NotNull Block block) {
|
||||
public abstract class BlockPlacementRule {
|
||||
protected final Block block;
|
||||
|
||||
protected BlockPlacementRule(@NotNull Block block) {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the block state id can be updated (for instance if a neighbour block changed).
|
||||
* This is first called on a newly placed block, and then this is called for all neighbors of the block
|
||||
*
|
||||
* @param instance the instance of the block
|
||||
* @param blockPosition the block position
|
||||
* @param currentBlock the current block
|
||||
* @param updateState The current parameters to the block update
|
||||
* @return the updated block
|
||||
*/
|
||||
public abstract @NotNull Block blockUpdate(@NotNull Instance instance, @NotNull Point blockPosition, @NotNull Block currentBlock);
|
||||
public @NotNull Block blockUpdate(@NotNull UpdateState updateState) {
|
||||
return updateState.currentBlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the block is placed.
|
||||
* It is recommended that you only set up basic properties on the block for this placement, such as determining facing, etc
|
||||
*
|
||||
* @param instance the instance of the block
|
||||
* @param block the block placed
|
||||
* @param blockFace the block face
|
||||
* @param blockPosition the block position
|
||||
* @param pl the player who placed the block
|
||||
* @param placementState The current parameters to the block placement
|
||||
* @return the block to place, {@code null} to cancel
|
||||
*/
|
||||
public abstract @Nullable Block blockPlace(@NotNull Instance instance,
|
||||
@NotNull Block block, @NotNull BlockFace blockFace, @NotNull Point blockPosition,
|
||||
@NotNull Player pl);
|
||||
public abstract @Nullable Block blockPlace(@NotNull PlacementState placementState);
|
||||
|
||||
public boolean isSelfReplaceable(@NotNull Block block, @NotNull BlockFace blockFace, @NotNull Point cursorPosition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public @NotNull Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public record PlacementState(
|
||||
@NotNull Block.Getter instance,
|
||||
@NotNull Block block,
|
||||
@NotNull BlockFace blockFace,
|
||||
@NotNull Point placePosition,
|
||||
@NotNull Point cursorPosition,
|
||||
@NotNull Pos playerPosition,
|
||||
@NotNull ItemMeta usedItemMeta,
|
||||
boolean isPlayerShifting
|
||||
) {}
|
||||
|
||||
public record UpdateState(@NotNull Block.Getter instance,
|
||||
@NotNull Point blockPosition,
|
||||
@NotNull Block currentBlock) {}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
package net.minestom.server.instance.block.rule.vanilla;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockFace;
|
||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AxisPlacementRule extends BlockPlacementRule {
|
||||
|
||||
public AxisPlacementRule(@NotNull Block block) {
|
||||
super(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Block blockUpdate(@NotNull Instance instance, @NotNull Point blockPosition, @NotNull Block block) {
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block blockPlace(@NotNull Instance instance,
|
||||
@NotNull Block block, @NotNull BlockFace blockFace, @NotNull Point blockPosition,
|
||||
@NotNull Player pl) {
|
||||
String axis = "y";
|
||||
if (blockFace == BlockFace.WEST || blockFace == BlockFace.EAST) {
|
||||
axis = "x";
|
||||
} else if (blockFace == BlockFace.SOUTH || blockFace == BlockFace.NORTH) {
|
||||
axis = "z";
|
||||
}
|
||||
return block.withProperty("axis", axis);
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
package net.minestom.server.instance.block.rule.vanilla;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockFace;
|
||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||
import net.minestom.server.utils.block.BlockUtils;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class RedstonePlacementRule extends BlockPlacementRule {
|
||||
|
||||
public RedstonePlacementRule() {
|
||||
super(Block.REDSTONE_WIRE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Block blockUpdate(@NotNull Instance instance, @NotNull Point blockPosition, @NotNull Block block) {
|
||||
BlockUtils blockUtils = new BlockUtils(instance, blockPosition);
|
||||
|
||||
String east = "none";
|
||||
String north = "none";
|
||||
String power = "0";
|
||||
String south = "none";
|
||||
String west = "none";
|
||||
|
||||
// TODO Block should have method isRedstone, as redstone connects to more than itself.
|
||||
|
||||
final BlockUtils blockNorth = blockUtils.north();
|
||||
final BlockUtils blockSouth = blockUtils.south();
|
||||
final BlockUtils blockEast = blockUtils.east();
|
||||
final BlockUtils blockWest = blockUtils.west();
|
||||
int connected = 0;
|
||||
|
||||
if (blockNorth.equals(Block.REDSTONE_WIRE) || blockNorth.below().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
north = "side";
|
||||
}
|
||||
if (blockSouth.equals(Block.REDSTONE_WIRE) || blockSouth.below().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
south = "side";
|
||||
}
|
||||
if (blockEast.equals(Block.REDSTONE_WIRE) || blockEast.below().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
east = "side";
|
||||
}
|
||||
if (blockWest.equals(Block.REDSTONE_WIRE) || blockWest.below().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
west = "side";
|
||||
}
|
||||
if (blockNorth.above().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
north = "up";
|
||||
}
|
||||
if (blockSouth.above().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
south = "up";
|
||||
}
|
||||
if (blockEast.above().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
east = "up";
|
||||
}
|
||||
if (blockWest.above().equals(Block.REDSTONE_WIRE)) {
|
||||
connected++;
|
||||
west = "up";
|
||||
}
|
||||
if (connected == 0) {
|
||||
north = "side";
|
||||
south = "side";
|
||||
east = "side";
|
||||
west = "side";
|
||||
} else if (connected == 1) {
|
||||
if (!north.equals("none")) {
|
||||
south = "side";
|
||||
}
|
||||
if (!south.equals("none")) {
|
||||
north = "side";
|
||||
}
|
||||
if (!east.equals("none")) {
|
||||
west = "side";
|
||||
}
|
||||
if (!west.equals("none")) {
|
||||
east = "side";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO power
|
||||
return Block.REDSTONE_WIRE.withProperties(Map.of(
|
||||
"east", east,
|
||||
"north", north,
|
||||
"south", south,
|
||||
"west", west,
|
||||
"power", power));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block blockPlace(@NotNull Instance instance,
|
||||
@NotNull Block block, @NotNull BlockFace blockFace, @NotNull Point blockPosition,
|
||||
@NotNull Player pl) {
|
||||
final Block belowBlock = instance.getBlock(blockPosition.sub(0, 1, 0));
|
||||
return belowBlock.isSolid() ? block : null;
|
||||
}
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
package net.minestom.server.instance.block.rule.vanilla;
|
||||
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockFace;
|
||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class StairsPlacementRule extends BlockPlacementRule {
|
||||
|
||||
public StairsPlacementRule(@NotNull Block block) {
|
||||
super(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Block blockUpdate(@NotNull Instance instance, @NotNull Point blockPosition, @NotNull Block block) {
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block blockPlace(@NotNull Instance instance,
|
||||
@NotNull Block block, @NotNull BlockFace blockFace,
|
||||
@NotNull Point blockPosition, @NotNull Player player) {
|
||||
Facing facing = this.getFacing(player);
|
||||
Shape shape = this.getShape(instance, blockPosition, facing);
|
||||
BlockFace half = BlockFace.BOTTOM; // waiting for new block faces to be implemented
|
||||
String waterlogged = "false"; // waiting for water to be implemented
|
||||
|
||||
return block.withProperties(Map.of(
|
||||
"facing", facing.toString(),
|
||||
"half", half.toString(),
|
||||
"shape", shape.toString(),
|
||||
"waterlogged", waterlogged));
|
||||
|
||||
}
|
||||
|
||||
private enum Shape {
|
||||
STRAIGHT,
|
||||
OUTER_LEFT,
|
||||
OUTER_RIGHT,
|
||||
INNER_LEFT,
|
||||
INNER_RIGHT
|
||||
}
|
||||
|
||||
private enum Facing {
|
||||
NORTH(
|
||||
new Vec(0, 0, 1),
|
||||
new Vec(0, 0, -1)
|
||||
),
|
||||
EAST(
|
||||
new Vec(-1, 0, 0),
|
||||
new Vec(1, 0, 0)
|
||||
),
|
||||
SOUTH(
|
||||
new Vec(0, 0, -1),
|
||||
new Vec(0, 0, 1)
|
||||
),
|
||||
WEST(
|
||||
new Vec(1, 0, 0),
|
||||
new Vec(-1, 0, 0)
|
||||
);
|
||||
|
||||
private final Point front;
|
||||
private final Point back;
|
||||
|
||||
Facing(@NotNull Point front, @NotNull Point back) {
|
||||
this.front = front;
|
||||
this.back = back;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Pair<@Nullable Shape, @Nullable Facing> getFront(@NotNull Instance instance, @NotNull Point blockPosition) {
|
||||
// TODO FIX
|
||||
return null;
|
||||
//return this.getProperties(instance, blockPosition.clone().add(this.front));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Pair<@Nullable Shape, @Nullable Facing> getBack(@NotNull Instance instance, @NotNull Point blockPosition) {
|
||||
return this.getProperties(instance, blockPosition.add(this.back));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Pair<@Nullable Shape, @Nullable Facing> getProperties(@NotNull Instance instance, @NotNull Point blockPosition) {
|
||||
Block block = instance.getBlock(blockPosition);
|
||||
if (block.isAir()) {
|
||||
return Pair.of(null, null);
|
||||
}
|
||||
Block state = instance.getBlock(blockPosition);
|
||||
try {
|
||||
// TODO: Get properties from state
|
||||
// Shape shape = Shape.valueOf(state.getProperty("shape").toUpperCase());
|
||||
// Facing facing = Facing.valueOf(state.getProperty("facing").toUpperCase());
|
||||
// return Pair.of(shape, facing);
|
||||
return Pair.of(null, null);
|
||||
} catch (Exception ex) {
|
||||
return Pair.of(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Shape getShape(@NotNull Instance instance, @NotNull Point blockPosition, @NotNull Facing facing) {
|
||||
// TODO FIX
|
||||
return null;
|
||||
/*Pair<Shape, Facing> front = facing.getFront(instance, blockPosition);
|
||||
Pair<Shape, Facing> back = facing.getBack(instance, blockPosition);
|
||||
Shape shape = this.getShapeFromSide(front, facing, Shape.INNER_RIGHT, Shape.INNER_LEFT);
|
||||
if (shape == null) {
|
||||
shape = this.getShapeFromSide(back, facing, Shape.OUTER_RIGHT, Shape.OUTER_LEFT);
|
||||
}
|
||||
return shape == null ? Shape.STRAIGHT : shape;*/
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Shape getShapeFromSide(@NotNull Pair<Shape, Facing> side, @NotNull Facing facing, @NotNull Shape right, @NotNull Shape left) {
|
||||
if (side.left() == null) {
|
||||
return null;
|
||||
}
|
||||
Facing sideFacing = side.right();
|
||||
if (facing.equals(Facing.NORTH)) {
|
||||
if (sideFacing.equals(Facing.EAST)) {
|
||||
return right;
|
||||
} else if (sideFacing.equals(Facing.WEST)) {
|
||||
return left;
|
||||
}
|
||||
} else if (facing.equals(Facing.SOUTH)) {
|
||||
if (sideFacing.equals(Facing.EAST)) {
|
||||
return left;
|
||||
} else if (sideFacing.equals(Facing.WEST)) {
|
||||
return right;
|
||||
}
|
||||
} else if (facing.equals(Facing.EAST)) {
|
||||
if (sideFacing.equals(Facing.SOUTH)) {
|
||||
return right;
|
||||
} else if (sideFacing.equals(Facing.NORTH)) {
|
||||
return left;
|
||||
}
|
||||
} else if (facing.equals(Facing.WEST)) {
|
||||
if (sideFacing.equals(Facing.SOUTH)) {
|
||||
return left;
|
||||
} else if (sideFacing.equals(Facing.NORTH)) {
|
||||
return right;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Facing getFacing(@NotNull Player player) {
|
||||
float degrees = (player.getPosition().yaw() - 90) % 360;
|
||||
if (degrees < 0) {
|
||||
degrees += 360;
|
||||
}
|
||||
if (0 <= degrees && degrees < 45) {
|
||||
return Facing.WEST;
|
||||
} else if (45 <= degrees && degrees < 135) {
|
||||
return Facing.NORTH;
|
||||
} else if (135 <= degrees && degrees < 225) {
|
||||
return Facing.EAST;
|
||||
} else if (225 <= degrees && degrees < 315) {
|
||||
return Facing.SOUTH;
|
||||
} else { // 315 <= degrees && degrees < 360
|
||||
return Facing.WEST;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package net.minestom.server.instance.block.rule.vanilla;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.BlockFace;
|
||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class WallPlacementRule extends BlockPlacementRule {
|
||||
|
||||
public WallPlacementRule(@NotNull Block block) {
|
||||
super(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Block blockUpdate(@NotNull Instance instance, @NotNull Point blockPosition, @NotNull Block block) {
|
||||
final int x = blockPosition.blockX();
|
||||
final int y = blockPosition.blockY();
|
||||
final int z = blockPosition.blockZ();
|
||||
|
||||
String east = "none";
|
||||
String north = "none";
|
||||
String south = "none";
|
||||
String up = "true";
|
||||
String waterlogged = "false";
|
||||
String west = "none";
|
||||
|
||||
if (isBlock(instance, x + 1, y, z)) {
|
||||
east = "low";
|
||||
}
|
||||
|
||||
if (isBlock(instance, x - 1, y, z)) {
|
||||
west = "low";
|
||||
}
|
||||
|
||||
if (isBlock(instance, x, y, z + 1)) {
|
||||
south = "low";
|
||||
}
|
||||
|
||||
if (isBlock(instance, x, y, z - 1)) {
|
||||
north = "low";
|
||||
}
|
||||
|
||||
return block.withProperties(Map.of(
|
||||
"east", east,
|
||||
"north", north,
|
||||
"south", south,
|
||||
"west", west,
|
||||
"up", up,
|
||||
"waterlogged", waterlogged));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block blockPlace(@NotNull Instance instance,
|
||||
@NotNull Block block, @NotNull BlockFace blockFace, @NotNull Point blockPosition,
|
||||
@NotNull Player pl) {
|
||||
return block;
|
||||
}
|
||||
|
||||
private boolean isBlock(Instance instance, int x, int y, int z) {
|
||||
return instance.getBlock(x, y, z).isSolid();
|
||||
}
|
||||
}
|
@ -17,8 +17,8 @@ import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public record PlayerHeadMeta(TagReadable readable) implements ItemMetaView<PlayerHeadMeta.Builder> {
|
||||
private static final Tag<UUID> SKULL_OWNER = Tag.UUID("Id").path("SkullOwner");
|
||||
private static final Tag<PlayerSkin> SKIN = Tag.Structure("Properties", new TagSerializer<PlayerSkin>() {
|
||||
public static final Tag<UUID> SKULL_OWNER = Tag.UUID("Id").path("SkullOwner");
|
||||
public static final Tag<PlayerSkin> SKIN = Tag.Structure("Properties", new TagSerializer<PlayerSkin>() {
|
||||
private static final Tag<NBT> TEXTURES = Tag.NBT("textures");
|
||||
|
||||
@Override
|
||||
|
@ -27,6 +27,8 @@ import net.minestom.server.network.packet.server.play.BlockChangePacket;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class BlockPlacementListener {
|
||||
private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager();
|
||||
|
||||
@ -34,7 +36,7 @@ public class BlockPlacementListener {
|
||||
final PlayerInventory playerInventory = player.getInventory();
|
||||
final Player.Hand hand = packet.hand();
|
||||
final BlockFace blockFace = packet.blockFace();
|
||||
final Point blockPosition = packet.blockPosition();
|
||||
Point blockPosition = packet.blockPosition();
|
||||
|
||||
final Instance instance = player.getInstance();
|
||||
if (instance == null)
|
||||
@ -87,10 +89,24 @@ public class BlockPlacementListener {
|
||||
}
|
||||
|
||||
// Get the newly placed block position
|
||||
final int offsetX = blockFace == BlockFace.WEST ? -1 : blockFace == BlockFace.EAST ? 1 : 0;
|
||||
final int offsetY = blockFace == BlockFace.BOTTOM ? -1 : blockFace == BlockFace.TOP ? 1 : 0;
|
||||
final int offsetZ = blockFace == BlockFace.NORTH ? -1 : blockFace == BlockFace.SOUTH ? 1 : 0;
|
||||
final Point placementPosition = blockPosition.add(offsetX, offsetY, offsetZ);
|
||||
//todo it feels like it should be possible to have better replacement rules than this, feels pretty scuffed.
|
||||
Point placementPosition = blockPosition;
|
||||
var interactedPlacementRule = BLOCK_MANAGER.getBlockPlacementRule(interactedBlock);
|
||||
if (interactedPlacementRule == null || !interactedPlacementRule.isSelfReplaceable(interactedBlock, blockFace, cursorPosition)) {
|
||||
// If the block is not replaceable, try to place next to it.
|
||||
final int offsetX = blockFace == BlockFace.WEST ? -1 : blockFace == BlockFace.EAST ? 1 : 0;
|
||||
final int offsetY = blockFace == BlockFace.BOTTOM ? -1 : blockFace == BlockFace.TOP ? 1 : 0;
|
||||
final int offsetZ = blockFace == BlockFace.NORTH ? -1 : blockFace == BlockFace.SOUTH ? 1 : 0;
|
||||
placementPosition = blockPosition.add(offsetX, offsetY, offsetZ);
|
||||
|
||||
var placementBlock = instance.getBlock(placementPosition);
|
||||
var placementRule = BLOCK_MANAGER.getBlockPlacementRule(placementBlock);
|
||||
if (!placementBlock.registry().isReplaceable() && (placementRule == null ||
|
||||
!placementRule.isSelfReplaceable(placementBlock, blockFace, cursorPosition))) {
|
||||
// If the block is still not replaceable, cancel the placement
|
||||
canPlaceBlock = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!canPlaceBlock) {
|
||||
// Send a block change with the real block in the instance to keep the client in sync,
|
||||
@ -136,7 +152,11 @@ public class BlockPlacementListener {
|
||||
final BlockPlacementRule blockPlacementRule = BLOCK_MANAGER.getBlockPlacementRule(resultBlock);
|
||||
if (blockPlacementRule != null) {
|
||||
// Get id from block placement rule instead of the event
|
||||
resultBlock = blockPlacementRule.blockPlace(instance, resultBlock, blockFace, blockPosition, player);
|
||||
resultBlock = blockPlacementRule.blockPlace(new BlockPlacementRule.PlacementState(
|
||||
instance, resultBlock, blockFace,
|
||||
placementPosition, cursorPosition,
|
||||
player.getPosition(), usedItem.meta(), player.isSneaking())
|
||||
);
|
||||
}
|
||||
if (resultBlock == null) {
|
||||
refresh(player, chunk);
|
||||
|
@ -172,6 +172,7 @@ public final class Registry {
|
||||
private final boolean liquid;
|
||||
private final boolean occludes;
|
||||
private final int lightEmission;
|
||||
private final boolean replaceable;
|
||||
private final String blockEntity;
|
||||
private final int blockEntityId;
|
||||
private final Supplier<Material> materialSupplier;
|
||||
@ -191,9 +192,10 @@ public final class Registry {
|
||||
this.jumpFactor = main.getDouble("jumpFactor", 1);
|
||||
this.air = main.getBoolean("air", false);
|
||||
this.solid = main.getBoolean("solid");
|
||||
this.occludes = main.getBoolean("occludes", true);
|
||||
this.liquid = main.getBoolean("liquid", false);
|
||||
this.occludes = main.getBoolean("occludes", true);
|
||||
this.lightEmission = main.getInt("lightEmission", 0);
|
||||
this.replaceable = main.getBoolean("replaceable", false);
|
||||
{
|
||||
Properties blockEntity = main.section("blockEntity");
|
||||
if (blockEntity != null) {
|
||||
@ -259,18 +261,22 @@ public final class Registry {
|
||||
return solid;
|
||||
}
|
||||
|
||||
public boolean occludes() {
|
||||
return occludes;
|
||||
}
|
||||
|
||||
public boolean isLiquid() {
|
||||
return liquid;
|
||||
}
|
||||
|
||||
public boolean occludes() {
|
||||
return occludes;
|
||||
}
|
||||
|
||||
public int lightEmission() {
|
||||
return lightEmission;
|
||||
}
|
||||
|
||||
public boolean isReplaceable() {
|
||||
return replaceable;
|
||||
}
|
||||
|
||||
public boolean isBlockEntity() {
|
||||
return blockEntity != null;
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ import java.util.Objects;
|
||||
|
||||
public class BlockUtils {
|
||||
|
||||
private final Instance instance;
|
||||
private final Block.Getter instance;
|
||||
private final Point position;
|
||||
|
||||
public BlockUtils(Instance instance, Point position) {
|
||||
public BlockUtils(Block.Getter instance, Point position) {
|
||||
this.instance = instance;
|
||||
this.position = position;
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
package net.minestom.testing.util;
|
||||
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MockBlockGetter implements Block.Getter, Block.Setter {
|
||||
|
||||
public static @NotNull MockBlockGetter empty() {
|
||||
return new MockBlockGetter(Map.of(), Block.AIR);
|
||||
}
|
||||
|
||||
public static @NotNull MockBlockGetter single(@NotNull Block block) {
|
||||
return new MockBlockGetter(Map.of(Vec.ZERO, block), Block.AIR);
|
||||
}
|
||||
|
||||
public static @NotNull MockBlockGetter all(@NotNull Block block) {
|
||||
return new MockBlockGetter(Map.of(), block);
|
||||
}
|
||||
|
||||
private final Map<Vec, Block> blocks = new HashMap<>();
|
||||
private final Block defaultBlock;
|
||||
|
||||
private MockBlockGetter(Map<Vec, Block> blocks, Block defaultBlock) {
|
||||
blocks.forEach((pos, block) -> this.blocks.put(new Vec(pos.blockX(), pos.blockY(), pos.blockZ()), block));
|
||||
this.defaultBlock = defaultBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @UnknownNullability Block getBlock(int x, int y, int z, @NotNull Condition condition) {
|
||||
return blocks.getOrDefault(new Vec(x, y, z), defaultBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, @NotNull Block block) {
|
||||
blocks.put(new Vec(x, y, z), block);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user