9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

refactor bush block

This commit is contained in:
XiaoMoMi
2025-03-28 01:02:06 +08:00
parent b57b084a43
commit d42c408f8c
11 changed files with 160 additions and 33 deletions

View File

@@ -34,6 +34,9 @@ blocks:
push-reaction: DESTROY
behavior:
type: bush_block
bottom-block-tags:
- minecraft:dirt
- minecraft:farmland
loot:
template: "default:loot_table/basic"
arguments:

View File

@@ -6,6 +6,7 @@ import net.momirealms.craftengine.shared.block.EmptyBlockBehavior;
public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key BUSH_BLOCK = Key.from("craftengine:bush_block");
public static final Key HANGING_BLOCK = Key.from("craftengine:hanging_block");
public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block");
public static final Key LEAVES_BLOCK = Key.from("craftengine:leaves_block");
public static final Key STRIPPABLE_BLOCK = Key.from("craftengine:strippable_block");
@@ -18,6 +19,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
register(FALLING_BLOCK, FallingBlockBehavior.FACTORY);
register(BUSH_BLOCK, BushBlockBehavior.FACTORY);
register(HANGING_BLOCK, HangingBlockBehavior.FACTORY);
register(LEAVES_BLOCK, LeavesBlockBehavior.FACTORY);
register(STRIPPABLE_BLOCK, StrippableBlockBehavior.FACTORY);
register(SAPLING_BLOCK, SaplingBlockBehavior.FACTORY);

View File

@@ -14,26 +14,29 @@ import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.loot.parameter.LootParameters;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.Tuple;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.util.context.ContextHolder;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.shared.block.BlockBehavior;
import org.bukkit.World;
import org.bukkit.*;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.Callable;
public class BushBlockBehavior extends AbstractBlockBehavior {
public static final Factory FACTORY = new Factory();
protected static final Object DIRT_TAG = BlockTags.getOrCreate(Key.of("minecraft", "dirt"));
protected static final Object FARMLAND = BlockTags.getOrCreate(Key.of("minecraft", "farmland"));
public static final BushBlockBehavior INSTANCE = new BushBlockBehavior(List.of(DIRT_TAG, FARMLAND));
protected final List<Object> tagsCanSurviveOn;
protected final Set<Object> blocksCansSurviveOn;
protected final Set<String> customBlocksCansSurviveOn;
protected final boolean any;
public BushBlockBehavior(List<Object> tagsCanSurviveOn) {
public BushBlockBehavior(List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn) {
this.tagsCanSurviveOn = tagsCanSurviveOn;
this.blocksCansSurviveOn = blocksCansSurviveOn;
this.customBlocksCansSurviveOn = customBlocksCansSurviveOn;
this.any = this.tagsCanSurviveOn.isEmpty() && this.blocksCansSurviveOn.isEmpty() && this.customBlocksCansSurviveOn.isEmpty();
}
@Override
@@ -82,19 +85,41 @@ public class BushBlockBehavior extends AbstractBlockBehavior {
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
if (arguments.containsKey("bottom-block-tags")) {
return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("bottom-block-tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList());
} else if (arguments.containsKey("tags")) {
return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList());
} else {
return INSTANCE;
}
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments);
return new BushBlockBehavior(tuple.left(), tuple.mid(), tuple.right());
}
}
private boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException {
public static Tuple<List<Object>, Set<Object>, Set<String>> readTagsAndState(Map<String, Object> arguments) {
List<Object> mcTags = new ArrayList<>();
for (String tag : MiscUtils.getAsStringList(arguments.getOrDefault("bottom-block-tags", List.of()))) {
mcTags.add(BlockTags.getOrCreate(Key.of(tag)));
}
Set<Object> mcBlocks = new HashSet<>();
Set<String> customBlocks = new HashSet<>();
for (String blockStateStr : MiscUtils.getAsStringList(arguments.getOrDefault("bottom-blocks", List.of()))) {
int index = blockStateStr.indexOf('[');
Key blockType = index != -1 ? Key.from(blockStateStr.substring(0, index)) : Key.from(blockStateStr);
Material material = Registry.MATERIAL.get(new NamespacedKey(blockType.namespace(), blockType.value()));
if (material != null) {
if (index == -1) {
// vanilla
mcBlocks.addAll(BlockStateUtils.getAllVanillaBlockStates(blockType));
} else {
mcBlocks.add(BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(blockStateStr)));
}
} else {
// custom maybe
customBlocks.add(blockStateStr);
}
}
return new Tuple<>(mcTags, mcBlocks, customBlocks);
}
protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException {
int y = Reflections.field$Vec3i$y.getInt(blockPos);
int x = Reflections.field$Vec3i$x.getInt(blockPos);
int z = Reflections.field$Vec3i$z.getInt(blockPos);
@@ -104,11 +129,28 @@ public class BushBlockBehavior extends AbstractBlockBehavior {
}
protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException {
if (this.any) return true;
for (Object tag : this.tagsCanSurviveOn) {
if ((boolean) Reflections.method$BlockStateBase$hasTag.invoke(belowState, tag)) {
return true;
}
}
int id = BlockStateUtils.blockStateToId(belowState);
if (BlockStateUtils.isVanillaBlock(id)) {
if (!this.blocksCansSurviveOn.isEmpty() && this.blocksCansSurviveOn.contains(belowState)) {
return true;
}
} else {
ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(id);
if (previousState != null && !previousState.isEmpty()) {
if (this.customBlocksCansSurviveOn.contains(previousState.owner().value().id().toString())) {
return true;
}
if (this.customBlocksCansSurviveOn.contains(previousState.toString())) {
return true;
}
}
}
return false;
}
}

View File

@@ -0,0 +1,38 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.util.Tuple;
import net.momirealms.craftengine.shared.block.BlockBehavior;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HangingBlockBehavior extends BushBlockBehavior {
public static final Factory FACTORY = new Factory();
public HangingBlockBehavior(List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn) {
super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
}
@Override
protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException {
int y = Reflections.field$Vec3i$y.getInt(blockPos);
int x = Reflections.field$Vec3i$x.getInt(blockPos);
int z = Reflections.field$Vec3i$z.getInt(blockPos);
Object belowPos = Reflections.constructor$BlockPos.newInstance(x, y + 1, z);
Object belowState = Reflections.method$BlockGetter$getBlockState.invoke(world, belowPos);
return mayPlaceOn(belowState, world, belowPos);
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments);
return new HangingBlockBehavior(tuple.left(), tuple.mid(), tuple.right());
}
}
}

View File

@@ -9,14 +9,15 @@ import net.momirealms.craftengine.shared.block.BlockBehavior;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class OnLiquidBlockBehavior extends BushBlockBehavior {
public static final Factory FACTORY = new Factory();
private final boolean onWater;
private final boolean onLava;
public OnLiquidBlockBehavior(List<Object> tagsCanSurviveOn, boolean onWater, boolean onLava) {
super(tagsCanSurviveOn);
public OnLiquidBlockBehavior(boolean onWater, boolean onLava) {
super(List.of(), Set.of(), Set.of());
this.onWater = onWater;
this.onLava = onLava;
}
@@ -33,7 +34,7 @@ public class OnLiquidBlockBehavior extends BushBlockBehavior {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water")));
return new OnLiquidBlockBehavior(List.of(), liquidTypes.contains("water"), liquidTypes.contains("lava"));
return new OnLiquidBlockBehavior(liquidTypes.contains("water"), liquidTypes.contains("lava"));
}
}

View File

@@ -2,7 +2,10 @@ package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.util.*;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.FeatureUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.UpdateOption;
@@ -12,6 +15,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.util.Tuple;
import net.momirealms.craftengine.shared.block.BlockBehavior;
import org.bukkit.Location;
import org.bukkit.World;
@@ -19,6 +23,7 @@ import org.bukkit.World;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
public class SaplingBlockBehavior extends BushBlockBehavior {
@@ -27,8 +32,8 @@ public class SaplingBlockBehavior extends BushBlockBehavior {
private final Property<Integer> stageProperty;
private final double boneMealSuccessChance;
public SaplingBlockBehavior(Key feature, Property<Integer> stageProperty, List<Object> tagsCanSurviveOn, double boneMealSuccessChance) {
super(tagsCanSurviveOn);
public SaplingBlockBehavior(Key feature, Property<Integer> stageProperty, List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn, double boneMealSuccessChance) {
super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
this.feature = feature;
this.stageProperty = stageProperty;
this.boneMealSuccessChance = boneMealSuccessChance;
@@ -121,13 +126,8 @@ public class SaplingBlockBehavior extends BushBlockBehavior {
throw new IllegalArgumentException("stage property not set for sapling");
}
double boneMealSuccessChance = MiscUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45));
if (arguments.containsKey("bottom-block-tags")) {
return new SaplingBlockBehavior(Key.of(feature), stageProperty, MiscUtils.getAsStringList(arguments.get("bottom-block-tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList(), boneMealSuccessChance);
} else if (arguments.containsKey("tags")) {
return new SaplingBlockBehavior(Key.of(feature), stageProperty, MiscUtils.getAsStringList(arguments.get("tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList(), boneMealSuccessChance);
} else {
return new SaplingBlockBehavior(Key.of(feature), stageProperty, List.of(DIRT_TAG, FARMLAND), boneMealSuccessChance);
}
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments);
return new SaplingBlockBehavior(Key.of(feature), stageProperty, tuple.left(), tuple.mid(), tuple.right(), boneMealSuccessChance);
}
}
}

View File

@@ -0,0 +1,11 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import java.util.List;
import java.util.Set;
public class SugarCaneBlockBehavior extends BushBlockBehavior {
public SugarCaneBlockBehavior(List<Object> tagsCanSurviveOn, Set<Object> blocksCansSurviveOn, Set<String> customBlocksCansSurviveOn) {
super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn);
}
}

View File

@@ -118,7 +118,7 @@ public class BukkitVanillaLootManager implements VanillaLootManager, Listener {
VanillaLoot vanillaLoot = this.blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK));
vanillaLoot.addLootTable(lootTable);
} else {
for (Object blockState : BlockStateUtils.getAllBlockStates(Key.of(target))) {
for (Object blockState : BlockStateUtils.getAllVanillaBlockStates(Key.of(target))) {
if (blockState == Reflections.instance$Blocks$AIR$defaultState) {
this.plugin.logger().warn(path, "Failed to load " + id + ". Invalid target " + target);
return;

View File

@@ -6,7 +6,6 @@ import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.network.impl.*;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;

View File

@@ -1,18 +1,23 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.core.block.BlockStateParser;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.PushReaction;
import net.momirealms.craftengine.core.util.Instrument;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MapColor;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Optional;
public class BlockStateUtils {
public static final IdentityHashMap<Object, Object> CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>();
@@ -27,8 +32,36 @@ public class BlockStateUtils {
hasInit = true;
}
@SuppressWarnings("unchecked")
public static List<Object> getAllBlockStates(String blockState) {
int index = blockState.indexOf('[');
if (index == -1) {
return getAllBlockStates(Key.of(blockState));
} else {
String blockTypeString = blockState.substring(0, index);
Key block = Key.of(blockTypeString);
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().getBlock(block);
if (optionalCustomBlock.isPresent()) {
ImmutableBlockState state = BlockStateParser.deserialize(blockState);
if (state == null) {
return List.of();
} else {
return List.of(state.customBlockState().handle());
}
} else {
BlockData blockData = Bukkit.createBlockData(blockState);
return List.of(blockDataToBlockState(blockData));
}
}
}
public static List<Object> getAllBlockStates(Key block) {
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().getBlock(block);
return optionalCustomBlock.map(customBlock -> customBlock.variantProvider().states().stream().map(it -> it.customBlockState().handle()).toList())
.orElseGet(() -> getAllVanillaBlockStates(block));
}
@SuppressWarnings("unchecked")
public static List<Object> getAllVanillaBlockStates(Key block) {
try {
Object blockIns = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$BLOCK, Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, block.namespace(), block.value()));
Object definition = Reflections.field$Block$StateDefinition.get(blockIns);

View File

@@ -3,8 +3,6 @@ package net.momirealms.craftengine.core.plugin.network;
import io.netty.channel.Channel;
import net.momirealms.craftengine.core.entity.player.Player;
import java.util.Collection;
public interface NetworkManager {
String MOD_CHANNEL = "craftengine:payload";