Skip to content

Commit

Permalink
Block Conditions Ported
Browse files Browse the repository at this point in the history
  • Loading branch information
Dueris committed Jul 15, 2024
1 parent 9e677ae commit ea89d5b
Show file tree
Hide file tree
Showing 12 changed files with 340 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.google.gson.JsonPrimitive;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
Expand All @@ -15,6 +14,7 @@
import org.bukkit.NamespacedKey;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.Set;
Expand All @@ -32,10 +32,12 @@ public boolean isEmpty() {
return this.handle.isEmpty();
}

@NotNull
public FactoryJsonObject getJsonObject(String key) {
return isPresent(key) ? new FactoryJsonObject(this.handle.get(key).getAsJsonObject()) : new FactoryJsonObject(new JsonObject());
}

@NotNull
public FactoryJsonArray getJsonArray(String key) {
return isPresent(key) ? new FactoryJsonArray(this.handle.get(key).getAsJsonArray()) : new FactoryJsonArray(new JsonArray());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
Expand Down Expand Up @@ -80,6 +79,7 @@ public final class OriginsPaper extends JavaPlugin implements Listener {
public static ConditionExecutor conditionExecutor;
public static String apoliVersion = "2.12.0-alpha.3";
public static boolean placeholderapi = false;
public static boolean showCommandOutput = false;
public static File playerDataFolder;
public static boolean forceUseCurrentVersion = false;
public static OriginScheduler.MainTickerThread scheduler = null;
Expand Down Expand Up @@ -181,6 +181,7 @@ public void onEnable() {
glowingEntitiesUtils = new GlowingEntitiesUtils(this);
try {
OriginConfiguration.load();
OriginsPaper.showCommandOutput = OriginConfiguration.getConfiguration().getBoolean("show-command-output");
} catch (IOException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void register() {
if (server != null) {
String blockName = ((CraftWorld) block.getWorld()).getHandle().getBlockState(CraftLocation.toBlockPosition(block)).getBlock().getDescriptionId();
CommandSourceStack source = new CommandSourceStack(
CommandSource.NULL,
OriginsPaper.showCommandOutput ? server : CommandSource.NULL,
new Vec3(CraftLocation.toBlockPosition(block).getX() + 0.5, CraftLocation.toBlockPosition(block).getY() + 0.5, CraftLocation.toBlockPosition(block).getZ() + 0.5),
new Vec2(0, 0),
((CraftWorld) block.getWorld()).getHandle(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ public void run() {
if (server != null) {
boolean validOutput = !(entity.getHandle() instanceof ServerPlayer) || ((ServerPlayer) entity.getHandle()).connection != null;
CommandSourceStack source = new CommandSourceStack(
CommandSource.NULL,
OriginsPaper.showCommandOutput && validOutput ? entity.getHandle() : CommandSource.NULL,
entity.getHandle().position(),
entity.getHandle().getRotationVector(),
entity.getHandle().level() instanceof ServerLevel ? (ServerLevel) entity.getHandle().level() : null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,286 @@
package me.dueris.originspaper.factory.conditions.types;

import me.dueris.calio.data.CalioDataTypes;
import me.dueris.calio.data.factory.FactoryElement;
import me.dueris.calio.data.factory.FactoryJsonObject;
import me.dueris.calio.registry.Registrable;
import me.dueris.originspaper.OriginsPaper;
import me.dueris.originspaper.factory.conditions.ConditionExecutor;
import me.dueris.originspaper.factory.data.types.Comparison;
import me.dueris.originspaper.factory.data.types.Shape;
import me.dueris.originspaper.factory.data.types.VectorGetter;
import me.dueris.originspaper.registry.Registries;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.LiquidBlockContainer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Location;
import org.bukkit.block.TileState;
import org.bukkit.craftbukkit.block.CraftBlock;
import org.bukkit.craftbukkit.util.CraftLocation;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiPredicate;

import static me.dueris.originspaper.factory.conditions.types.EntityConditions.compareOutOfBounds;
import static me.dueris.originspaper.factory.conditions.types.EntityConditions.warnCouldNotGetObject;

public class BlockConditions {

public void registerConditions() {
register(new ConditionFactory(OriginsPaper.apoliIdentifier("offset"), (data, block) -> {
return ConditionExecutor.testBlock(data.getJsonObject("condition"), block.getWorld().getBlockAt(block.getLocation().offset(
data.getNumberOrDefault("x", 0).getInt(),
data.getNumberOrDefault("y", 0).getInt(),
data.getNumberOrDefault("z", 0).getInt()
).toLocation(block.getWorld())));
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("height"), (data, block) -> {
return Comparison.fromString(data.getString("comparison")).compare(block.getY(), data.getNumber("compare_to").getInt());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("distance_from_coordinates"), (data, block) -> {
boolean scaleReferenceToDimension = data.getBooleanOrDefault("scale_reference_to_dimension", true),
setResultOnWrongDimension = data.isPresent("result_on_wrong_dimension"),
resultOnWrongDimension = setResultOnWrongDimension && data.getBoolean("result_on_wrong_dimension");
double x = 0, y = 0, z = 0;
Comparison comparison = Comparison.fromString(data.getString("comparison"));
Vec3 pos;
Level world;
BlockPos blockPos = CraftLocation.toBlockPosition(block.getLocation());
pos = new Vec3(blockPos.getX(), blockPos.getY(), blockPos.getZ());
LevelReader worldView = block.getCraftWorld().getHandle();
if (!(worldView instanceof Level))
return warnCouldNotGetObject("world", "block", compareOutOfBounds(Comparison.fromString(data.getString("comparison"))));
else
world = (Level) worldView;
double currentDimensionCoordinateScale = world.dimensionType().coordinateScale();

// Get the reference's scaled coordinates
switch (data.getStringOrDefault("reference", "world_origin")) {
case "player_spawn":
// if (entity instanceof ServerPlayerEntity) { // null instance of AnyClass is always false so the block case is covered
//
// }
// // No break on purpose (defaulting to natural spawn)
case "world_spawn":
if (setResultOnWrongDimension && world.dimension() != Level.OVERWORLD)
return resultOnWrongDimension;
BlockPos spawnPos;
if (world instanceof ServerLevel)
spawnPos = world.getSharedSpawnPos();
else
return warnCouldNotGetObject("world with spawn position", "entity", compareOutOfBounds(comparison));
x = spawnPos.getX();
y = spawnPos.getY();
z = spawnPos.getZ();
break;
case "world_origin":
break;
}
Vec3 coords = VectorGetter.getNMSVector(data.getJsonObject("coordinates"));
Vec3 offset = VectorGetter.getNMSVector(data.getJsonObject("offset"));
x += coords.x + offset.x;
y += coords.y + offset.y;
z += coords.z + offset.z;
if (scaleReferenceToDimension && (x != 0 || z != 0)) {
if (currentDimensionCoordinateScale == 0) // pocket dimensions?
// coordinate scale 0 means it takes 0 blocks to travel in the OW to travel 1 block in the dimension,
// so the dimension is folded on 0 0, so unless the OW reference is at 0 0, it gets scaled to infinity
return compareOutOfBounds(comparison);
x /= currentDimensionCoordinateScale;
z /= currentDimensionCoordinateScale;
}

// Get the distance to these coordinates
double distance,
xDistance = data.getBooleanOrDefault("ignore_x", false) ? 0 : Math.abs(pos.x() - x),
yDistance = data.getBooleanOrDefault("ignore_y", false) ? 0 : Math.abs(pos.y() - y),
zDistance = data.getBooleanOrDefault("ignore_z", false) ? 0 : Math.abs(pos.z() - z);
if (data.getBooleanOrDefault("scale_distance_to_dimension", false)) {
xDistance *= currentDimensionCoordinateScale;
zDistance *= currentDimensionCoordinateScale;
}

distance = Shape.getDistance(data.getEnumValueOrDefault("shape", Shape.class, Shape.CUBE), xDistance, yDistance, zDistance);

if (data.isPresent("round_to_digit"))
distance = new BigDecimal(distance).setScale(data.getNumber("round_to_digit").getInt(), RoundingMode.HALF_UP).doubleValue();

return comparison.compare(distance, data.getNumber("compare_to").getDouble());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("block"), (data, block) -> {
return block.getNMS().is(BuiltInRegistries.BLOCK.get(data.getResourceLocation("block")));
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("in_tag"), (data, block) -> {
Block nms = block.getNMS().getBlock();
return nms.defaultBlockState().is((TagKey<Block>) data.getTagKey("tag", net.minecraft.core.registries.Registries.BLOCK));
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("adjacent"), (data, block) -> {
FactoryJsonObject adjacentCondition = data.getJsonObject("adjacent_condition");
int adjacent = 0;
for (Direction d : Direction.values()) {
Location relativeLocation = CraftLocation.toBukkit(block.getPosition().relative(d));
relativeLocation.setWorld(block.getWorld());
if (adjacentCondition.isEmpty() || ConditionExecutor.testBlock(adjacentCondition, block.getWorld().getBlockAt(relativeLocation))) {
adjacent++;
}
}
return Comparison.fromString(data.getString("comparison")).compare(adjacent, data.getNumber("compare_to").getInt());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("replacable"), (data, block) -> {
return block.getNMS().canBeReplaced();
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("attachable"), (data, block) -> {
for (Direction d : Direction.values()) {
BlockPos adjacent = block.getPosition().relative(d);
if (block.getHandle().getBlockState(adjacent).isFaceSturdy(block.getHandle(), block.getPosition(), d.getOpposite())) {
return true;
}
}
return false;
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("fluid"), (data, block) -> {
return ConditionExecutor.testFluid(data.getJsonObject("fluid_condition"), block.getHandle().getFluidState(block.getPosition()).getType());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("movement_blocking"), (data, block) -> {
BlockState state = block.getNMS();
return state.blocksMotion() && !state.getCollisionShape(block.getHandle(), block.getPosition()).isEmpty();
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("light_blocking"), (data, block) -> {
return !block.getNMS().canOcclude();
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("water_loggable"), (data, block) -> {
return block.getNMS().getBlock() instanceof LiquidBlockContainer;
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("exposed_to_sky"), (data, block) -> {
return block.getHandle().canSeeSky(block.getPosition());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("light_level"), (data, block) -> {
Level world = (Level) block.getHandle();
BlockPos blockPos = block.getPosition();

Comparison comparison = Comparison.fromString(data.getString("comparison"));

int compareTo = data.getNumber("compare_to").getInt();
int lightLevel;

if (data.isPresent("light_type")) {
lightLevel = world.getBrightness(data.getEnumValue("light_type", LightLayer.class), blockPos);
} else {
if (world.isClientSide) {
world.updateSkyBrightness(); // Re-calculate the world's ambient darkness, since it's only calculated once in the client
}

lightLevel = world.getMaxLocalRawBrightness(blockPos);

}

return comparison.compare(lightLevel, compareTo);
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("block_state"), (data, block) -> {
BlockState state = block.getNMS();
Collection<Property<?>> properties = state.getProperties();
String desiredPropertyName = data.getString("property");
Property<?> property = null;
for (Property<?> p : properties) {
if (p.getName().equals(desiredPropertyName)) {
property = p;
break;
}
}
if (property != null) {
Object value = state.getValue(property);
if (data.isPresent("enum") && value instanceof Enum) {
return ((Enum) value).name().equalsIgnoreCase(data.getString("enum"));
} else if (data.isPresent("value") && value instanceof Boolean) {
return (Boolean) value == data.getBoolean("value");
} else if (data.isPresent("comparison") && data.isPresent("compare_to") && value instanceof Integer) {
return Comparison.fromString(data.getString("comparison")).compare((Integer) value, data.getNumber("compare_to").getInt());
}
return true;
}
return false;
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("block_entity"), (data, block) -> {
return block.getState() instanceof TileState;
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("nbt"), (data, block) -> {
CompoundTag nbt = new CompoundTag();
return NbtUtils.compareNbt(data.transformWithCalio("nbt", CalioDataTypes::compoundTag), nbt, true);
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("slipperiness"), (data, block) -> {
BlockState state = block.getNMS();
return Comparison.fromString(data.getString("comparison")).compare(state.getBlock().getFriction(), data.getNumber("compare_to").getFloat());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("blast_resistance"), (data, block) -> {
BlockState state = block.getNMS();
return Comparison.fromString(data.getString("comparison")).compare(state.getBlock().getExplosionResistance(), data.getNumber("compare_to").getFloat());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("hardness"), (data, block) -> {
BlockState state = block.getNMS();
return Comparison.fromString(data.getString("comparison")).compare(state.getBlock().defaultDestroyTime(), data.getNumber("compare_to").getFloat());
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("material"), (data, block) -> {
List<TagKey<Block>> tagKeyList = new ArrayList<>();
if (data.isPresent("material")) {
tagKeyList.add(TagKey.create(net.minecraft.core.registries.Registries.BLOCK, ResourceLocation.parse("apoli:material/" + data.getString("material"))));
}

if (data.isPresent("materials")) {
data.getJsonArray("materials").asList.stream().map(FactoryElement::getString).forEach(s -> {
tagKeyList.add(TagKey.create(net.minecraft.core.registries.Registries.BLOCK, ResourceLocation.parse("apoli:material/" + s)));
});
}

BlockState state = block.getNMS();
for (TagKey<Block> blockTagKey : tagKeyList) {
if (state.is(blockTagKey)) {
return true;
}
}

return false;
}));
register(new ConditionFactory(OriginsPaper.apoliIdentifier("command"), (data, block) -> {
MinecraftServer server = block.getHandle().getServer();
if (server == null) {
return false;
}

AtomicInteger result = new AtomicInteger();
CommandSourceStack source = server.createCommandSourceStack()
.withPosition(block.getPosition().getCenter())
.withPermission(4)
.withCallback((successful, returnValue) -> result.set(returnValue))
.withSuppressedOutput();

Comparison comparison = data.isPresent("comparison") ? Comparison.fromString(data.getString("comparison")) : Comparison.GREATER_THAN_OR_EQUAL;
String command = data.getString("command");

int compareTo = data.getNumberOrDefault("compare_to", 1).getInt();
server.getCommands().performPrefixedCommand(source, command);

return comparison.compare(result.get(), compareTo);
}));
}

public void register(ConditionFactory factory) {
Expand Down
Loading

0 comments on commit ea89d5b

Please sign in to comment.