mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-23 08:59:27 +00:00
@@ -75,7 +75,7 @@ repositories {
|
||||
```
|
||||
```kotlin
|
||||
dependencies {
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.61")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.61")
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.63")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.63")
|
||||
}
|
||||
```
|
||||
@@ -4,11 +4,11 @@ plugins {
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://jitpack.io/")
|
||||
maven("https://repo.momirealms.net/releases/")
|
||||
maven("https://libraries.minecraft.net/")
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -60,6 +60,8 @@ dependencies {
|
||||
compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}")
|
||||
// authlib
|
||||
compileOnly("com.mojang:authlib:${rootProject.properties["authlib_version"]}")
|
||||
// concurrentutil
|
||||
compileOnly("ca.spottedleaf:concurrentutil:${rootProject.properties["concurrent_util_version"]}")
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -99,6 +101,10 @@ tasks {
|
||||
relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs")
|
||||
relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons")
|
||||
relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref")
|
||||
relocate("io.netty.handler.codec.http", "net.momirealms.craftengine.libraries.netty.handler.codec.http")
|
||||
relocate("io.netty.handler.codec.rtsp", "net.momirealms.craftengine.libraries.netty.handler.codec.rtsp")
|
||||
relocate("io.netty.handler.codec.spdy", "net.momirealms.craftengine.libraries.netty.handler.codec.spdy")
|
||||
relocate("io.netty.handler.codec.http2", "net.momirealms.craftengine.libraries.netty.handler.codec.http2")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ repositories {
|
||||
maven("https://nexus.neetgames.com/repository/maven-releases/") // mcmmo
|
||||
maven("https://repo.dmulloy2.net/repository/public/") // mcmmo required
|
||||
maven("https://repo.auxilor.io/repository/maven-public/") // eco
|
||||
maven("https://repo.hiusers.com/releases") // zaphkiel
|
||||
maven("https://jitpack.io") // sxitem slimefun
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -67,6 +69,16 @@ dependencies {
|
||||
compileOnly("com.willfp:libreforge:4.58.1")
|
||||
// AureliumSkills
|
||||
compileOnly("com.github.Archy-X:AureliumSkills:Beta1.3.21")
|
||||
// Zaphkiel
|
||||
compileOnly("ink.ptms:ZaphkielAPI:2.1.0")
|
||||
// WorldGuard
|
||||
compileOnly(files("${rootProject.rootDir}/libs/worldguard-bukkit-7.0.14-dist.jar"))
|
||||
// HeadDatabase
|
||||
compileOnly("com.arcaniax:HeadDatabase-API:1.3.2")
|
||||
// SXItem
|
||||
compileOnly("com.github.Saukiya:SX-Item:4.4.6")
|
||||
// Slimefun
|
||||
compileOnly("io.github.Slimefun:Slimefun4:RC-32")
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.CustomFishingSource;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.MMOItemsSource;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.MythicMobsSource;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsSource;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.*;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.leveler.*;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelModel;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelUtils;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineModel;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDropListener;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicSkillHelper;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.region.WorldGuardRegionCondition;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.viaversion.ViaVersionUtils;
|
||||
@@ -23,9 +22,12 @@ import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.core.entity.furniture.ExternalModel;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.loot.LootConditions;
|
||||
import net.momirealms.craftengine.core.plugin.compatibility.CompatibilityManager;
|
||||
import net.momirealms.craftengine.core.plugin.compatibility.LevelerProvider;
|
||||
import net.momirealms.craftengine.core.plugin.compatibility.ModelProvider;
|
||||
import net.momirealms.craftengine.core.plugin.context.condition.AlwaysFalseCondition;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventConditions;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.WorldManager;
|
||||
@@ -120,6 +122,23 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
|
||||
new MythicItemDropListener(this.plugin);
|
||||
logHook("MythicMobs");
|
||||
}
|
||||
Key worldGuardRegion = Key.of("worldguard:region");
|
||||
if (this.isPluginEnabled("WorldGuard")) {
|
||||
EventConditions.register(worldGuardRegion, new WorldGuardRegionCondition.FactoryImpl<>());
|
||||
LootConditions.register(worldGuardRegion, new WorldGuardRegionCondition.FactoryImpl<>());
|
||||
logHook("WorldGuard");
|
||||
} else {
|
||||
EventConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>());
|
||||
LootConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>());
|
||||
}
|
||||
if (this.isPluginEnabled("BetterModel")) {
|
||||
BetterModelUtils.registerConstantBlockEntityRender();
|
||||
logHook("BetterModel");
|
||||
}
|
||||
if (this.isPluginEnabled("ModelEngine")) {
|
||||
ModelEngineUtils.registerConstantBlockEntityRender();
|
||||
logHook("ModelEngine");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -249,6 +268,22 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
|
||||
itemManager.registerExternalItemSource(new CustomFishingSource());
|
||||
logHook("CustomFishing");
|
||||
}
|
||||
if (this.isPluginEnabled("Zaphkiel")) {
|
||||
itemManager.registerExternalItemSource(new ZaphkielSource());
|
||||
logHook("Zaphkiel");
|
||||
}
|
||||
if (this.isPluginEnabled("HeadDatabase")) {
|
||||
itemManager.registerExternalItemSource(new HeadDatabaseSource());
|
||||
logHook("HeadDatabase");
|
||||
}
|
||||
if (this.isPluginEnabled("SX-Item")) {
|
||||
itemManager.registerExternalItemSource(new SXItemSource());
|
||||
logHook("SX-Item");
|
||||
}
|
||||
if (this.isPluginEnabled("Slimefun")) {
|
||||
itemManager.registerExternalItemSource(new SlimefunSource());
|
||||
logHook("Slimefun");
|
||||
}
|
||||
}
|
||||
|
||||
private Plugin getPlugin(String name) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.item;
|
||||
|
||||
import me.arcaniax.hdb.api.HeadDatabaseAPI;
|
||||
import net.momirealms.craftengine.core.item.ExternalItemSource;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class HeadDatabaseSource implements ExternalItemSource<ItemStack> {
|
||||
private HeadDatabaseAPI api;
|
||||
|
||||
@Override
|
||||
public String plugin() {
|
||||
return "headdatabase";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemStack build(String id, ItemBuildContext context) {
|
||||
if (api == null) {
|
||||
api = new HeadDatabaseAPI();
|
||||
}
|
||||
return api.getItemHead(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id(ItemStack item) {
|
||||
if (api == null) {
|
||||
api = new HeadDatabaseAPI();
|
||||
}
|
||||
return api.getItemID(item);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,18 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.item;
|
||||
|
||||
import io.lumine.mythic.api.adapters.AbstractPlayer;
|
||||
import io.lumine.mythic.api.skills.SkillCaster;
|
||||
import io.lumine.mythic.bukkit.BukkitAdapter;
|
||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import io.lumine.mythic.core.drops.DropMetadataImpl;
|
||||
import net.momirealms.craftengine.core.item.ExternalItemSource;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class MythicMobsSource implements ExternalItemSource<ItemStack> {
|
||||
private MythicBukkit mythicBukkit;
|
||||
|
||||
@@ -20,7 +27,18 @@ public class MythicMobsSource implements ExternalItemSource<ItemStack> {
|
||||
if (mythicBukkit == null || mythicBukkit.isClosed()) {
|
||||
this.mythicBukkit = MythicBukkit.inst();
|
||||
}
|
||||
return mythicBukkit.getItemManager().getItemStack(id);
|
||||
return Optional.ofNullable(context.player())
|
||||
.map(p -> (Player) p.platformPlayer())
|
||||
.map(p -> {
|
||||
AbstractPlayer target = BukkitAdapter.adapt(p);
|
||||
SkillCaster caster = mythicBukkit.getSkillManager().getCaster(target);
|
||||
DropMetadataImpl meta = new DropMetadataImpl(caster, target);
|
||||
return mythicBukkit.getItemManager().getItem(id)
|
||||
.map(i -> i.generateItemStack(meta, 1))
|
||||
.map(BukkitAdapter::adapt)
|
||||
.orElse(null);
|
||||
})
|
||||
.orElseGet(() -> mythicBukkit.getItemManager().getItemStack(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.item;
|
||||
|
||||
import github.saukiya.sxitem.SXItem;
|
||||
import net.momirealms.craftengine.core.item.ExternalItemSource;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class SXItemSource implements ExternalItemSource<ItemStack> {
|
||||
|
||||
@Override
|
||||
public String plugin() {
|
||||
return "sx-item";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemStack build(String id, ItemBuildContext context) {
|
||||
return SXItem.getItemManager().getItem(id, Optional.ofNullable(context.player()).map(p -> (Player) p.platformPlayer()).orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id(ItemStack item) {
|
||||
return SXItem.getItemManager().getItemKey(item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.item;
|
||||
|
||||
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
|
||||
import net.momirealms.craftengine.core.item.ExternalItemSource;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class SlimefunSource implements ExternalItemSource<ItemStack> {
|
||||
|
||||
@Override
|
||||
public String plugin() {
|
||||
return "slimefun";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemStack build(String id, ItemBuildContext context) {
|
||||
return Optional.ofNullable(SlimefunItem.getById(id)).map(SlimefunItem::getItem).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id(ItemStack item) {
|
||||
return Optional.ofNullable(SlimefunItem.getByItem(item)).map(SlimefunItem::getId).orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.item;
|
||||
|
||||
import ink.ptms.zaphkiel.Zaphkiel;
|
||||
import net.momirealms.craftengine.core.item.ExternalItemSource;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author iiabc
|
||||
* @since 2025/8/30 09:39
|
||||
*/
|
||||
public class ZaphkielSource implements ExternalItemSource<ItemStack> {
|
||||
|
||||
@Override
|
||||
public String plugin() {
|
||||
return "zaphkiel";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ItemStack build(String id, ItemBuildContext context) {
|
||||
Player player = Optional.ofNullable(context.player()).map(it -> (Player) it.platformPlayer()).orElse(null);
|
||||
return Zaphkiel.INSTANCE.api().getItemManager().generateItemStack(id, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id(ItemStack item) {
|
||||
return Zaphkiel.INSTANCE.api().getItemHandler().getItemId(item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel;
|
||||
|
||||
import kr.toxicity.model.api.BetterModel;
|
||||
import kr.toxicity.model.api.data.renderer.ModelRenderer;
|
||||
import kr.toxicity.model.api.tracker.DummyTracker;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.bukkit.Location;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public class BetterModelBlockEntityElement implements BlockEntityElement {
|
||||
private DummyTracker dummyTracker;
|
||||
private final Location location;
|
||||
private final BetterModelBlockEntityElementConfig config;
|
||||
|
||||
public BetterModelBlockEntityElement(World world, BlockPos pos, BetterModelBlockEntityElementConfig config) {
|
||||
this.config = config;
|
||||
Vector3f position = config.position();
|
||||
this.location = new Location((org.bukkit.World) world.platformWorld(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z, config.yaw(), config.pitch());
|
||||
this.dummyTracker = createDummyTracker();
|
||||
}
|
||||
|
||||
private DummyTracker createDummyTracker() {
|
||||
ModelRenderer modelRenderer = BetterModel.plugin().modelManager().renderer(this.config.model());
|
||||
if (modelRenderer == null) {
|
||||
return null;
|
||||
} else {
|
||||
return modelRenderer.create(this.location);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(Player player) {
|
||||
if (this.dummyTracker != null) {
|
||||
this.dummyTracker.remove((org.bukkit.entity.Player) player.platformPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Player player) {
|
||||
if (this.dummyTracker != null) {
|
||||
this.dummyTracker.spawn((org.bukkit.entity.Player) player.platformPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
if (this.dummyTracker != null) {
|
||||
this.dummyTracker.close();
|
||||
this.dummyTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
if (this.dummyTracker == null) {
|
||||
this.dummyTracker = createDummyTracker();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel;
|
||||
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BetterModelBlockEntityElementConfig implements BlockEntityElementConfig<BetterModelBlockEntityElement> {
|
||||
private final Vector3f position;
|
||||
private final float yaw;
|
||||
private final float pitch;
|
||||
private final String model;
|
||||
|
||||
public BetterModelBlockEntityElementConfig(String model, Vector3f position, float yaw, float pitch) {
|
||||
this.pitch = pitch;
|
||||
this.position = position;
|
||||
this.yaw = yaw;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public String model() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public float pitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public Vector3f position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public float yaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BetterModelBlockEntityElement create(World world, BlockPos pos) {
|
||||
return new BetterModelBlockEntityElement(world, pos, this);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <E extends BlockEntityElement> BlockEntityElementConfig<E> create(Map<String, Object> arguments) {
|
||||
String model = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("model"), "warning.config.block.state.entity_renderer.better_model.missing_model");
|
||||
return (BlockEntityElementConfig<E>) new BetterModelBlockEntityElementConfig(
|
||||
model,
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel;
|
||||
|
||||
import kr.toxicity.model.api.BetterModel;
|
||||
import kr.toxicity.model.api.data.renderer.ModelRenderer;
|
||||
import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
public class BetterModelUtils {
|
||||
@@ -13,4 +15,8 @@ public class BetterModelUtils {
|
||||
}
|
||||
renderer.create(base);
|
||||
}
|
||||
|
||||
public static void registerConstantBlockEntityRender() {
|
||||
BukkitBlockEntityElementConfigs.register(Key.of("craftengine:better_model"), new BetterModelBlockEntityElementConfig.Factory());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.model.modelengine;
|
||||
|
||||
import com.ticxo.modelengine.api.ModelEngineAPI;
|
||||
import com.ticxo.modelengine.api.entity.Dummy;
|
||||
import com.ticxo.modelengine.api.model.ActiveModel;
|
||||
import com.ticxo.modelengine.api.model.ModeledEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.bukkit.Location;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
// TODO not tested yet
|
||||
public class ModelEngineBlockEntityElement implements BlockEntityElement {
|
||||
private Dummy<?> dummy;
|
||||
private final Location location;
|
||||
private final ModelEngineBlockEntityElementConfig config;
|
||||
|
||||
public ModelEngineBlockEntityElement(World world, BlockPos pos, ModelEngineBlockEntityElementConfig config) {
|
||||
this.config = config;
|
||||
Vector3f position = config.position();
|
||||
this.location = new Location((org.bukkit.World) world.platformWorld(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z, config.yaw(), config.pitch());
|
||||
this.dummy = createDummy();
|
||||
}
|
||||
|
||||
private Dummy<?> createDummy() {
|
||||
ActiveModel activeModel = ModelEngineAPI.createActiveModel(config.model());
|
||||
if (activeModel == null) {
|
||||
return null;
|
||||
} else {
|
||||
Dummy<?> dummy = new Dummy<>();
|
||||
dummy.setLocation(this.location);
|
||||
dummy.setDetectingPlayers(false);
|
||||
ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(dummy);
|
||||
modeledEntity.addModel(activeModel, false);
|
||||
return dummy;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(Player player) {
|
||||
if (this.dummy != null) {
|
||||
this.dummy.setForceViewing((org.bukkit.entity.Player) player.platformPlayer(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Player player) {
|
||||
if (this.dummy != null) {
|
||||
this.dummy.setForceHidden((org.bukkit.entity.Player) player.platformPlayer(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
if (this.dummy != null) {
|
||||
this.dummy.setRemoved(true);
|
||||
this.dummy = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
if (this.dummy == null) {
|
||||
this.dummy = createDummy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.model.modelengine;
|
||||
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ModelEngineBlockEntityElementConfig implements BlockEntityElementConfig<ModelEngineBlockEntityElement> {
|
||||
private final Vector3f position;
|
||||
private final float yaw;
|
||||
private final float pitch;
|
||||
private final String model;
|
||||
|
||||
public ModelEngineBlockEntityElementConfig(String model, Vector3f position, float yaw, float pitch) {
|
||||
this.pitch = pitch;
|
||||
this.position = position;
|
||||
this.yaw = yaw;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public String model() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public float pitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public Vector3f position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public float yaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelEngineBlockEntityElement create(World world, BlockPos pos) {
|
||||
return new ModelEngineBlockEntityElement(world, pos, this);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <E extends BlockEntityElement> BlockEntityElementConfig<E> create(Map<String, Object> arguments) {
|
||||
String model = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("model"), "warning.config.block.state.entity_renderer.model_engine.missing_model");
|
||||
return (BlockEntityElementConfig<E>) new ModelEngineBlockEntityElementConfig(
|
||||
model,
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.compatibility.model.modelengine;
|
||||
import com.ticxo.modelengine.api.ModelEngineAPI;
|
||||
import com.ticxo.modelengine.api.model.ActiveModel;
|
||||
import com.ticxo.modelengine.api.model.ModeledEntity;
|
||||
import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
public class ModelEngineUtils {
|
||||
@@ -24,4 +26,8 @@ public class ModelEngineUtils {
|
||||
}
|
||||
return entityId;
|
||||
}
|
||||
|
||||
public static void registerConstantBlockEntityRender() {
|
||||
BukkitBlockEntityElementConfigs.register(Key.of("craftengine:model_engine"), new ModelEngineBlockEntityElementConfig.Factory());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class MythicItemDrop extends ItemDrop implements IItemDrop {
|
||||
|
||||
@Override
|
||||
public AbstractItemStack getDrop(DropMetadata dropMetadata, double amount) {
|
||||
ItemBuildContext context = ItemBuildContext.EMPTY;
|
||||
ItemBuildContext context = ItemBuildContext.empty();
|
||||
SkillCaster caster = dropMetadata.getCaster();
|
||||
if (caster != null && caster.getEntity() instanceof AbstractPlayer abstractPlayer) {
|
||||
Entity bukkitEntity = abstractPlayer.getBukkitEntity();
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.region;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import net.momirealms.craftengine.core.plugin.context.Condition;
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class WorldGuardRegionCondition<CTX extends Context> implements Condition<CTX> {
|
||||
private static final Key TYPE = Key.of("worldguard:region");
|
||||
private final MatchMode mode;
|
||||
private final List<String> regions;
|
||||
|
||||
public WorldGuardRegionCondition(MatchMode mode, List<String> regions) {
|
||||
this.mode = mode;
|
||||
this.regions = regions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(CTX ctx) {
|
||||
if (this.regions.isEmpty()) return false;
|
||||
Optional<WorldPosition> optionalPos = ctx.getOptionalParameter(DirectContextParameters.POSITION);
|
||||
if (optionalPos.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
WorldPosition position = optionalPos.get();
|
||||
RegionManager regionManager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt((World) position.world().platformWorld()));
|
||||
if (regionManager != null) {
|
||||
ApplicableRegionSet set = regionManager.getApplicableRegions(BlockVector3.at(position.x(), position.y(), position.z()));
|
||||
List<String> regionsAtThisPos = new ArrayList<>(set.size());
|
||||
for (ProtectedRegion region : set) {
|
||||
String id = region.getId();
|
||||
regionsAtThisPos.add(id);
|
||||
}
|
||||
Predicate<String> predicate = regionsAtThisPos::contains;
|
||||
return this.mode.matcher.apply(predicate, this.regions);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public enum MatchMode {
|
||||
ANY((p, regions) -> {
|
||||
for (String region : regions) {
|
||||
if (p.test(region)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
ALL((p, regions) -> {
|
||||
for (String region : regions) {
|
||||
if (!p.test(region)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
private final BiFunction<Predicate<String>, List<String>, Boolean> matcher;
|
||||
|
||||
MatchMode(BiFunction<Predicate<String>, List<String>, Boolean> matcher) {
|
||||
this.matcher = matcher;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {
|
||||
|
||||
@Override
|
||||
public Condition<CTX> create(Map<String, Object> arguments) {
|
||||
int mode = ResourceConfigUtils.getAsInt(arguments.getOrDefault("mode", 1), "mode") - 1;
|
||||
MatchMode matchMode = MatchMode.values()[mode];
|
||||
List<String> regions = MiscUtils.getAsStringList(arguments.get("regions"));
|
||||
return new WorldGuardRegionCondition<>(matchMode, regions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ public class ExprCustomItem extends SimpleExpression<ItemType> {
|
||||
private Expression<?> itemIds;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, SkriptParser.ParseResult parseResult) {
|
||||
itemIds = exprs[0];
|
||||
return true;
|
||||
@@ -49,7 +48,7 @@ public class ExprCustomItem extends SimpleExpression<ItemType> {
|
||||
if (object instanceof String string) {
|
||||
CustomItem<ItemStack> customItem = CraftEngineItems.byId(Key.of(string));
|
||||
if (customItem != null) {
|
||||
ItemType itemType = new ItemType(customItem.buildItemStack(ItemBuildContext.EMPTY));
|
||||
ItemType itemType = new ItemType(customItem.buildItemStack(ItemBuildContext.empty()));
|
||||
items.add(itemType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public class WorldEditBlockRegister {
|
||||
if (state == null) return null;
|
||||
|
||||
try {
|
||||
String id = state.customBlockState().handle().toString();
|
||||
String id = state.customBlockState().literalObject().toString();
|
||||
int first = id.indexOf('{');
|
||||
int last = id.indexOf('}');
|
||||
if (first != -1 && last != -1 && last > first) {
|
||||
|
||||
@@ -21,6 +21,9 @@ dependencies {
|
||||
implementation(project(":bukkit:compatibility:legacy"))
|
||||
implementation(project(":common-files"))
|
||||
|
||||
// concurrentutil
|
||||
implementation(files("${rootProject.rootDir}/libs/concurrentutil-${rootProject.properties["concurrent_util_version"]}.jar"))
|
||||
|
||||
implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}")
|
||||
implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
|
||||
implementation("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}")
|
||||
@@ -47,7 +50,7 @@ bukkit {
|
||||
name = "CraftEngine"
|
||||
apiVersion = "1.20"
|
||||
authors = listOf("XiaoMoMi")
|
||||
contributors = listOf("jhqwqmc", "iqtesterrr", "WhiteProject1", "Catnies", "xiaozhangup", "TamashiiMon")
|
||||
contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors")
|
||||
softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit", "Skript")
|
||||
foliaSupported = true
|
||||
}
|
||||
@@ -77,5 +80,10 @@ tasks {
|
||||
relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs")
|
||||
relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons")
|
||||
relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref")
|
||||
relocate("ca.spottedleaf.concurrentutil", "net.momirealms.craftengine.libraries.concurrentutil")
|
||||
relocate("io.netty.handler.codec.http", "net.momirealms.craftengine.libraries.netty.handler.codec.http")
|
||||
relocate("io.netty.handler.codec.rtsp", "net.momirealms.craftengine.libraries.netty.handler.codec.rtsp")
|
||||
relocate("io.netty.handler.codec.spdy", "net.momirealms.craftengine.libraries.netty.handler.codec.spdy")
|
||||
relocate("io.netty.handler.codec.http2", "net.momirealms.craftengine.libraries.netty.handler.codec.http2")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ dependencies {
|
||||
implementation(project(":bukkit:compatibility:legacy"))
|
||||
implementation(project(":common-files"))
|
||||
|
||||
// concurrentutil
|
||||
implementation(files("${rootProject.rootDir}/libs/concurrentutil-${rootProject.properties["concurrent_util_version"]}.jar"))
|
||||
|
||||
implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}")
|
||||
implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
|
||||
implementation("net.momirealms:craft-engine-nms-helper-mojmap:${rootProject.properties["nms_helper_version"]}")
|
||||
@@ -50,7 +53,7 @@ paper {
|
||||
name = "CraftEngine"
|
||||
apiVersion = "1.20"
|
||||
authors = listOf("XiaoMoMi")
|
||||
contributors = listOf("jhqwqmc", "iqtesterrr", "WhiteProject1", "Catnies", "xiaozhangup", "TamashiiMon")
|
||||
contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors")
|
||||
foliaSupported = true
|
||||
serverDependencies {
|
||||
register("PlaceholderAPI") {
|
||||
@@ -82,6 +85,10 @@ paper {
|
||||
register("MMOItems") { required = false }
|
||||
register("MythicMobs") { required = false }
|
||||
register("CustomFishing") { required = false }
|
||||
register("Zaphkiel") { required = false }
|
||||
register("HeadDatabase") { required = false }
|
||||
register("SX-Item") { required = false }
|
||||
register("Slimefun") { required = false }
|
||||
|
||||
// leveler
|
||||
register("AuraSkills") { required = false }
|
||||
@@ -149,5 +156,10 @@ tasks {
|
||||
relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs")
|
||||
relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons")
|
||||
relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref")
|
||||
relocate("ca.spottedleaf.concurrentutil", "net.momirealms.craftengine.libraries.concurrentutil")
|
||||
relocate("io.netty.handler.codec.http", "net.momirealms.craftengine.libraries.netty.handler.codec.http")
|
||||
relocate("io.netty.handler.codec.rtsp", "net.momirealms.craftengine.libraries.netty.handler.codec.rtsp")
|
||||
relocate("io.netty.handler.codec.spdy", "net.momirealms.craftengine.libraries.netty.handler.codec.spdy")
|
||||
relocate("io.netty.handler.codec.http2", "net.momirealms.craftengine.libraries.netty.handler.codec.http2")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import io.papermc.paper.plugin.bootstrap.PluginBootstrap;
|
||||
import io.papermc.paper.plugin.bootstrap.PluginProviderContext;
|
||||
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents;
|
||||
import net.momirealms.craftengine.bukkit.plugin.agent.RuntimePatcher;
|
||||
import net.momirealms.craftengine.bukkit.plugin.classpath.PaperClassPathAppender;
|
||||
import net.momirealms.craftengine.bukkit.plugin.classpath.BukkitClassPathAppender;
|
||||
import net.momirealms.craftengine.bukkit.plugin.classpath.PaperPluginClassPathAppender;
|
||||
import net.momirealms.craftengine.core.plugin.logger.PluginLogger;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Slf4jPluginLogger;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -39,14 +39,24 @@ public class PaperCraftEngineBootstrap implements PluginBootstrap {
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Failed to getLogger", e);
|
||||
}
|
||||
this.plugin = new BukkitCraftEngine(
|
||||
logger,
|
||||
context.getDataDirectory(),
|
||||
new PaperClassPathAppender(this.getClass().getClassLoader())
|
||||
);
|
||||
try {
|
||||
this.plugin = new BukkitCraftEngine(
|
||||
logger,
|
||||
context.getDataDirectory(),
|
||||
new BukkitClassPathAppender(),
|
||||
new PaperPluginClassPathAppender(this.getClass().getClassLoader())
|
||||
);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
this.plugin = new BukkitCraftEngine(
|
||||
logger,
|
||||
context.getDataDirectory(),
|
||||
new PaperPluginClassPathAppender(this.getClass().getClassLoader()),
|
||||
new PaperPluginClassPathAppender(this.getClass().getClassLoader())
|
||||
);
|
||||
}
|
||||
this.plugin.applyDependencies();
|
||||
this.plugin.setUpConfig();
|
||||
if (VersionHelper.isOrAbove1_21_4()) {
|
||||
if (isDatapackDiscoveryAvailable()) {
|
||||
new ModernEventHandler(context, this.plugin).register();
|
||||
} else {
|
||||
try {
|
||||
@@ -58,6 +68,16 @@ public class PaperCraftEngineBootstrap implements PluginBootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDatapackDiscoveryAvailable() {
|
||||
try {
|
||||
Class<?> eventsClass = Class.forName("io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents");
|
||||
eventsClass.getField("DATAPACK_DISCOVERY");
|
||||
return true;
|
||||
} catch (ClassNotFoundException | NoSuchFieldException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull JavaPlugin createPlugin(@NotNull PluginProviderContext context) {
|
||||
return new PaperCraftEnginePlugin(this);
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
package net.momirealms.craftengine.bukkit.advancement;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.advancement.AbstractAdvancementManager;
|
||||
import net.momirealms.craftengine.core.advancement.AdvancementType;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
public class BukkitAdvancementManager extends AbstractAdvancementManager {
|
||||
private final BukkitCraftEngine plugin;
|
||||
@@ -33,6 +41,70 @@ public class BukkitAdvancementManager extends AbstractAdvancementManager {
|
||||
return this.advancementParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToast(Player player, Item<?> icon, Component message, AdvancementType type) {
|
||||
try {
|
||||
Object displayInfo = CoreReflections.constructor$DisplayInfo.newInstance(
|
||||
icon.getLiteralObject(),
|
||||
ComponentUtils.adventureToMinecraft(message), // title
|
||||
CoreReflections.instance$Component$empty, // description
|
||||
VersionHelper.isOrAbove1_20_3() ? Optional.empty() : null, // background
|
||||
CoreReflections.instance$AdvancementType$values[type.ordinal()],
|
||||
true, // show toast
|
||||
false, // announce to chat
|
||||
true // hidden
|
||||
);
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
displayInfo = Optional.of(displayInfo);
|
||||
}
|
||||
Object resourceLocation = KeyUtils.toResourceLocation(Key.of("craftengine", "toast"));
|
||||
Object criterion = VersionHelper.isOrAbove1_20_2() ?
|
||||
CoreReflections.constructor$Criterion.newInstance(CoreReflections.constructor$ImpossibleTrigger.newInstance(), CoreReflections.constructor$ImpossibleTrigger$TriggerInstance.newInstance()) :
|
||||
CoreReflections.constructor$Criterion.newInstance(CoreReflections.constructor$ImpossibleTrigger$TriggerInstance.newInstance());
|
||||
Map<String, Object> criteria = Map.of("impossible", criterion);
|
||||
Object advancementProgress = CoreReflections.constructor$AdvancementProgress.newInstance();
|
||||
Object advancement;
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
Object advancementRequirements = VersionHelper.isOrAbove1_20_3() ?
|
||||
CoreReflections.constructor$AdvancementRequirements.newInstance(List.of(List.of("impossible"))) :
|
||||
CoreReflections.constructor$AdvancementRequirements.newInstance((Object) new String[][] {{"impossible"}});
|
||||
advancement = CoreReflections.constructor$Advancement.newInstance(
|
||||
Optional.empty(),
|
||||
displayInfo,
|
||||
CoreReflections.instance$AdvancementRewards$EMPTY,
|
||||
criteria,
|
||||
advancementRequirements,
|
||||
false
|
||||
);
|
||||
CoreReflections.method$AdvancementProgress$update.invoke(advancementProgress, advancementRequirements);
|
||||
advancement = CoreReflections.constructor$AdvancementHolder.newInstance(resourceLocation, advancement);
|
||||
} else {
|
||||
advancement = CoreReflections.constructor$Advancement.newInstance(
|
||||
resourceLocation,
|
||||
null, // parent
|
||||
displayInfo,
|
||||
CoreReflections.instance$AdvancementRewards$EMPTY,
|
||||
criteria,
|
||||
new String[][] {{"impossible"}},
|
||||
false
|
||||
);
|
||||
CoreReflections.method$AdvancementProgress$update.invoke(advancementProgress, criteria, new String[][] {{"impossible"}});
|
||||
}
|
||||
CoreReflections.method$AdvancementProgress$grantProgress.invoke(advancementProgress, "impossible");
|
||||
Map<Object, Object> advancementsToGrant = new HashMap<>();
|
||||
advancementsToGrant.put(resourceLocation, advancementProgress);
|
||||
Object grantPacket = VersionHelper.isOrAbove1_21_5() ?
|
||||
NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, Arrays.asList(advancement), new HashSet<>(), advancementsToGrant, true) :
|
||||
NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, Arrays.asList(advancement), new HashSet<>(), advancementsToGrant);
|
||||
Object removePacket = VersionHelper.isOrAbove1_21_5() ?
|
||||
NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, new ArrayList<>(), new HashSet<>() {{add(resourceLocation);}}, new HashMap<>(), true) :
|
||||
NetworkReflections.constructor$ClientboundUpdateAdvancementsPacket.newInstance(false, new ArrayList<>(), new HashSet<>() {{add(resourceLocation);}}, new HashMap<>());
|
||||
player.sendPackets(List.of(grantPacket, removePacket), false);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
this.plugin.logger().warn("Failed to send toast for player " + player.name(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public class AdvancementParser implements ConfigParser {
|
||||
public static final String[] CONFIG_SECTION_NAME = new String[] {"advancements", "advancement"};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.Location;
|
||||
@@ -29,8 +29,8 @@ public final class BukkitAdaptors {
|
||||
return new BukkitEntity(entity);
|
||||
}
|
||||
|
||||
public static BukkitBlockInWorld adapt(final Block block) {
|
||||
return new BukkitBlockInWorld(block);
|
||||
public static BukkitExistingBlock adapt(final Block block) {
|
||||
return new BukkitExistingBlock(block);
|
||||
}
|
||||
|
||||
public static Location toLocation(WorldPosition position) {
|
||||
|
||||
@@ -27,10 +27,28 @@ import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public final class CraftEngineBlocks {
|
||||
|
||||
private CraftEngineBlocks() {}
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns an unmodifiable map of all currently loaded custom blocks.
|
||||
* The map keys represent unique identifiers, and the values are the corresponding CustomBlock instances.
|
||||
*
|
||||
* <p><strong>Important:</strong> Do not attempt to access this method during the onEnable phase
|
||||
* as it will be empty. Instead, listen for the {@code CraftEngineReloadEvent} and use this method
|
||||
* after the event is fired to obtain the complete block list.
|
||||
*
|
||||
* @return a non-null map containing all loaded custom blocks
|
||||
*/
|
||||
@NotNull
|
||||
public static Map<Key, CustomBlock> loadedBlocks() {
|
||||
return BukkitBlockManager.instance().loadedBlocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom block by ID
|
||||
*
|
||||
@@ -126,7 +144,7 @@ public final class CraftEngineBlocks {
|
||||
boolean success;
|
||||
Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld());
|
||||
Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
||||
Object blockState = block.customBlockState().handle();
|
||||
Object blockState = block.customBlockState().literalObject();
|
||||
Object oldBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos);
|
||||
success = FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState, option.flags());
|
||||
if (success) {
|
||||
@@ -188,9 +206,10 @@ public final class CraftEngineBlocks {
|
||||
if (dropLoot) {
|
||||
ContextHolder.Builder builder = new ContextHolder.Builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
BukkitServerPlayer serverPlayer = BukkitCraftEngine.instance().adapt(player);
|
||||
BukkitServerPlayer serverPlayer = null;
|
||||
if (player != null) {
|
||||
builder.withParameter(DirectContextParameters.PLAYER, serverPlayer);
|
||||
serverPlayer = BukkitCraftEngine.instance().adapt(player);
|
||||
builder.withOptionalParameter(DirectContextParameters.PLAYER, serverPlayer);
|
||||
}
|
||||
for (Item<?> item : state.getDrops(builder, world, serverPlayer)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
@@ -249,6 +268,6 @@ public final class CraftEngineBlocks {
|
||||
*/
|
||||
@NotNull
|
||||
public static BlockData getBukkitBlockData(@NotNull ImmutableBlockState blockState) {
|
||||
return BlockStateUtils.fromBlockData(blockState.customBlockState().handle());
|
||||
return BlockStateUtils.fromBlockData(blockState.customBlockState().literalObject());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,11 +27,27 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class CraftEngineFurniture {
|
||||
|
||||
private CraftEngineFurniture() {}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of all currently loaded custom furniture.
|
||||
* The map keys represent unique identifiers, and the values are the corresponding CustomFurniture instances.
|
||||
*
|
||||
* <p><strong>Important:</strong> Do not attempt to access this method during the onEnable phase
|
||||
* as it will be empty. Instead, listen for the {@code CraftEngineReloadEvent} and use this method
|
||||
* after the event is fired to obtain the complete furniture list.
|
||||
*
|
||||
* @return a non-null map containing all loaded custom furniture
|
||||
*/
|
||||
@NotNull
|
||||
public static Map<Key, CustomFurniture> loadedFurniture() {
|
||||
return BukkitFurnitureManager.instance().loadedFurniture();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets custom furniture by ID
|
||||
*
|
||||
|
||||
@@ -8,10 +8,28 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public final class CraftEngineItems {
|
||||
|
||||
private CraftEngineItems() {}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of all currently loaded custom items.
|
||||
* The map keys represent unique identifiers, and the values are the corresponding CustomItem instances.
|
||||
*
|
||||
* <p><strong>Important:</strong> Do not attempt to access this method during the onEnable phase
|
||||
* as it will be empty. Instead, listen for the {@code CraftEngineReloadEvent} and use this method
|
||||
* after the event is fired to obtain the complete item list.
|
||||
*
|
||||
* @return a non-null map containing all loaded custom items
|
||||
* @throws IllegalStateException if the BukkitItemManager instance is not available
|
||||
*/
|
||||
@NotNull
|
||||
public static Map<Key, CustomItem<ItemStack>> loadedItems() {
|
||||
return BukkitItemManager.instance().loadedItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom item by ID
|
||||
*
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package net.momirealms.craftengine.bukkit.api.event;
|
||||
|
||||
import net.momirealms.craftengine.core.pack.PackCacheData;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* This event is triggered when a user executes the "/ce reload pack" command.
|
||||
* <p>
|
||||
* The event initiates a process that caches all resource content into a virtual file system
|
||||
* to ensure optimal build performance. To add your resource pack through this event,
|
||||
* you must use the {@link #registerExternalResourcePack(Path)} method every time this event is called.
|
||||
* </p>
|
||||
* <p>
|
||||
* Important: The caching system will not update your resource pack if its file size or
|
||||
* last modification time remains unchanged between reloads. Ensure these attributes change
|
||||
* if you need the cache to recognize updates.
|
||||
* </p>
|
||||
*/
|
||||
public class AsyncResourcePackCacheEvent extends Event {
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
private final PackCacheData cacheData;
|
||||
|
||||
public AsyncResourcePackCacheEvent(@NotNull PackCacheData cacheData) {
|
||||
super(true);
|
||||
this.cacheData = cacheData;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PackCacheData cacheData() {
|
||||
return this.cacheData;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public HandlerList getHandlers() {
|
||||
return getHandlerList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an external resource pack to the cache.
|
||||
* <p>
|
||||
* This method accepts either a .zip file or a directory path representing a resource pack.
|
||||
* The resource pack will be added to the appropriate cache collection based on its type.
|
||||
* </p>
|
||||
*
|
||||
* @param path the file system path to the resource pack. Must be either a .zip file or a directory.
|
||||
* @throws IllegalArgumentException if the provided path is neither a .zip file nor a directory.
|
||||
*/
|
||||
public void registerExternalResourcePack(@NotNull final Path path) {
|
||||
if (Files.isRegularFile(path) && path.getFileName().endsWith(".zip")) {
|
||||
this.cacheData.externalZips().add(path);
|
||||
} else if (Files.isDirectory(path)) {
|
||||
this.cacheData.externalFolders().add(path);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal resource pack path: " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,17 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class CraftEngineReloadEvent extends Event {
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
private final BukkitCraftEngine plugin;
|
||||
private static boolean firstFlag = true;
|
||||
private final boolean isFirstReload;
|
||||
|
||||
public CraftEngineReloadEvent(BukkitCraftEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
this.isFirstReload = firstFlag;
|
||||
firstFlag = false;
|
||||
}
|
||||
|
||||
public boolean isFirstReload() {
|
||||
return this.isFirstReload;
|
||||
}
|
||||
|
||||
public BukkitCraftEngine plugin() {
|
||||
|
||||
@@ -9,7 +9,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
@@ -82,7 +82,7 @@ public final class BlockEventListener implements Listener {
|
||||
try {
|
||||
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
|
||||
Object placeSound = CoreReflections.field$SoundType$placeSound.get(soundType);
|
||||
player.playSound(block.getLocation(), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
|
||||
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
this.plugin.logger().warn("Failed to get sound type", e);
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public final class BlockEventListener implements Listener {
|
||||
Object ownerBlock = BlockStateUtils.getBlockOwner(blockState);
|
||||
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
|
||||
Object placeSound = CoreReflections.field$SoundType$placeSound.get(soundType);
|
||||
player.playSound(block.getLocation(), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
|
||||
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
this.plugin.logger().warn("Failed to get sound type", e);
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public final class BlockEventListener implements Listener {
|
||||
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
|
||||
optionalCustomItem.get().execute(
|
||||
PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.PLAYER, serverPlayer)
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
@@ -156,7 +156,7 @@ public final class BlockEventListener implements Listener {
|
||||
// execute functions
|
||||
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
|
||||
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state)
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
@@ -174,12 +174,15 @@ public final class BlockEventListener implements Listener {
|
||||
// override vanilla block loots
|
||||
if (player.getGameMode() != GameMode.CREATIVE) {
|
||||
this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> {
|
||||
if (!event.isDropItems()) {
|
||||
return;
|
||||
}
|
||||
if (it.override()) {
|
||||
event.setDropItems(false);
|
||||
event.setExpToDrop(0);
|
||||
}
|
||||
ContextHolder lootContext = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.PLAYER, serverPlayer)
|
||||
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand).build();
|
||||
@@ -198,7 +201,7 @@ public final class BlockEventListener implements Listener {
|
||||
try {
|
||||
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
|
||||
Object breakSound = CoreReflections.field$SoundType$breakSound.get(soundType);
|
||||
block.getWorld().playSound(block.getLocation(), FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
|
||||
block.getWorld().playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
this.plugin.logger().warn("Failed to get sound type", e);
|
||||
}
|
||||
@@ -224,7 +227,7 @@ public final class BlockEventListener implements Listener {
|
||||
WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5);
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block));
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block));
|
||||
for (LootTable<?> lootTable : it.lootTables()) {
|
||||
for (Item<?> item : lootTable.getRandomItems(builder.build(), world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
@@ -250,7 +253,7 @@ public final class BlockEventListener implements Listener {
|
||||
state.owner().value().execute(PlayerOptionalContext.of(BukkitAdaptors.adapt(player), ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.POSITION, new WorldPosition(new BukkitWorld(event.getWorld()), LocationUtils.toVec3d(location)))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
|
||||
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state)
|
||||
), EventTrigger.STEP);
|
||||
if (cancellable.isCancelled()) {
|
||||
|
||||
@@ -76,7 +76,6 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
private List<Key> blockRegisterOrder = new ObjectArrayList<>();
|
||||
// Event listeners
|
||||
private BlockEventListener blockEventListener;
|
||||
private FallingBlockRemoveListener fallingBlockRemoveListener;
|
||||
// cached tag packet
|
||||
private Object cachedUpdateTagsPacket;
|
||||
|
||||
@@ -101,7 +100,6 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
if (enableNoteBlocks) {
|
||||
this.recordVanillaNoteBlocks();
|
||||
}
|
||||
this.fallingBlockRemoveListener = VersionHelper.isOrAbove1_20_3() ? new FallingBlockRemoveListener() : null;
|
||||
this.stateId2ImmutableBlockStates = new ImmutableBlockState[this.customBlockCount];
|
||||
Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.INSTANCE.defaultState());
|
||||
this.resetPacketConsumers();
|
||||
@@ -123,9 +121,6 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
@Override
|
||||
public void delayedInit() {
|
||||
Bukkit.getPluginManager().registerEvents(this.blockEventListener, this.plugin.javaPlugin());
|
||||
if (this.fallingBlockRemoveListener != null) {
|
||||
Bukkit.getPluginManager().registerEvents(this.fallingBlockRemoveListener, this.plugin.javaPlugin());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,7 +140,6 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
public void disable() {
|
||||
this.unload();
|
||||
HandlerList.unregisterAll(this.blockEventListener);
|
||||
if (this.fallingBlockRemoveListener != null) HandlerList.unregisterAll(this.fallingBlockRemoveListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -181,14 +175,14 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockStateWrapper createPackedBlockState(String blockState) {
|
||||
public BlockStateWrapper createBlockState(String blockState) {
|
||||
ImmutableBlockState state = BlockStateParser.deserialize(blockState);
|
||||
if (state != null) {
|
||||
return state.customBlockState();
|
||||
}
|
||||
try {
|
||||
BlockData blockData = Bukkit.createBlockData(blockState);
|
||||
return BlockStateUtils.toPackedBlockState(blockData);
|
||||
return BlockStateUtils.toBlockStateWrapper(blockData);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
@@ -220,7 +214,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
for (ImmutableBlockState state : customBlock.variantProvider().states()) {
|
||||
ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()];
|
||||
if (previous != null && !previous.isEmpty()) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.bind_failed", state.toString(), previous.toString());
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.bind_failed", state.toString(), previous.toString(), BlockStateUtils.getBlockOwnerIdFromState(previous.customBlockState().literalObject()).toString());
|
||||
}
|
||||
this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state;
|
||||
this.tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId());
|
||||
@@ -231,7 +225,7 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
@Override
|
||||
public Key getBlockOwnerId(BlockStateWrapper state) {
|
||||
return BlockStateUtils.getBlockOwnerIdFromState(state.handle());
|
||||
return BlockStateUtils.getBlockOwnerIdFromState(state.literalObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -258,9 +252,9 @@ public final class BukkitBlockManager extends AbstractBlockManager {
|
||||
int size = RegistryUtils.currentBlockRegistrySize();
|
||||
BlockStateWrapper[] states = new BlockStateWrapper[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
states[i] = BlockStateWrapper.create(BlockStateUtils.idToBlockState(i), i, BlockStateUtils.isVanillaBlock(i));
|
||||
states[i] = new BukkitBlockStateWrapper(BlockStateUtils.idToBlockState(i), i);
|
||||
}
|
||||
BlockRegistryMirror.init(states, BlockStateWrapper.vanilla(MBlocks.STONE$defaultState, BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState)));
|
||||
BlockRegistryMirror.init(states, new BukkitBlockStateWrapper(MBlocks.STONE$defaultState, BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState)));
|
||||
}
|
||||
|
||||
private void registerEmptyBlock() {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.momirealms.craftengine.bukkit.block;
|
||||
|
||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||
|
||||
public class BukkitBlockStateWrapper implements BlockStateWrapper {
|
||||
private final Object blockState;
|
||||
private final int registryId;
|
||||
|
||||
public BukkitBlockStateWrapper(Object blockState, int registryId) {
|
||||
this.blockState = blockState;
|
||||
this.registryId = registryId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object literalObject() {
|
||||
return this.blockState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int registryId() {
|
||||
return this.registryId;
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
@NotNull Key id,
|
||||
@NotNull Holder.Reference<CustomBlock> holder,
|
||||
@NotNull Map<String, Property<?>> properties,
|
||||
@NotNull Map<String, Integer> appearances,
|
||||
@NotNull Map<String, BlockStateAppearance> appearances,
|
||||
@NotNull Map<String, BlockStateVariant> variantMapper,
|
||||
@NotNull BlockSettings settings,
|
||||
@NotNull Map<EventTrigger, List<Function<PlayerOptionalContext>>> events,
|
||||
@@ -76,13 +76,13 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
try {
|
||||
for (ImmutableBlockState immutableBlockState : variantProvider().states()) {
|
||||
if (immutableBlockState.vanillaBlockState() == null) {
|
||||
CraftEngine.instance().logger().warn("Could not find vanilla block immutableBlockState for " + immutableBlockState + ". This might cause errors!");
|
||||
CraftEngine.instance().logger().warn("Could not find vanilla visual block state for " + immutableBlockState + ". This might cause errors!");
|
||||
continue;
|
||||
} else if (immutableBlockState.customBlockState() == null) {
|
||||
CraftEngine.instance().logger().warn("Could not find custom block immutableBlockState for " + immutableBlockState + ". This might cause errors!");
|
||||
CraftEngine.instance().logger().warn("Could not find real block state for " + immutableBlockState + ". This might cause errors!");
|
||||
continue;
|
||||
}
|
||||
DelegatingBlockState nmsState = (DelegatingBlockState) immutableBlockState.customBlockState().handle();
|
||||
DelegatingBlockState nmsState = (DelegatingBlockState) immutableBlockState.customBlockState().literalObject();
|
||||
nmsState.setBlockState(immutableBlockState);
|
||||
BlockSettings settings = immutableBlockState.settings();
|
||||
|
||||
@@ -98,10 +98,10 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
Object pushReaction = ((Object[]) CoreReflections.method$PushReaction$values.invoke(null))[settings.pushReaction().ordinal()];
|
||||
CoreReflections.field$BlockStateBase$pushReaction.set(nmsState, pushReaction);
|
||||
|
||||
boolean canOcclude = settings.canOcclude() == Tristate.UNDEFINED ? BlockStateUtils.isOcclude(immutableBlockState.vanillaBlockState().handle()) : settings.canOcclude().asBoolean();
|
||||
boolean canOcclude = settings.canOcclude() == Tristate.UNDEFINED ? BlockStateUtils.isOcclude(immutableBlockState.vanillaBlockState().literalObject()) : settings.canOcclude().asBoolean();
|
||||
CoreReflections.field$BlockStateBase$canOcclude.set(nmsState, canOcclude);
|
||||
|
||||
boolean useShapeForLightOcclusion = settings.useShapeForLightOcclusion() == Tristate.UNDEFINED ? CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.getBoolean(immutableBlockState.vanillaBlockState().handle()) : settings.useShapeForLightOcclusion().asBoolean();
|
||||
boolean useShapeForLightOcclusion = settings.useShapeForLightOcclusion() == Tristate.UNDEFINED ? CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.getBoolean(immutableBlockState.vanillaBlockState().literalObject()) : settings.useShapeForLightOcclusion().asBoolean();
|
||||
CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.set(nmsState, useShapeForLightOcclusion);
|
||||
|
||||
CoreReflections.field$BlockStateBase$isRedstoneConductor.set(nmsState, settings.isRedstoneConductor().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE);
|
||||
@@ -111,7 +111,7 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
// set parent block properties
|
||||
DelegatingBlock nmsBlock = (DelegatingBlock) BlockStateUtils.getBlockOwner(nmsState);
|
||||
ObjectHolder<BlockShape> shapeHolder = nmsBlock.shapeDelegate();
|
||||
shapeHolder.bindValue(new BukkitBlockShape(immutableBlockState.vanillaBlockState().handle(), Optional.ofNullable(immutableBlockState.settings().supportShapeBlockState()).map(it -> {
|
||||
shapeHolder.bindValue(new BukkitBlockShape(immutableBlockState.vanillaBlockState().literalObject(), Optional.ofNullable(immutableBlockState.settings().supportShapeBlockState()).map(it -> {
|
||||
try {
|
||||
Object blockState = BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(it));
|
||||
if (!BlockStateUtils.isVanillaBlock(blockState)) {
|
||||
@@ -128,6 +128,9 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
behaviorHolder.bindValue(super.behavior);
|
||||
// set block side properties
|
||||
CoreReflections.field$BlockBehaviour$explosionResistance.set(nmsBlock, settings.resistance());
|
||||
CoreReflections.field$BlockBehaviour$friction.set(nmsBlock, settings.friction());
|
||||
CoreReflections.field$BlockBehaviour$speedFactor.set(nmsBlock, settings.speedFactor());
|
||||
CoreReflections.field$BlockBehaviour$jumpFactor.set(nmsBlock, settings.jumpFactor());
|
||||
CoreReflections.field$BlockBehaviour$soundType.set(nmsBlock, SoundUtils.toSoundType(settings.sounds()));
|
||||
// init cache
|
||||
CoreReflections.method$BlockStateBase$initCache.invoke(nmsState);
|
||||
@@ -137,7 +140,7 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
}
|
||||
// modify cache
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(immutableBlockState.vanillaBlockState().handle());
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(immutableBlockState.vanillaBlockState().literalObject());
|
||||
// set block light
|
||||
CoreReflections.field$BlockStateBase$lightBlock.set(nmsState, blockLight);
|
||||
// set propagates skylight
|
||||
@@ -146,11 +149,11 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
} else if (settings.propagatesSkylightDown() == Tristate.FALSE) {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, false);
|
||||
} else {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(immutableBlockState.vanillaBlockState().handle()));
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(immutableBlockState.vanillaBlockState().literalObject()));
|
||||
}
|
||||
} else {
|
||||
Object cache = CoreReflections.field$BlockStateBase$cache.get(nmsState);
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().handle()));
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().literalObject()));
|
||||
// set block light
|
||||
CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, blockLight);
|
||||
// set propagates skylight
|
||||
@@ -159,7 +162,7 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
} else if (settings.propagatesSkylightDown() == Tristate.FALSE) {
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, false);
|
||||
} else {
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().handle())));
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().literalObject())));
|
||||
}
|
||||
if (!isConditionallyFullOpaque) {
|
||||
CoreReflections.field$BlockStateBase$opacityIfCached.set(nmsState, blockLight);
|
||||
@@ -197,7 +200,7 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
public static class BuilderImpl implements Builder {
|
||||
protected final Key id;
|
||||
protected Map<String, Property<?>> properties;
|
||||
protected Map<String, Integer> appearances;
|
||||
protected Map<String, BlockStateAppearance> appearances;
|
||||
protected Map<String, BlockStateVariant> variantMapper;
|
||||
protected BlockSettings settings;
|
||||
protected List<Map<String, Object>> behavior;
|
||||
@@ -215,7 +218,7 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder appearances(Map<String, Integer> appearances) {
|
||||
public Builder appearances(Map<String, BlockStateAppearance> appearances) {
|
||||
this.appearances = appearances;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
package net.momirealms.craftengine.bukkit.block;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public final class FallingBlockRemoveListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onFallingBlockBreak(org.bukkit.event.entity.EntityRemoveEvent event) {
|
||||
if (event.getCause() == org.bukkit.event.entity.EntityRemoveEvent.Cause.DROP && event.getEntity() instanceof FallingBlock fallingBlock) {
|
||||
try {
|
||||
Object fallingBlockEntity = CraftBukkitReflections.field$CraftEntity$entity.get(fallingBlock);
|
||||
boolean cancelDrop = (boolean) CoreReflections.field$FallingBlockEntity$cancelDrop.get(fallingBlockEntity);
|
||||
if (cancelDrop) return;
|
||||
Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(fallingBlock.getWorld());
|
||||
WorldPosition position = new WorldPosition(world, CoreReflections.field$Entity$xo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$yo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$zo.getDouble(fallingBlockEntity));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FALLING_BLOCK, true)
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : customState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlockEntity);
|
||||
boolean isSilent = (boolean) CoreReflections.method$SynchedEntityData$get.invoke(entityData, CoreReflections.instance$Entity$DATA_SILENT);
|
||||
if (!isSilent) {
|
||||
world.playBlockSound(position, customState.settings().sounds().destroySound());
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle EntityRemoveEvent", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.behavior.special.FallOnBlockBehavior;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class BouncingBlockBehavior extends BukkitBlockBehavior implements FallOnBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final double bounceHeight;
|
||||
private final boolean syncPlayerPosition;
|
||||
private final double fallDamageMultiplier;
|
||||
|
||||
public BouncingBlockBehavior(CustomBlock customBlock, double bounceHeight, boolean syncPlayerPosition, double fallDamageMultiplier) {
|
||||
super(customBlock);
|
||||
this.bounceHeight = bounceHeight;
|
||||
this.syncPlayerPosition = syncPlayerPosition;
|
||||
this.fallDamageMultiplier = fallDamageMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.fallDamageMultiplier <= 0.0) return;
|
||||
Object entity = args[3];
|
||||
Number fallDistance = (Number) args[4];
|
||||
FastNMS.INSTANCE.method$Entity$causeFallDamage(
|
||||
entity, fallDistance.doubleValue() * this.fallDamageMultiplier, 1.0F,
|
||||
FastNMS.INSTANCE.method$DamageSources$fall(FastNMS.INSTANCE.method$Entity$damageSources(entity))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntityMovementAfterFallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object entity = args[1];
|
||||
if (FastNMS.INSTANCE.method$Entity$getSharedFlag(entity, 1)) {
|
||||
superMethod.call();
|
||||
} else {
|
||||
bounceUp(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void bounceUp(Object entity) {
|
||||
Vec3d deltaMovement = LocationUtils.fromVec(FastNMS.INSTANCE.method$Entity$getDeltaMovement(entity));
|
||||
if (deltaMovement.y < 0.0) {
|
||||
double d = CoreReflections.clazz$LivingEntity.isInstance(entity) ? 1.0 : 0.8;
|
||||
double y = -deltaMovement.y * this.bounceHeight * d;
|
||||
FastNMS.INSTANCE.method$Entity$setDeltaMovement(entity, deltaMovement.x, y, deltaMovement.z);
|
||||
if (CoreReflections.clazz$Player.isInstance(entity) && this.syncPlayerPosition
|
||||
&& /* 防抖 -> */ y > 0.035 /* <- 防抖 */
|
||||
) {
|
||||
// 这里一定要延迟 1t 不然就会出问题
|
||||
if (VersionHelper.isFolia()) {
|
||||
Entity bukkitEntity = FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity);
|
||||
bukkitEntity.getScheduler().runDelayed(BukkitCraftEngine.instance().javaPlugin(),
|
||||
r -> FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true),
|
||||
null, 1L
|
||||
);
|
||||
} else {
|
||||
CraftEngine.instance().scheduler().sync().runLater(
|
||||
() -> FastNMS.INSTANCE.field$Entity$hurtMarked(entity, true),
|
||||
1L
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
double bounceHeight = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("bounce-height", 0.66), "bounce-height");
|
||||
boolean syncPlayerPosition = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("sync-player-position", true), "sync-player-position");
|
||||
double fallDamageMultiplier = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("fall-damage-multiplier", 0.5), "fall-damage-multiplier");
|
||||
return new BouncingBlockBehavior(block, bounceHeight, syncPlayerPosition, fallDamageMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,11 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
Direction.Axis axis = blockState.get(axisProperty);
|
||||
return switch (rotation) {
|
||||
case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> switch (axis) {
|
||||
case X -> blockState.with(axisProperty, Direction.Axis.Z).customBlockState().handle();
|
||||
case Z -> blockState.with(axisProperty, Direction.Axis.X).customBlockState().handle();
|
||||
default -> blockState.customBlockState().handle();
|
||||
case X -> blockState.with(axisProperty, Direction.Axis.Z).customBlockState().literalObject();
|
||||
case Z -> blockState.with(axisProperty, Direction.Axis.X).customBlockState().literalObject();
|
||||
default -> blockState.customBlockState().literalObject();
|
||||
};
|
||||
default -> blockState.customBlockState().handle();
|
||||
default -> blockState.customBlockState().literalObject();
|
||||
};
|
||||
};
|
||||
});
|
||||
@@ -45,7 +45,7 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
Property<HorizontalDirection> directionProperty = (Property<HorizontalDirection>) property;
|
||||
behavior.rotateFunction = (thisBlock, blockState, rotation) ->
|
||||
blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty).toDirection()).toHorizontalDirection())
|
||||
.customBlockState().handle();
|
||||
.customBlockState().literalObject();
|
||||
behavior.mirrorFunction = (thisBlock, blockState, mirror) -> {
|
||||
Rotation rotation = mirror.getRotation(blockState.get(directionProperty).toDirection());
|
||||
return behavior.rotateFunction.rotate(thisBlock, blockState, rotation);
|
||||
@@ -55,7 +55,7 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
Property<Direction> directionProperty = (Property<Direction>) property;
|
||||
behavior.rotateFunction = (thisBlock, blockState, rotation) ->
|
||||
blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty)))
|
||||
.customBlockState().handle();
|
||||
.customBlockState().literalObject();
|
||||
behavior.mirrorFunction = (thisBlock, blockState, mirror) -> {
|
||||
Rotation rotation = mirror.getRotation(blockState.get(directionProperty));
|
||||
return behavior.rotateFunction.rotate(thisBlock, blockState, rotation);
|
||||
@@ -68,7 +68,7 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
Property<HorizontalDirection> directionProperty = (Property<HorizontalDirection>) property;
|
||||
behavior.rotateFunction = (thisBlock, blockState, rotation) ->
|
||||
blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty).toDirection()).toHorizontalDirection())
|
||||
.customBlockState().handle();
|
||||
.customBlockState().literalObject();
|
||||
behavior.mirrorFunction = (thisBlock, blockState, mirror) -> {
|
||||
Rotation rotation = mirror.getRotation(blockState.get(directionProperty).toDirection());
|
||||
return behavior.rotateFunction.rotate(thisBlock, blockState, rotation);
|
||||
@@ -139,7 +139,7 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
if (optionalCustomState.isEmpty()) return CoreReflections.instance$ItemStack$EMPTY;
|
||||
ImmutableBlockState immutableBlockState = optionalCustomState.get();
|
||||
if (immutableBlockState.get(this.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, pos, immutableBlockState.with(this.waterloggedProperty, false).customBlockState().handle(), 3);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, pos, immutableBlockState.with(this.waterloggedProperty, false).customBlockState().literalObject(), 3);
|
||||
return FastNMS.INSTANCE.constructor$ItemStack(MItems.WATER_BUCKET, 1);
|
||||
}
|
||||
return CoreReflections.instance$ItemStack$EMPTY;
|
||||
@@ -154,7 +154,7 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
ImmutableBlockState immutableBlockState = optionalCustomState.get();
|
||||
Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(args[3]);
|
||||
if (!immutableBlockState.get(this.waterloggedProperty) && fluidType == MFluids.WATER) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[1], immutableBlockState.with(this.waterloggedProperty, true).customBlockState().handle(), 3);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[1], immutableBlockState.with(this.waterloggedProperty, true).customBlockState().literalObject(), 3);
|
||||
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[0], args[1], fluidType, 5);
|
||||
return true;
|
||||
}
|
||||
@@ -182,6 +182,6 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior {
|
||||
if (optionalCustomState.isEmpty()) return false;
|
||||
BlockStateWrapper vanillaState = optionalCustomState.get().vanillaBlockState();
|
||||
if (vanillaState == null) return false;
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isPathFindable(vanillaState.handle(), VersionHelper.isOrAbove1_20_5() ? null : args[1], VersionHelper.isOrAbove1_20_5() ? null : args[2], args[isPathFindable$type]);
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isPathFindable(vanillaState.literalObject(), VersionHelper.isOrAbove1_20_5() ? null : args[1], VersionHelper.isOrAbove1_20_5() ? null : args[2], args[isPathFindable$type]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,15 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block");
|
||||
public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block");
|
||||
public static final Key DOUBLE_HIGH_BLOCK = Key.from("craftengine:double_high_block");
|
||||
public static final Key CHANGE_OVER_TIME_BLOCK = Key.from("craftengine:change_over_time_block");
|
||||
public static final Key SIMPLE_STORAGE_BLOCK = Key.from("craftengine:simple_storage_block");
|
||||
public static final Key TOGGLEABLE_LAMP_BLOCK = Key.from("craftengine:toggleable_lamp_block");
|
||||
public static final Key SOFA_BLOCK = Key.from("craftengine:sofa_block");
|
||||
public static final Key BOUNCING_BLOCK = Key.from("craftengine:bouncing_block");
|
||||
public static final Key DIRECTIONAL_ATTACHED_BLOCK = Key.from("craftengine:directional_attached_block");
|
||||
public static final Key LIQUID_FLOWABLE_BLOCK = Key.from("craftengine:liquid_flowable_block");
|
||||
public static final Key SIMPLE_PARTICLE_BLOCK = Key.from("craftengine:simple_particle_block");
|
||||
public static final Key WALL_TORCH_PARTICLE_BLOCK = Key.from("craftengine:wall_torch_particle_block");
|
||||
|
||||
public static void init() {
|
||||
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
|
||||
@@ -52,5 +61,14 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY);
|
||||
register(PRESSURE_PLATE_BLOCK, PressurePlateBlockBehavior.FACTORY);
|
||||
register(DOUBLE_HIGH_BLOCK, DoubleHighBlockBehavior.FACTORY);
|
||||
register(CHANGE_OVER_TIME_BLOCK, ChangeOverTimeBlockBehavior.FACTORY);
|
||||
register(SIMPLE_STORAGE_BLOCK, SimpleStorageBlockBehavior.FACTORY);
|
||||
register(TOGGLEABLE_LAMP_BLOCK, ToggleableLampBlockBehavior.FACTORY);
|
||||
register(SOFA_BLOCK, SofaBlockBehavior.FACTORY);
|
||||
register(BOUNCING_BLOCK, BouncingBlockBehavior.FACTORY);
|
||||
register(DIRECTIONAL_ATTACHED_BLOCK, DirectionalAttachedBlockBehavior.FACTORY);
|
||||
register(LIQUID_FLOWABLE_BLOCK, LiquidFlowableBlockBehavior.FACTORY);
|
||||
register(SIMPLE_PARTICLE_BLOCK, SimpleParticleBlockBehavior.FACTORY);
|
||||
register(WALL_TORCH_PARTICLE_BLOCK, WallTorchParticleBlockBehavior.FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockTags;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
@@ -76,10 +77,7 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception {
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos);
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos);
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos);
|
||||
Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y - 1, z);
|
||||
Object belowPos = LocationUtils.below(blockPos);
|
||||
Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos);
|
||||
return mayPlaceOn(belowState, world, belowPos);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
|
||||
import net.momirealms.craftengine.core.block.*;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.RandomUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final float changeSpeed;
|
||||
private final Key nextBlock;
|
||||
|
||||
public ChangeOverTimeBlockBehavior(CustomBlock customBlock, float changeSpeed, Key nextBlock) {
|
||||
super(customBlock);
|
||||
this.changeSpeed = changeSpeed;
|
||||
this.nextBlock = nextBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomTick(Object thisBlock, Object[] args, Callable<Object> superMethod) throws ReflectiveOperationException {
|
||||
if (RandomUtils.generateRandomFloat(0F, 1F) >= this.changeSpeed) return;
|
||||
Optional<Object> nextState = BukkitBlockManager.instance().blockById(this.nextBlock)
|
||||
.map(CustomBlock::defaultState)
|
||||
.map(ImmutableBlockState::customBlockState)
|
||||
.map(BlockStateWrapper::literalObject);
|
||||
if (nextState.isEmpty()) return;
|
||||
CraftBukkitReflections.method$CraftEventFactory$handleBlockFormEvent.invoke(null, args[1], args[2], nextState.get(), UpdateOption.UPDATE_ALL.flags());
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
float changeSpeed = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("change-speed", 0.05688889F), "change-speed");
|
||||
Key nextBlock = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("next-block", "minecraft:air"), "warning.config.block.behavior.change_over_time.missing_next_block"));
|
||||
return new ChangeOverTimeBlockBehavior(block, changeSpeed, nextBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class ConcretePowderBlockBehavior extends BukkitBlockBehavior {
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().blockById(this.targetBlock);
|
||||
if (optionalCustomBlock.isPresent()) {
|
||||
CustomBlock customBlock = optionalCustomBlock.get();
|
||||
this.defaultBlockState = customBlock.defaultState().customBlockState().handle();
|
||||
this.defaultBlockState = customBlock.defaultState().customBlockState().literalObject();
|
||||
this.defaultImmutableBlockState = customBlock.defaultState();
|
||||
} else {
|
||||
CraftEngine.instance().logger().warn("Failed to create solid block " + this.targetBlock + " in ConcretePowderBlockBehavior");
|
||||
@@ -129,7 +129,7 @@ public class ConcretePowderBlockBehavior extends BukkitBlockBehavior {
|
||||
Object mutablePos = CoreReflections.method$BlockPos$mutable.invoke(pos);
|
||||
int j = Direction.values().length;
|
||||
for (int k = 0; k < j; k++) {
|
||||
Object direction = CoreReflections.instance$Directions[k];
|
||||
Object direction = CoreReflections.instance$Direction$values[k];
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, mutablePos);
|
||||
if (direction != CoreReflections.instance$Direction$DOWN || canSolidify(blockState)) {
|
||||
CoreReflections.method$MutableBlockPos$setWithOffset.invoke(mutablePos, pos, direction);
|
||||
|
||||
@@ -94,7 +94,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
BlockStateUtils.getOptionalCustomBlockState(state).ifPresent(customState -> {
|
||||
int age = this.getAge(customState);
|
||||
if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(this.ageProperty, age + 1).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
if (isMaxAge(state))
|
||||
return InteractionResult.PASS;
|
||||
boolean sendSwing = false;
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualState = state.vanillaBlockState().literalObject();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
@@ -156,7 +156,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
boolean sendParticles = false;
|
||||
Object visualState = customState.vanillaBlockState().handle();
|
||||
Object visualState = customState.vanillaBlockState().literalObject();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, level, pos, visualState);
|
||||
@@ -180,7 +180,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
if (i > maxAge) {
|
||||
i = maxAge;
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(this.ageProperty, i).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
|
||||
if (sendParticles) {
|
||||
world.spawnParticle(ParticleUtils.HAPPY_VILLAGER, x + 0.5, y + 0.5, z + 0.5, 15, 0.25, 0.25, 0.25);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<?> facingProperty;
|
||||
private final boolean isSixDirection;
|
||||
|
||||
public DirectionalAttachedBlockBehavior(CustomBlock customBlock, Property<?> facingProperty, boolean isSixDirection) {
|
||||
super(customBlock);
|
||||
this.facingProperty = facingProperty;
|
||||
this.isSixDirection = isSixDirection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null);
|
||||
if (state == null) return args[0];
|
||||
DirectionalAttachedBlockBehavior behavior = state.behavior().getAs(DirectionalAttachedBlockBehavior.class).orElse(null);
|
||||
if (behavior == null) return state;
|
||||
boolean flag;
|
||||
if (isSixDirection) {
|
||||
Direction direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]).opposite();
|
||||
flag = direction == state.get(behavior.facingProperty);
|
||||
} else {
|
||||
HorizontalDirection direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]).opposite().toHorizontalDirection();
|
||||
flag = direction == state.get(behavior.facingProperty);
|
||||
}
|
||||
return flag && !FastNMS.INSTANCE.method$BlockStateBase$canSurvive(args[0], args[updateShape$level], args[updateShape$blockPos]) ? MBlocks.AIR$defaultState : args[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null);
|
||||
if (state == null) return false;
|
||||
DirectionalAttachedBlockBehavior behavior = state.behavior().getAs(DirectionalAttachedBlockBehavior.class).orElse(null);
|
||||
if (behavior == null) return false;
|
||||
Direction direction;
|
||||
if (isSixDirection) {
|
||||
direction = ((Direction) state.get(behavior.facingProperty)).opposite();
|
||||
} else {
|
||||
direction = ((HorizontalDirection) state.get(behavior.facingProperty)).opposite().toDirection();
|
||||
}
|
||||
BlockPos blockPos = LocationUtils.fromBlockPos(args[2]).relative(direction);
|
||||
Object nmsPos = LocationUtils.toBlockPos(blockPos);
|
||||
Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[1], nmsPos);
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, args[1], nmsPos, DirectionUtils.toNMSDirection(direction), CoreReflections.instance$SupportType$FULL);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
DirectionalAttachedBlockBehavior behavior = state.behavior().getAs(DirectionalAttachedBlockBehavior.class).orElse(null);
|
||||
if (behavior == null) return null;
|
||||
World level = context.getLevel();
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
for (Direction direction : context.getNearestLookingDirections()) {
|
||||
if (isSixDirection) {
|
||||
state = state.with((Property<Direction>) behavior.facingProperty, direction.opposite());
|
||||
if (FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state.customBlockState().literalObject(), level.serverWorld(), LocationUtils.toBlockPos(clickedPos))) {
|
||||
return state;
|
||||
}
|
||||
} else if (direction.axis().isHorizontal()) {
|
||||
state = state.with((Property<HorizontalDirection>) behavior.facingProperty, direction.opposite().toHorizontalDirection());
|
||||
if (FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state.customBlockState().literalObject(), level.serverWorld(), LocationUtils.toBlockPos(clickedPos))) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<?> facing = ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.surface_attached.missing_facing");
|
||||
boolean isHorizontalDirection = facing.valueClass() == HorizontalDirection.class;
|
||||
boolean isDirection = facing.valueClass() == Direction.class;
|
||||
if (!(isHorizontalDirection || isDirection)) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.behavior.surface_attached.missing_facing");
|
||||
}
|
||||
return new DirectionalAttachedBlockBehavior(block, facing, isDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
if (neighborState.get(anotherDoorBehavior.get().halfProperty) != half) {
|
||||
return neighborState.with(anotherDoorBehavior.get().halfProperty, half).customBlockState().handle();
|
||||
return neighborState.with(anotherDoorBehavior.get().halfProperty, half).customBlockState().literalObject();
|
||||
}
|
||||
return MBlocks.AIR$defaultState;
|
||||
} else {
|
||||
@@ -245,7 +245,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public void setOpen(@Nullable Player player, Object serverLevel, ImmutableBlockState state, BlockPos pos, boolean isOpen) {
|
||||
if (isOpen(state) != isOpen) {
|
||||
org.bukkit.World world = FastNMS.INSTANCE.method$Level$getCraftWorld(serverLevel);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(serverLevel, LocationUtils.toBlockPos(pos), state.with(this.openProperty, isOpen).customBlockState().handle(), UpdateOption.builder().updateImmediate().updateClients().build().flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(serverLevel, LocationUtils.toBlockPos(pos), state.with(this.openProperty, isOpen).customBlockState().literalObject(), UpdateOption.builder().updateImmediate().updateClients().build().flags());
|
||||
world.sendGameEvent(player == null ? null : (org.bukkit.entity.Player) player.platformPlayer(), isOpen ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||
SoundData soundData = isOpen ? this.openSound : this.closeSound;
|
||||
if (soundData != null) {
|
||||
@@ -307,7 +307,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
);
|
||||
}
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, flag).with(this.openProperty, flag).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, flag).with(this.openProperty, flag).customBlockState().literalObject(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public class DoubleHighBlockBehavior extends BukkitBlockBehavior {
|
||||
World level = context.getLevel();
|
||||
BlockPos anotherHalfPos = context.getClickedPos().relative(Direction.UP);
|
||||
BlockStateWrapper blockStateWrapper = state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState();
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), LocationUtils.toBlockPos(anotherHalfPos), blockStateWrapper.handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), LocationUtils.toBlockPos(anotherHalfPos), blockStateWrapper.literalObject(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,11 +10,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
|
||||
@@ -67,7 +63,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
return;
|
||||
}
|
||||
Object blockState = args[0];
|
||||
Object fallingBlockEntity = CoreReflections.method$FallingBlockEntity$fall.invoke(null, world, blockPos, blockState);
|
||||
Object fallingBlockEntity = FastNMS.INSTANCE.createInjectedFallingBlockEntity(world, blockPos, blockState);
|
||||
if (this.hurtAmount > 0 && this.maxHurt > 0) {
|
||||
CoreReflections.method$FallingBlockEntity$setHurtsEntities.invoke(fallingBlockEntity, this.hurtAmount, this.maxHurt);
|
||||
}
|
||||
@@ -76,27 +72,17 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Override
|
||||
public void onBrokenAfterFall(Object thisBlock, Object[] args) throws Exception {
|
||||
// Use EntityRemoveEvent for 1.20.3+
|
||||
if (VersionHelper.isOrAbove1_20_3()) return;
|
||||
Object level = args[0];
|
||||
Object fallingBlockEntity = args[2];
|
||||
boolean cancelDrop = (boolean) CoreReflections.field$FallingBlockEntity$cancelDrop.get(fallingBlockEntity);
|
||||
if (cancelDrop) return;
|
||||
Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, CoreReflections.field$Entity$xo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$yo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$zo.getDouble(fallingBlockEntity));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FALLING_BLOCK, true)
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
for (Item<Object> item : customState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlockEntity);
|
||||
boolean isSilent = (boolean) CoreReflections.method$SynchedEntityData$get.invoke(entityData, CoreReflections.instance$Entity$DATA_SILENT);
|
||||
if (!isSilent) {
|
||||
Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, CoreReflections.field$Entity$xo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$yo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$zo.getDouble(fallingBlockEntity));
|
||||
world.playBlockSound(position, customState.settings().sounds().destroySound());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
if (relativeStateIsWall) {
|
||||
// TODO: 连接原版方块
|
||||
}
|
||||
return customState.with(this.inWallProperty, flag).customBlockState().handle();
|
||||
return customState.with(this.inWallProperty, flag).customBlockState().literalObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,7 +148,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
private void playerToggle(UseOnContext context, ImmutableBlockState state) {
|
||||
Player player = context.getPlayer();
|
||||
this.toggle(state, context.getLevel(), context.getClickedPos(), player);
|
||||
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().literalObject()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
this.playSound(LocationUtils.fromBlockPos(blockPos), world, hasSignal);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, hasSignal).customBlockState().literalObject(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
|
||||
private void toggle(ImmutableBlockState state, World world, BlockPos pos, @Nullable Player player) {
|
||||
@@ -240,7 +240,7 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
newState = blockState.with(this.openProperty, true);
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
|
||||
boolean open = isOpen(newState);
|
||||
((org.bukkit.World) world.platformWorld()).sendGameEvent(
|
||||
player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null,
|
||||
|
||||
@@ -8,7 +8,7 @@ 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.ParticleUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
@@ -59,7 +59,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
boolean sendParticles = false;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
Object visualState = customState.vanillaBlockState().handle();
|
||||
Object visualState = customState.vanillaBlockState().literalObject();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, level, blockPos, visualState);
|
||||
@@ -86,12 +86,12 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
|
||||
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
|
||||
return InteractionResult.PASS;
|
||||
BlockPos pos = context.getClickedPos();
|
||||
BukkitBlockInWorld upper = (BukkitBlockInWorld) context.getLevel().getBlockAt(pos.x(), pos.y() + 1, pos.z());
|
||||
BukkitExistingBlock upper = (BukkitExistingBlock) context.getLevel().getBlockAt(pos.x(), pos.y() + 1, pos.z());
|
||||
Block block = upper.block();
|
||||
if (!block.isEmpty())
|
||||
return InteractionResult.PASS;
|
||||
boolean sendSwing = false;
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualState = state.vanillaBlockState().literalObject();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
@@ -20,10 +21,7 @@ public class HangingBlockBehavior extends BushBlockBehavior {
|
||||
|
||||
@Override
|
||||
protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException {
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos);
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos);
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos);
|
||||
Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y + 1, z);
|
||||
Object belowPos = LocationUtils.above(blockPos);
|
||||
Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos);
|
||||
return mayPlaceOn(belowState, world, belowPos);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
|
||||
if (FastNMS.INSTANCE.method$CraftEventFactory$callRedstoneChange(world, blockPos, 0, 15).getNewCurrent() != 15) {
|
||||
return;
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, customState.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, customState.cycle(this.litProperty).customBlockState().literalObject(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
|
||||
if (FastNMS.INSTANCE.method$CraftEventFactory$callRedstoneChange(world, blockPos, 0, 15).getNewCurrent() != 15) {
|
||||
return;
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, customState.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, customState.cycle(this.litProperty).customBlockState().literalObject(), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,10 +86,10 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
|
||||
LeavesBlockBehavior behavior = optionalBehavior.get();
|
||||
ImmutableBlockState newState = behavior.updateDistance(customState, level, blockPos);
|
||||
if (newState != customState) {
|
||||
if (blockState == newState.customBlockState().handle()) {
|
||||
if (blockState == newState.customBlockState().literalObject()) {
|
||||
CoreReflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512);
|
||||
} else {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior {
|
||||
Object mutablePos = CoreReflections.constructor$MutableBlockPos.newInstance();
|
||||
int j = Direction.values().length;
|
||||
for (int k = 0; k < j; ++k) {
|
||||
Object direction = CoreReflections.instance$Directions[k];
|
||||
Object direction = CoreReflections.instance$Direction$values[k];
|
||||
CoreReflections.method$MutableBlockPos$setWithOffset.invoke(mutablePos, blockPos, direction);
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, mutablePos);
|
||||
i = Math.min(i, getDistanceAt(blockState) + 1);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.behavior.special.PlaceLiquidBlockBehavior;
|
||||
import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class LiquidFlowableBlockBehavior extends BukkitBlockBehavior implements PlaceLiquidBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
|
||||
public LiquidFlowableBlockBehavior(CustomBlock customBlock) {
|
||||
super(customBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object level = args[0];
|
||||
Object pos = args[1];
|
||||
Object blockState = args[2];
|
||||
Object fluidState = args[3];
|
||||
Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(fluidState);
|
||||
if (fluidType == MFluids.LAVA || fluidType == MFluids.FLOWING_LAVA) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.LAVA_CONVERTS_BLOCK, pos, 0);
|
||||
} else {
|
||||
FastNMS.INSTANCE.method$Block$dropResources(blockState, level, pos);
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, FastNMS.INSTANCE.method$FluidState$createLegacyBlock(fluidState), UpdateOption.UPDATE_ALL.flags());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
return new LiquidFlowableBlockBehavior(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,6 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
if (signalForState == 0) {
|
||||
this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock);
|
||||
} else {
|
||||
// todo 为什么
|
||||
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime);
|
||||
}
|
||||
}
|
||||
@@ -122,7 +121,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
private Object setSignalForState(Object state, int strength) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
if (optionalCustomState.isEmpty()) return state;
|
||||
return optionalCustomState.get().with(this.poweredProperty, strength > 0).customBlockState().handle();
|
||||
return optionalCustomState.get().with(this.poweredProperty, strength > 0).customBlockState().literalObject();
|
||||
}
|
||||
|
||||
private void checkPressed(@Nullable Object entity, Object level, Object pos, Object state, int currentSignal, Object thisBlock) {
|
||||
@@ -189,7 +188,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
Object pos = args[2];
|
||||
Object newState = args[3];
|
||||
boolean movedByPiston = (boolean) args[4];
|
||||
if (!movedByPiston && !FastNMS.INSTANCE.method$BlockStateBase$is(state, FastNMS.INSTANCE.method$BlockState$getBlock(newState))) {
|
||||
if (!movedByPiston && !FastNMS.INSTANCE.method$BlockStateBase$isBlock(state, FastNMS.INSTANCE.method$BlockState$getBlock(newState))) {
|
||||
if (this.getSignalForState(state) > 0) {
|
||||
this.updateNeighbours(level, pos, thisBlock);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
boolean sendParticles = false;
|
||||
Object visualState = customState.vanillaBlockState().handle();
|
||||
Object visualState = customState.vanillaBlockState().literalObject();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, level, blockPos, visualState);
|
||||
@@ -151,7 +151,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
|
||||
return InteractionResult.PASS;
|
||||
boolean sendSwing = false;
|
||||
Object visualState = state.vanillaBlockState().handle();
|
||||
Object visualState = state.vanillaBlockState().literalObject();
|
||||
Object visualStateBlock = BlockStateUtils.getBlockOwner(visualState);
|
||||
if (CoreReflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
|
||||
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.entity.BukkitBlockEntityTypes;
|
||||
import net.momirealms.craftengine.bukkit.block.entity.SimpleParticleBlockEntity;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.particle.ParticleConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleParticleBlockBehavior extends BukkitBlockBehavior implements EntityBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
public final ParticleConfig[] particles;
|
||||
public final int tickInterval;
|
||||
|
||||
public SimpleParticleBlockBehavior(CustomBlock customBlock, ParticleConfig[] particles, int tickInterval) {
|
||||
super(customBlock);
|
||||
this.particles = particles;
|
||||
this.tickInterval = tickInterval;
|
||||
}
|
||||
|
||||
public ParticleConfig[] particles() {
|
||||
return this.particles;
|
||||
}
|
||||
|
||||
public int tickInterval() {
|
||||
return tickInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityType<T> blockEntityType() {
|
||||
return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_PARTICLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state) {
|
||||
return new SimpleParticleBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
if (this.particles.length == 0) return null;
|
||||
return EntityBlockBehavior.createTickerHelper(SimpleParticleBlockEntity::tick);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
List<ParticleConfig> particles = ResourceConfigUtils.parseConfigAsList(ResourceConfigUtils.get(arguments, "particles", "particle"), ParticleConfig::fromMap$blockEntity);
|
||||
int tickInterval = ResourceConfigUtils.getAsInt(arguments.getOrDefault("tick-interval", 10), "tick-interval");
|
||||
return new SimpleParticleBlockBehavior(block, particles.toArray(new ParticleConfig[0]), tickInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.entity.BukkitBlockEntityTypes;
|
||||
import net.momirealms.craftengine.bukkit.block.entity.SimpleStorageBlockEntity;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.gui.BukkitInventory;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.util.MCUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class SimpleStorageBlockBehavior extends BukkitBlockBehavior implements EntityBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final String containerTitle;
|
||||
private final int rows;
|
||||
private final SoundData openSound;
|
||||
private final SoundData closeSound;
|
||||
private final boolean hasAnalogOutputSignal;
|
||||
private final boolean canPlaceItem;
|
||||
private final boolean canTakeItem;
|
||||
@Nullable
|
||||
private final Property<Boolean> openProperty;
|
||||
|
||||
public SimpleStorageBlockBehavior(CustomBlock customBlock,
|
||||
String containerTitle,
|
||||
int rows,
|
||||
SoundData openSound,
|
||||
SoundData closeSound,
|
||||
boolean hasAnalogOutputSignal,
|
||||
boolean canPlaceItem,
|
||||
boolean canTakeItem,
|
||||
@Nullable Property<Boolean> openProperty) {
|
||||
super(customBlock);
|
||||
this.containerTitle = containerTitle;
|
||||
this.rows = rows;
|
||||
this.openSound = openSound;
|
||||
this.closeSound = closeSound;
|
||||
this.hasAnalogOutputSignal = hasAnalogOutputSignal;
|
||||
this.canPlaceItem = canPlaceItem;
|
||||
this.canTakeItem = canTakeItem;
|
||||
this.openProperty = openProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
|
||||
CEWorld world = context.getLevel().storageWorld();
|
||||
net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer();
|
||||
BlockEntity blockEntity = world.getBlockEntityAtIfLoaded(context.getClickedPos());
|
||||
if (player != null && blockEntity instanceof SimpleStorageBlockEntity entity) {
|
||||
Player bukkitPlayer = (Player) player.platformPlayer();
|
||||
Optional.ofNullable(entity.inventory()).ifPresent(inventory -> {
|
||||
entity.onPlayerOpen(player);
|
||||
bukkitPlayer.openInventory(inventory);
|
||||
new BukkitInventory(inventory).open(player, AdventureHelper.miniMessage().deserialize(this.containerTitle, PlayerOptionalContext.of(player).tagResolvers()));
|
||||
});
|
||||
}
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
|
||||
// 1.21.5+
|
||||
@Override
|
||||
public void affectNeighborsAfterRemoval(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object level = args[1];
|
||||
Object pos = args[2];
|
||||
Object blockState = args[0];
|
||||
FastNMS.INSTANCE.method$Level$updateNeighbourForOutputSignal(level, pos, BlockStateUtils.getBlockOwner(blockState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object world = args[1];
|
||||
Object blockPos = args[2];
|
||||
BlockPos pos = LocationUtils.fromBlockPos(blockPos);
|
||||
World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(world);
|
||||
CEWorld ceWorld = BukkitWorldManager.instance().getWorld(bukkitWorld.getUID());
|
||||
BlockEntity blockEntity = ceWorld.getBlockEntityAtIfLoaded(pos);
|
||||
if (blockEntity instanceof SimpleStorageBlockEntity entity) {
|
||||
entity.checkOpeners(world, blockPos, args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityType<T> blockEntityType() {
|
||||
return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.SIMPLE_STORAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state) {
|
||||
return new SimpleStorageBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String containerTitle() {
|
||||
return this.containerTitle;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SoundData closeSound() {
|
||||
return this.closeSound;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SoundData openSound() {
|
||||
return this.openSound;
|
||||
}
|
||||
|
||||
public int rows() {
|
||||
return this.rows;
|
||||
}
|
||||
|
||||
public boolean canPlaceItem() {
|
||||
return this.canPlaceItem;
|
||||
}
|
||||
|
||||
public boolean canTakeItem() {
|
||||
return this.canTakeItem;
|
||||
}
|
||||
|
||||
public @Nullable Property<Boolean> openProperty() {
|
||||
return openProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnalogOutputSignal(Object thisBlock, Object[] args) {
|
||||
if (!this.hasAnalogOutputSignal) return 0;
|
||||
Object world = args[1];
|
||||
Object blockPos = args[2];
|
||||
BlockPos pos = LocationUtils.fromBlockPos(blockPos);
|
||||
World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(world);
|
||||
CEWorld ceWorld = BukkitWorldManager.instance().getWorld(bukkitWorld.getUID());
|
||||
BlockEntity blockEntity = ceWorld.getBlockEntityAtIfLoaded(pos);
|
||||
if (blockEntity instanceof SimpleStorageBlockEntity entity) {
|
||||
Inventory inventory = entity.inventory();
|
||||
if (inventory != null) {
|
||||
float signal = 0.0F;
|
||||
for (int i = 0; i < inventory.getSize(); i++) {
|
||||
ItemStack item = inventory.getItem(i);
|
||||
if (item != null) {
|
||||
signal += (float) item.getAmount() / (float) (Math.min(inventory.getMaxStackSize(), item.getMaxStackSize()));
|
||||
}
|
||||
}
|
||||
signal /= (float) inventory.getSize();
|
||||
return MCUtils.lerpDiscrete(signal, 0, 15);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnalogOutputSignal(Object thisBlock, Object[] args) {
|
||||
return this.hasAnalogOutputSignal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getContainer(Object thisBlock, Object[] args) {
|
||||
CEWorld ceWorld = BukkitWorldManager.instance().getWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1]));
|
||||
BlockPos blockPos = LocationUtils.fromBlockPos(args[2]);
|
||||
BlockEntity blockEntity = ceWorld.getBlockEntityAtIfLoaded(blockPos);
|
||||
if (blockEntity instanceof SimpleStorageBlockEntity entity) {
|
||||
return FastNMS.INSTANCE.method$CraftInventory$getInventory(entity.inventory());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
String title = arguments.getOrDefault("title", "").toString();
|
||||
int rows = MCUtils.clamp(ResourceConfigUtils.getAsInt(arguments.getOrDefault("rows", 1), "rows"), 1, 6);
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
boolean hasAnalogOutputSignal = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("has-signal", true), "has-signal");
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
if (sounds != null) {
|
||||
openSound = Optional.ofNullable(sounds.get("open")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
}
|
||||
boolean canPlaceItem = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("allow-input", true), "allow-input");
|
||||
boolean canTakeItem = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("allow-output", true), "allow-output");
|
||||
Property<Boolean> property = (Property<Boolean>) block.getProperty("open");
|
||||
return new SimpleStorageBlockBehavior(block, title, rows, openSound, closeSound, hasAnalogOutputSignal, canPlaceItem, canTakeItem, property);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.block.state.properties.SofaShape;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class SofaBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<HorizontalDirection> facingProperty;
|
||||
private final Property<SofaShape> shapeProperty;
|
||||
|
||||
public SofaBlockBehavior(CustomBlock block, Property<HorizontalDirection> facing, Property<SofaShape> shape) {
|
||||
super(block);
|
||||
this.facingProperty = facing;
|
||||
this.shapeProperty = shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
ImmutableBlockState blockState = state.owner().value().defaultState()
|
||||
.with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection());
|
||||
if (super.waterloggedProperty != null) {
|
||||
Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
|
||||
blockState = blockState.with(this.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);
|
||||
}
|
||||
return blockState.with(this.shapeProperty, getSofaShape(blockState, context.getLevel().serverWorld(), clickedPos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object level = args[updateShape$level];
|
||||
Object blockPos = args[updateShape$blockPos];
|
||||
Object blockState = args[0];
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return blockState;
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
if (super.waterloggedProperty != null && customState.get(this.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5);
|
||||
}
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
SofaShape sofaShape = getSofaShape(customState, level, LocationUtils.fromBlockPos(blockPos));
|
||||
return direction.axis().isHorizontal()
|
||||
? customState.with(this.shapeProperty, sofaShape).customBlockState().literalObject()
|
||||
: superMethod.call();
|
||||
}
|
||||
|
||||
private SofaShape getSofaShape(ImmutableBlockState state, Object level, BlockPos pos) {
|
||||
Direction direction = state.get(this.facingProperty).toDirection();
|
||||
Object relativeBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(direction.opposite())));
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(relativeBlockState);
|
||||
if (optionalCustomState.isPresent()) {
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
Optional<SofaBlockBehavior> optionalStairsBlockBehavior = customState.behavior().getAs(SofaBlockBehavior.class);
|
||||
if (optionalStairsBlockBehavior.isPresent()) {
|
||||
SofaBlockBehavior stairsBlockBehavior = optionalStairsBlockBehavior.get();
|
||||
Direction direction1 = customState.get(stairsBlockBehavior.facingProperty).toDirection();
|
||||
if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1)) {
|
||||
if (direction1 == direction.counterClockWise()) {
|
||||
return SofaShape.INNER_LEFT;
|
||||
}
|
||||
return SofaShape.INNER_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return SofaShape.STRAIGHT;
|
||||
}
|
||||
|
||||
private boolean canTakeShape(ImmutableBlockState state, Object level, BlockPos pos, Direction face) {
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(face)));
|
||||
Optional<ImmutableBlockState> optionalAnotherState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalAnotherState.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
ImmutableBlockState anotherState = optionalAnotherState.get();
|
||||
Optional<SofaBlockBehavior> optionalBehavior = anotherState.behavior().getAs(SofaBlockBehavior.class);
|
||||
if (optionalBehavior.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
SofaBlockBehavior anotherBehavior = optionalBehavior.get();
|
||||
return anotherState.get(anotherBehavior.facingProperty) != state.get(this.facingProperty);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.sofa.missing_facing");
|
||||
Property<SofaShape> shape = (Property<SofaShape>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("shape"), "warning.config.block.behavior.sofa.missing_shape");
|
||||
return new SofaBlockBehavior(block, facing, shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public class StackableBlockBehavior extends BukkitBlockBehavior {
|
||||
private void updateStackableBlock(ImmutableBlockState state, BlockPos pos, World world, Item<ItemStack> item, Player player, InteractionHand hand) {
|
||||
ImmutableBlockState nextStage = state.cycle(this.amountProperty);
|
||||
Location location = new Location((org.bukkit.World) world.platformWorld(), pos.x(), pos.y(), pos.z());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), nextStage.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), nextStage.customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
|
||||
if (this.stackSound != null) {
|
||||
world.playBlockSound(new Vec3d(location.getX(), location.getY(), location.getZ()), this.stackSound);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class StairsBlockBehavior extends BukkitBlockBehavior {
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
StairsShape stairsShape = getStairsShape(customState, level, LocationUtils.fromBlockPos(blockPos));
|
||||
return direction.axis().isHorizontal()
|
||||
? customState.with(this.shapeProperty, stairsShape).customBlockState().handle()
|
||||
? customState.with(this.shapeProperty, stairsShape).customBlockState().literalObject()
|
||||
: superMethod.call();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ToggleableLampBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<Boolean> litProperty;
|
||||
private final Property<Boolean> poweredProperty;
|
||||
private final boolean canOpenWithHand;
|
||||
|
||||
public ToggleableLampBlockBehavior(CustomBlock block, Property<Boolean> litProperty, Property<Boolean> poweredProperty, boolean canOpenWithHand) {
|
||||
super(block);
|
||||
this.litProperty = litProperty;
|
||||
this.poweredProperty = poweredProperty;
|
||||
this.canOpenWithHand = canOpenWithHand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
|
||||
if (!this.canOpenWithHand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
ToggleableLampBlockBehavior behavior = state.behavior().getAs(ToggleableLampBlockBehavior.class).orElse(null);
|
||||
if (behavior == null) return InteractionResult.PASS;
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(
|
||||
context.getLevel().serverWorld(),
|
||||
LocationUtils.toBlockPos(context.getClickedPos()),
|
||||
state.cycle(behavior.litProperty).customBlockState().literalObject(),
|
||||
2
|
||||
);
|
||||
Optional.ofNullable(context.getPlayer()).ifPresent(p -> p.swingHand(context.getHand()));
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.poweredProperty == null) return;
|
||||
Object state = args[0];
|
||||
Object level = args[1];
|
||||
Object pos = args[2];
|
||||
Object oldState = args[3];
|
||||
if (FastNMS.INSTANCE.method$BlockState$getBlock(oldState) != FastNMS.INSTANCE.method$BlockState$getBlock(state) && CoreReflections.clazz$ServerLevel.isInstance(level)) {
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
checkAndFlip(optionalCustomState.get(), level, pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.poweredProperty == null) return;
|
||||
Object blockState = args[0];
|
||||
Object world = args[1];
|
||||
if (!CoreReflections.clazz$ServerLevel.isInstance(world)) return;
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState);
|
||||
if (optionalCustomState.isEmpty()) return;
|
||||
Object blockPos = args[2];
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
checkAndFlip(customState, world, blockPos);
|
||||
}
|
||||
|
||||
private void checkAndFlip(ImmutableBlockState customState, Object level, Object pos) {
|
||||
boolean hasNeighborSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, pos);
|
||||
boolean isPowered = customState.get(this.poweredProperty);
|
||||
if (hasNeighborSignal != isPowered) {
|
||||
ImmutableBlockState blockState = customState;
|
||||
if (!isPowered) {
|
||||
blockState = blockState.cycle(this.litProperty);
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState.with(this.poweredProperty, hasNeighborSignal).customBlockState().literalObject(), 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", false), "can-open-with-hand");
|
||||
Property<Boolean> lit = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("lit"), "warning.config.block.behavior.toggleable_lamp.missing_lit");
|
||||
Property<Boolean> powered = (Property<Boolean>) (canOpenWithHand ? block.getProperty("powered") : ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.toggleable_lamp.missing_powered"));
|
||||
return new ToggleableLampBlockBehavior(block, lit, powered, canOpenWithHand);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
private void playerToggle(UseOnContext context, ImmutableBlockState state) {
|
||||
Player player = context.getPlayer();
|
||||
this.toggle(state, context.getLevel(), context.getClickedPos(), player);
|
||||
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().literalObject()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
this.playSound(LocationUtils.fromBlockPos(blockPos), world, hasSignal);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, hasSignal).customBlockState().literalObject(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
if (this.waterloggedProperty != null && customState.get(this.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(level, blockPos, MFluids.WATER, 5);
|
||||
}
|
||||
@@ -203,7 +203,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
|
||||
private void toggle(ImmutableBlockState state, World world, BlockPos pos, @Nullable Player player) {
|
||||
ImmutableBlockState newState = state.cycle(this.openProperty);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
|
||||
boolean open = newState.get(this.openProperty);
|
||||
((org.bukkit.World) world.platformWorld()).sendGameEvent(
|
||||
player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null,
|
||||
|
||||
@@ -4,15 +4,20 @@ import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.behavior.special.FallOnBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.behavior.special.PlaceLiquidBlockBehavior;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
|
||||
implements FallOnBlockBehavior, PlaceLiquidBlockBehavior {
|
||||
private final AbstractBlockBehavior[] behaviors;
|
||||
|
||||
public UnsafeCompositeBlockBehavior(CustomBlock customBlock, List<AbstractBlockBehavior> behaviors) {
|
||||
@@ -20,6 +25,26 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
this.behaviors = behaviors.toArray(new AbstractBlockBehavior[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
for (AbstractBlockBehavior behavior : behaviors) {
|
||||
if (behavior instanceof PlaceLiquidBlockBehavior) {
|
||||
return behavior.canPlaceLiquid(thisBlock, args, superMethod);
|
||||
}
|
||||
}
|
||||
return super.canPlaceLiquid(thisBlock, args, superMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
for (AbstractBlockBehavior behavior : behaviors) {
|
||||
if (behavior instanceof PlaceLiquidBlockBehavior) {
|
||||
return behavior.placeLiquid(thisBlock, args, superMethod);
|
||||
}
|
||||
}
|
||||
return super.placeLiquid(thisBlock, args, superMethod);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends BlockBehavior> Optional<T> getAs(Class<T> tClass) {
|
||||
@@ -31,6 +56,22 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public EntityBlockBehavior getEntityBehavior() {
|
||||
EntityBlockBehavior target = null;
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
if (behavior instanceof EntityBlockBehavior entityBehavior) {
|
||||
if (target == null) {
|
||||
target = entityBehavior;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Multiple entity block behaviors are not allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
@@ -74,6 +115,18 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
return previous;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getContainer(Object thisBlock, Object[] args) throws Exception {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
Object container = behavior.getContainer(thisBlock, args);
|
||||
if (container != null) {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
@@ -264,6 +317,30 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAnalogOutputSignal(Object thisBlock, Object[] args) throws Exception {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
if (behavior.hasAnalogOutputSignal(thisBlock, args)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnalogOutputSignal(Object thisBlock, Object[] args) throws Exception {
|
||||
int signal = 0;
|
||||
int count = 0;
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
int s = behavior.getAnalogOutputSignal(thisBlock, args);
|
||||
if (s != 0) {
|
||||
signal += s;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count == 0 ? 0 : signal / count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object playerWillDestroy(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object previous = args[0];
|
||||
@@ -282,4 +359,26 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
behavior.spawnAfterBreak(thisBlock, args, superMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
if (behavior instanceof FallOnBlockBehavior f) {
|
||||
f.fallOn(thisBlock, args, superMethod);
|
||||
return;
|
||||
}
|
||||
}
|
||||
FallOnBlockBehavior.super.fallOn(thisBlock, args, superMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntityMovementAfterFallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
if (behavior instanceof FallOnBlockBehavior f) {
|
||||
f.updateEntityMovementAfterFallOn(thisBlock, args, superMethod);
|
||||
return;
|
||||
}
|
||||
}
|
||||
FallOnBlockBehavior.super.updateEntityMovementAfterFallOn(thisBlock, args, superMethod);
|
||||
}
|
||||
}
|
||||
@@ -66,13 +66,13 @@ public class VerticalCropBlockBehavior extends BukkitBlockBehavior {
|
||||
if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
|
||||
Object nextPos = this.direction ? LocationUtils.above(blockPos) : LocationUtils.below(blockPos);
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
CraftBukkitReflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, nextPos, super.customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
CraftBukkitReflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, nextPos, super.customBlock.defaultState().customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags());
|
||||
} else {
|
||||
CraftBukkitReflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, nextPos, super.customBlock.defaultState().customBlockState().handle());
|
||||
CraftBukkitReflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, nextPos, super.customBlock.defaultState().customBlockState().literalObject());
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().literalObject(), UpdateOption.UPDATE_NONE.flags());
|
||||
} else if (RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, age + 1).customBlockState().literalObject(), UpdateOption.UPDATE_NONE.flags());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class VerticalCropBlockBehavior extends BukkitBlockBehavior {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<Integer> ageProperty = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.sugar_cane.missing_age");
|
||||
Property<Integer> ageProperty = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.vertical_crop.missing_age");
|
||||
int maxHeight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("max-height", 3), "max-height");
|
||||
boolean direction = arguments.getOrDefault("direction", "up").toString().equalsIgnoreCase("up");
|
||||
return new VerticalCropBlockBehavior(block, ageProperty, maxHeight,
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.entity.BukkitBlockEntityTypes;
|
||||
import net.momirealms.craftengine.bukkit.block.entity.WallTorchParticleBlockEntity;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.particle.ParticleConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class WallTorchParticleBlockBehavior extends BukkitBlockBehavior implements EntityBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
public final ParticleConfig[] particles;
|
||||
public final int tickInterval;
|
||||
public final Property<HorizontalDirection> facingProperty;
|
||||
|
||||
public WallTorchParticleBlockBehavior(CustomBlock customBlock, ParticleConfig[] particles, int tickInterval, Property<HorizontalDirection> facingProperty) {
|
||||
super(customBlock);
|
||||
this.particles = particles;
|
||||
this.tickInterval = tickInterval;
|
||||
this.facingProperty = facingProperty;
|
||||
}
|
||||
|
||||
public ParticleConfig[] particles() {
|
||||
return this.particles;
|
||||
}
|
||||
|
||||
public int tickInterval() {
|
||||
return tickInterval;
|
||||
}
|
||||
|
||||
public Property<HorizontalDirection> facingProperty() {
|
||||
return facingProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityType<T> blockEntityType() {
|
||||
return EntityBlockBehavior.blockEntityTypeHelper(BukkitBlockEntityTypes.WALL_TORCH_PARTICLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state) {
|
||||
return new WallTorchParticleBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType<T> blockEntityType) {
|
||||
if (this.particles.length == 0) return null;
|
||||
return EntityBlockBehavior.createTickerHelper(WallTorchParticleBlockEntity::tick);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
List<ParticleConfig> particles = ResourceConfigUtils.parseConfigAsList(ResourceConfigUtils.get(arguments, "particles", "particle"), ParticleConfig::fromMap$blockEntity);
|
||||
int tickInterval = ResourceConfigUtils.getAsInt(arguments.getOrDefault("tick-interval", 10), "tick-interval");
|
||||
Property<HorizontalDirection> directionProperty = (Property<HorizontalDirection>) block.getProperty("facing");
|
||||
if (directionProperty == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.behavior.wall_torch_particle.missing_facing");
|
||||
}
|
||||
return new WallTorchParticleBlockBehavior(block, particles.toArray(new ParticleConfig[0]), tickInterval, directionProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity;
|
||||
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
|
||||
public abstract class AbstractAnimateTickBlockEntity extends BlockEntity {
|
||||
protected int tickCount;
|
||||
|
||||
public AbstractAnimateTickBlockEntity(BlockEntityType<? extends BlockEntity> type, BlockPos pos, ImmutableBlockState blockState) {
|
||||
super(type, pos, blockState);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity;
|
||||
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BlockEntityHolder implements InventoryHolder {
|
||||
private final BlockEntity blockEntity;
|
||||
private Inventory inventory;
|
||||
|
||||
public BlockEntityHolder(BlockEntity entity) {
|
||||
this.blockEntity = entity;
|
||||
}
|
||||
|
||||
public BlockEntity blockEntity() {
|
||||
return blockEntity;
|
||||
}
|
||||
|
||||
public void setInventory(Inventory inventory) {
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Inventory getInventory() {
|
||||
return this.inventory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity;
|
||||
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityType;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityTypeKeys;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntityTypes;
|
||||
|
||||
public class BukkitBlockEntityTypes extends BlockEntityTypes {
|
||||
public static final BlockEntityType<SimpleStorageBlockEntity> SIMPLE_STORAGE = register(BlockEntityTypeKeys.SIMPLE_STORAGE, SimpleStorageBlockEntity::new);
|
||||
public static final BlockEntityType<SimpleParticleBlockEntity> SIMPLE_PARTICLE = register(BlockEntityTypeKeys.SIMPLE_PARTICLE, SimpleParticleBlockEntity::new);
|
||||
public static final BlockEntityType<WallTorchParticleBlockEntity> WALL_TORCH_PARTICLE = register(BlockEntityTypeKeys.WALL_TORCH_PARTICLE, WallTorchParticleBlockEntity::new);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.behavior.SimpleParticleBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.SimpleContext;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.particle.ParticleConfig;
|
||||
|
||||
public class SimpleParticleBlockEntity extends AbstractAnimateTickBlockEntity {
|
||||
private final SimpleParticleBlockBehavior behavior;
|
||||
private final Context context = SimpleContext.of(ContextHolder.empty());
|
||||
|
||||
public SimpleParticleBlockEntity(BlockPos pos, ImmutableBlockState blockState) {
|
||||
super(BukkitBlockEntityTypes.SIMPLE_PARTICLE, pos, blockState);
|
||||
this.behavior = blockState.behavior().getAs(SimpleParticleBlockBehavior.class).orElseThrow();
|
||||
}
|
||||
|
||||
public void animateTick(ImmutableBlockState state, World level, BlockPos pos) {
|
||||
for (ParticleConfig particle : this.behavior.particles) {
|
||||
Vec3d location = new Vec3d(super.pos.x() + particle.x.getDouble(context), super.pos.y() + particle.y.getDouble(context), super.pos.z() + particle.z.getDouble(context));
|
||||
level.spawnParticle(
|
||||
location,
|
||||
particle.particleType,
|
||||
particle.count.getInt(context),
|
||||
particle.xOffset.getDouble(context),
|
||||
particle.yOffset.getDouble(context),
|
||||
particle.zOffset.getDouble(context),
|
||||
particle.speed.getDouble(context),
|
||||
particle.particleData,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tick(CEWorld ceWorld, BlockPos blockPos, ImmutableBlockState state, SimpleParticleBlockEntity particle) {
|
||||
particle.tickCount++;
|
||||
if (particle.tickCount % particle.behavior.tickInterval != 0) return;
|
||||
particle.animateTick(state, ceWorld.world(), blockPos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||
import net.momirealms.craftengine.bukkit.block.behavior.SimpleStorageBlockBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.entity.BlockEntity;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.ListTag;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SimpleStorageBlockEntity extends BlockEntity {
|
||||
private final SimpleStorageBlockBehavior behavior;
|
||||
private final Inventory inventory;
|
||||
private double maxInteractionDistance;
|
||||
private boolean openState = false;
|
||||
|
||||
public SimpleStorageBlockEntity(BlockPos pos, ImmutableBlockState blockState) {
|
||||
super(BukkitBlockEntityTypes.SIMPLE_STORAGE, pos, blockState);
|
||||
this.behavior = super.blockState.behavior().getAs(SimpleStorageBlockBehavior.class).orElseThrow();
|
||||
BlockEntityHolder holder = new BlockEntityHolder(this);
|
||||
this.inventory = FastNMS.INSTANCE.createSimpleStorageContainer(holder, this.behavior.rows() * 9, this.behavior.canPlaceItem(), this.behavior.canTakeItem());
|
||||
holder.setInventory(this.inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveCustomData(CompoundTag tag) {
|
||||
// 保存前先把所有打开此容器的玩家界面关闭
|
||||
this.inventory.close();
|
||||
ListTag itemsTag = new ListTag();
|
||||
@Nullable ItemStack[] storageContents = this.inventory.getStorageContents();
|
||||
for (int i = 0; i < storageContents.length; i++) {
|
||||
if (storageContents[i] != null) {
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
int slot = i;
|
||||
CoreReflections.instance$ItemStack$CODEC.encodeStart(MRegistryOps.SPARROW_NBT, FastNMS.INSTANCE.field$CraftItemStack$handle(storageContents[i]))
|
||||
.ifSuccess(success -> {
|
||||
CompoundTag itemTag = (CompoundTag) success;
|
||||
itemTag.putInt("slot", slot);
|
||||
itemsTag.add(itemTag);
|
||||
})
|
||||
.ifError(error -> CraftEngine.instance().logger().severe("Error while saving storage item: " + error));
|
||||
} else {
|
||||
Object nmsTag = FastNMS.INSTANCE.method$itemStack$save(FastNMS.INSTANCE.field$CraftItemStack$handle(storageContents[i]), FastNMS.INSTANCE.constructor$CompoundTag());
|
||||
CompoundTag itemTag = (CompoundTag) MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, nmsTag);
|
||||
itemTag.putInt("slot", i);
|
||||
itemsTag.add(itemTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
tag.put("items", itemsTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCustomData(CompoundTag tag) {
|
||||
ListTag itemsTag = Optional.ofNullable(tag.getList("items")).orElseGet(ListTag::new);
|
||||
ItemStack[] storageContents = new ItemStack[this.behavior.rows() * 9];
|
||||
for (int i = 0; i < itemsTag.size(); i++) {
|
||||
CompoundTag itemTag = itemsTag.getCompound(i);
|
||||
int slot = itemTag.getInt("slot");
|
||||
if (slot < 0 || slot >= storageContents.length) {
|
||||
continue;
|
||||
}
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
CoreReflections.instance$ItemStack$CODEC.parse(MRegistryOps.SPARROW_NBT, itemTag)
|
||||
.resultOrPartial((s) -> CraftEngine.instance().logger().severe("Tried to load invalid item: '" + itemTag + "'. " + s))
|
||||
.ifPresent(nmsStack -> storageContents[slot] = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsStack));
|
||||
} else {
|
||||
Object nmsTag = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.NBT, itemTag);
|
||||
Object itemStack = FastNMS.INSTANCE.method$ItemStack$of(nmsTag);
|
||||
storageContents[slot] = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack);
|
||||
}
|
||||
}
|
||||
this.inventory.setStorageContents(storageContents);
|
||||
}
|
||||
|
||||
public Inventory inventory() {
|
||||
if (!isValid()) return null;
|
||||
return this.inventory;
|
||||
}
|
||||
|
||||
public void onPlayerOpen(Player player) {
|
||||
if (!isValidContainer()) return;
|
||||
if (!player.isSpectatorMode()) {
|
||||
// 有非观察者的人,那么就不触发开启音效和事件
|
||||
if (!hasNoViewer(this.inventory.getViewers())) return;
|
||||
this.maxInteractionDistance = Math.max(player.getCachedInteractionRange(), this.maxInteractionDistance);
|
||||
this.setOpen(player);
|
||||
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(super.world.world().serverWorld(), LocationUtils.toBlockPos(this.pos), BlockStateUtils.getBlockOwner(this.blockState.customBlockState().literalObject()), 5);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPlayerClose(Player player) {
|
||||
if (!isValidContainer()) return;
|
||||
if (!player.isSpectatorMode()) {
|
||||
// 有非观察者的人,那么就不触发关闭音效和事件
|
||||
for (HumanEntity viewer : this.inventory.getViewers()) {
|
||||
if (viewer.getGameMode() == GameMode.SPECTATOR || viewer == player.platformPlayer()) {
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.maxInteractionDistance = 0;
|
||||
this.setClose(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void setOpen(@Nullable Player player) {
|
||||
this.updateOpenBlockState(true);
|
||||
org.bukkit.World bukkitWorld = (org.bukkit.World) super.world.world().platformWorld();
|
||||
if (player != null) {
|
||||
bukkitWorld.sendGameEvent((org.bukkit.entity.Player) player.platformPlayer(), GameEvent.CONTAINER_OPEN, new Vector(this.pos.x(), this.pos.y(), this.pos.z()));
|
||||
} else {
|
||||
bukkitWorld.sendGameEvent(null, GameEvent.CONTAINER_OPEN, new Vector(this.pos.x(), this.pos.y(), this.pos.z()));
|
||||
}
|
||||
this.openState = true;
|
||||
SoundData soundData = this.behavior.openSound();
|
||||
if (soundData != null) {
|
||||
super.world.world().playBlockSound(Vec3d.atCenterOf(this.pos), soundData);
|
||||
}
|
||||
}
|
||||
|
||||
private void setClose(@Nullable Player player) {
|
||||
this.updateOpenBlockState(false);
|
||||
org.bukkit.World bukkitWorld = (org.bukkit.World) super.world.world().platformWorld();
|
||||
if (player != null) {
|
||||
bukkitWorld.sendGameEvent((org.bukkit.entity.Player) player.platformPlayer(), GameEvent.CONTAINER_CLOSE, new Vector(this.pos.x(), this.pos.y(), this.pos.z()));
|
||||
} else {
|
||||
bukkitWorld.sendGameEvent(null, GameEvent.CONTAINER_CLOSE, new Vector(this.pos.x(), this.pos.y(), this.pos.z()));
|
||||
}
|
||||
this.openState = false;
|
||||
SoundData soundData = this.behavior.closeSound();
|
||||
if (soundData != null) {
|
||||
super.world.world().playBlockSound(Vec3d.atCenterOf(this.pos), soundData);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasNoViewer(List<HumanEntity> viewers) {
|
||||
for (HumanEntity viewer : viewers) {
|
||||
if (viewer.getGameMode() != GameMode.SPECTATOR) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidContainer() {
|
||||
return this.isValid() && this.inventory != null && this.behavior != null;
|
||||
}
|
||||
|
||||
public void updateOpenBlockState(boolean open) {
|
||||
ImmutableBlockState state = super.world.getBlockStateAtIfLoaded(this.pos);
|
||||
if (state == null || state.behavior() != this.behavior) return;
|
||||
Property<Boolean> property = this.behavior.openProperty();
|
||||
if (property == null) return;
|
||||
super.world.world().setBlockAt(this.pos.x(), this.pos.y(), this.pos.z(), state.with(property, open), UpdateOption.UPDATE_ALL.flags());
|
||||
}
|
||||
|
||||
public void checkOpeners(Object level, Object pos, Object blockState) {
|
||||
if (!this.isValidContainer()) return;
|
||||
double maxInteractionDistance = 0d;
|
||||
List<HumanEntity> viewers = this.inventory.getViewers();
|
||||
int validViewers = 0;
|
||||
for (HumanEntity viewer : viewers) {
|
||||
if (viewer instanceof org.bukkit.entity.Player player) {
|
||||
maxInteractionDistance = Math.max(BukkitAdaptors.adapt(player).getCachedInteractionRange(), maxInteractionDistance);
|
||||
if (player.getGameMode() != GameMode.SPECTATOR) {
|
||||
validViewers++;
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean shouldOpen = validViewers != 0;
|
||||
if (shouldOpen && !this.openState) {
|
||||
this.setOpen(null);
|
||||
} else if (!shouldOpen && this.openState) {
|
||||
this.setClose(null);
|
||||
}
|
||||
|
||||
this.maxInteractionDistance = maxInteractionDistance;
|
||||
if (!viewers.isEmpty()) {
|
||||
FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(blockState), 5);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove() {
|
||||
this.inventory.close();
|
||||
Vec3d pos = Vec3d.atCenterOf(this.pos);
|
||||
for (ItemStack stack : this.inventory.getContents()) {
|
||||
if (stack != null) {
|
||||
super.world.world().dropItemNaturally(pos, BukkitItemManager.instance().wrap(stack));
|
||||
}
|
||||
}
|
||||
this.inventory.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.behavior.WallTorchParticleBlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.SimpleContext;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.particle.ParticleConfig;
|
||||
|
||||
public class WallTorchParticleBlockEntity extends AbstractAnimateTickBlockEntity {
|
||||
private final WallTorchParticleBlockBehavior behavior;
|
||||
private final Context context = SimpleContext.of(ContextHolder.empty());
|
||||
|
||||
public WallTorchParticleBlockEntity(BlockPos pos, ImmutableBlockState blockState) {
|
||||
super(BukkitBlockEntityTypes.WALL_TORCH_PARTICLE, pos, blockState);
|
||||
this.behavior = blockState.behavior().getAs(WallTorchParticleBlockBehavior.class).orElseThrow();
|
||||
}
|
||||
|
||||
public void animateTick(ImmutableBlockState state, World level, BlockPos pos) {
|
||||
HorizontalDirection direction = state.get(this.behavior.facingProperty);
|
||||
if (direction == null) return;
|
||||
Vec3d center = Vec3d.atCenterOf(pos);
|
||||
HorizontalDirection opposite = direction.opposite();
|
||||
for (ParticleConfig particle : this.behavior.particles) {
|
||||
Vec3d location = new Vec3d(
|
||||
center.x() + particle.x.getDouble(context) * opposite.stepX(),
|
||||
center.y() + particle.y.getDouble(context),
|
||||
center.z() + particle.z.getDouble(context) * opposite.stepZ()
|
||||
);
|
||||
level.spawnParticle(
|
||||
location,
|
||||
particle.particleType,
|
||||
particle.count.getInt(context),
|
||||
particle.xOffset.getDouble(context),
|
||||
particle.yOffset.getDouble(context),
|
||||
particle.zOffset.getDouble(context),
|
||||
particle.speed.getDouble(context),
|
||||
particle.particleData,
|
||||
context
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tick(CEWorld ceWorld, BlockPos blockPos, ImmutableBlockState state, WallTorchParticleBlockEntity particle) {
|
||||
particle.tickCount++;
|
||||
if (particle.tickCount % particle.behavior.tickInterval != 0) return;
|
||||
particle.animateTick(state, ceWorld.world(), blockPos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
|
||||
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigs;
|
||||
|
||||
public class BukkitBlockEntityElementConfigs extends BlockEntityElementConfigs {
|
||||
|
||||
static {
|
||||
register(ITEM_DISPLAY, ItemDisplayBlockEntityElementConfig.FACTORY);
|
||||
register(TEXT_DISPLAY, TextDisplayBlockEntityElementConfig.FACTORY);
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ItemDisplayBlockEntityElement implements BlockEntityElement {
|
||||
private final ItemDisplayBlockEntityElementConfig config;
|
||||
private final Object cachedSpawnPacket;
|
||||
private final Object cachedDespawnPacket;
|
||||
private final int entityId;
|
||||
|
||||
public ItemDisplayBlockEntityElement(ItemDisplayBlockEntityElementConfig config, BlockPos pos) {
|
||||
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||
Vector3f position = config.position();
|
||||
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
|
||||
config.xRot(), config.yRot(), MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
);
|
||||
this.config = config;
|
||||
this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId));
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(Player player) {
|
||||
player.sendPacket(this.cachedDespawnPacket, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Player player) {
|
||||
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
|
||||
import net.momirealms.craftengine.core.entity.Billboard;
|
||||
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ItemDisplayBlockEntityElementConfig implements BlockEntityElementConfig<ItemDisplayBlockEntityElement> {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Function<Player, List<Object>> lazyMetadataPacket;
|
||||
private final Function<Player, Item<?>> item;
|
||||
private final Vector3f scale;
|
||||
private final Vector3f position;
|
||||
private final Vector3f translation;
|
||||
private final float xRot;
|
||||
private final float yRot;
|
||||
private final Quaternionf rotation;
|
||||
private final ItemDisplayContext displayContext;
|
||||
private final Billboard billboard;
|
||||
|
||||
public ItemDisplayBlockEntityElementConfig(Function<Player, Item<?>> item,
|
||||
Vector3f scale,
|
||||
Vector3f position,
|
||||
Vector3f translation,
|
||||
float xRot,
|
||||
float yRot,
|
||||
Quaternionf rotation,
|
||||
ItemDisplayContext displayContext,
|
||||
Billboard billboard) {
|
||||
this.item = item;
|
||||
this.scale = scale;
|
||||
this.position = position;
|
||||
this.translation = translation;
|
||||
this.xRot = xRot;
|
||||
this.yRot = yRot;
|
||||
this.rotation = rotation;
|
||||
this.displayContext = displayContext;
|
||||
this.billboard = billboard;
|
||||
this.lazyMetadataPacket = player -> {
|
||||
List<Object> dataValues = new ArrayList<>();
|
||||
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.apply(player).getLiteralObject(), dataValues);
|
||||
ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(this.scale, dataValues);
|
||||
ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(this.rotation, dataValues);
|
||||
ItemDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(this.billboard.id(), dataValues);
|
||||
ItemDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(this.translation, dataValues);
|
||||
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(this.displayContext.id(), dataValues);
|
||||
return dataValues;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDisplayBlockEntityElement create(World world, BlockPos pos) {
|
||||
return new ItemDisplayBlockEntityElement(this, pos);
|
||||
}
|
||||
|
||||
public Item<?> item(Player player) {
|
||||
return this.item.apply(player);
|
||||
}
|
||||
|
||||
public Vector3f scale() {
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
public Vector3f translation() {
|
||||
return this.translation;
|
||||
}
|
||||
|
||||
public Vector3f position() {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public float yRot() {
|
||||
return this.yRot;
|
||||
}
|
||||
|
||||
public float xRot() {
|
||||
return this.xRot;
|
||||
}
|
||||
|
||||
public Billboard billboard() {
|
||||
return billboard;
|
||||
}
|
||||
|
||||
public ItemDisplayContext displayContext() {
|
||||
return displayContext;
|
||||
}
|
||||
|
||||
public Quaternionf rotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public List<Object> metadataValues(Player player) {
|
||||
return this.lazyMetadataPacket.apply(player);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <E extends BlockEntityElement> BlockEntityElementConfig<E> create(Map<String, Object> arguments) {
|
||||
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("item"), "warning.config.block.state.entity_renderer.item_display.missing_item"));
|
||||
return (BlockEntityElementConfig<E>) new ItemDisplayBlockEntityElementConfig(
|
||||
player -> BukkitItemManager.instance().createWrappedItem(itemId, player),
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"),
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"),
|
||||
ResourceConfigUtils.getAsVector3f(arguments.get("translation"), "translation"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
|
||||
ResourceConfigUtils.getAsQuaternionf(arguments.getOrDefault("rotation", 0f), "rotation"),
|
||||
ItemDisplayContext.valueOf(arguments.getOrDefault("display-context", "none").toString().toUpperCase(Locale.ROOT)),
|
||||
Billboard.valueOf(arguments.getOrDefault("billboard", "fixed").toString().toUpperCase(Locale.ROOT))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TextDisplayBlockEntityElement implements BlockEntityElement {
|
||||
private final TextDisplayBlockEntityElementConfig config;
|
||||
private final Object cachedSpawnPacket;
|
||||
private final Object cachedDespawnPacket;
|
||||
private final int entityId;
|
||||
|
||||
public TextDisplayBlockEntityElement(TextDisplayBlockEntityElementConfig config, BlockPos pos) {
|
||||
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||
Vector3f position = config.position();
|
||||
this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, UUID.randomUUID(), pos.x() + position.x, pos.y() + position.y, pos.z() + position.z,
|
||||
config.xRot(), config.yRot(), MEntityTypes.TEXT_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
);
|
||||
this.config = config;
|
||||
this.cachedDespawnPacket = FastNMS.INSTANCE.constructor$ClientboundRemoveEntitiesPacket(IntList.of(entityId));
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(Player player) {
|
||||
player.sendPacket(this.cachedDespawnPacket, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Player player) {
|
||||
player.sendPackets(List.of(this.cachedSpawnPacket, FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(this.entityId, this.config.metadataValues(player))), true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package net.momirealms.craftengine.bukkit.block.entity.renderer.element;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.entity.data.TextDisplayEntityData;
|
||||
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
|
||||
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigFactory;
|
||||
import net.momirealms.craftengine.core.entity.Billboard;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class TextDisplayBlockEntityElementConfig implements BlockEntityElementConfig<TextDisplayBlockEntityElement> {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Function<Player, List<Object>> lazyMetadataPacket;
|
||||
private final String text;
|
||||
private final Vector3f scale;
|
||||
private final Vector3f position;
|
||||
private final Vector3f translation;
|
||||
private final float xRot;
|
||||
private final float yRot;
|
||||
private final Quaternionf rotation;
|
||||
private final Billboard billboard;
|
||||
|
||||
public TextDisplayBlockEntityElementConfig(String text,
|
||||
Vector3f scale,
|
||||
Vector3f position,
|
||||
Vector3f translation,
|
||||
float xRot,
|
||||
float yRot,
|
||||
Quaternionf rotation,
|
||||
Billboard billboard) {
|
||||
this.text = text;
|
||||
this.scale = scale;
|
||||
this.position = position;
|
||||
this.translation = translation;
|
||||
this.xRot = xRot;
|
||||
this.yRot = yRot;
|
||||
this.rotation = rotation;
|
||||
this.billboard = billboard;
|
||||
this.lazyMetadataPacket = player -> {
|
||||
List<Object> dataValues = new ArrayList<>();
|
||||
TextDisplayEntityData.Text.addEntityDataIfNotDefaultValue(ComponentUtils.adventureToMinecraft(text(player)), dataValues);
|
||||
TextDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(this.scale, dataValues);
|
||||
TextDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(this.rotation, dataValues);
|
||||
TextDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(this.billboard.id(), dataValues);
|
||||
TextDisplayEntityData.Translation.addEntityDataIfNotDefaultValue(this.translation, dataValues);
|
||||
return dataValues;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextDisplayBlockEntityElement create(World world, BlockPos pos) {
|
||||
return new TextDisplayBlockEntityElement(this, pos);
|
||||
}
|
||||
|
||||
public Component text(Player player) {
|
||||
return AdventureHelper.miniMessage().deserialize(this.text, PlayerOptionalContext.of(player).tagResolvers());
|
||||
}
|
||||
|
||||
public Vector3f scale() {
|
||||
return this.scale;
|
||||
}
|
||||
|
||||
public Vector3f translation() {
|
||||
return this.translation;
|
||||
}
|
||||
|
||||
public Vector3f position() {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public float yRot() {
|
||||
return this.yRot;
|
||||
}
|
||||
|
||||
public float xRot() {
|
||||
return this.xRot;
|
||||
}
|
||||
|
||||
public Billboard billboard() {
|
||||
return billboard;
|
||||
}
|
||||
|
||||
public Quaternionf rotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public List<Object> metadataValues(Player player) {
|
||||
return this.lazyMetadataPacket.apply(player);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockEntityElementConfigFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <E extends BlockEntityElement> BlockEntityElementConfig<E> create(Map<String, Object> arguments) {
|
||||
String text = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("text"), "warning.config.block.state.entity_renderer.text_display.missing_text");
|
||||
return (BlockEntityElementConfig<E>) new TextDisplayBlockEntityElementConfig(
|
||||
text,
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("scale", 1f), "scale"),
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", 0.5f), "position"),
|
||||
ResourceConfigUtils.getAsVector3f(arguments.get("translation"), "translation"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("pitch", 0f), "pitch"),
|
||||
ResourceConfigUtils.getAsFloat(arguments.getOrDefault("yaw", 0f), "yaw"),
|
||||
ResourceConfigUtils.getAsQuaternionf(arguments.getOrDefault("rotation", 0f), "rotation"),
|
||||
Billboard.valueOf(arguments.getOrDefault("billboard", "fixed").toString().toUpperCase(Locale.ROOT))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.entity;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.EntityUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.entity.AbstractEntity;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
@@ -68,7 +68,7 @@ public class BukkitEntity extends AbstractEntity {
|
||||
|
||||
@Override
|
||||
public Key type() {
|
||||
return KeyUtils.namespacedKey2Key(literalObject().getType().getKey());
|
||||
return EntityUtils.getEntityType(literalObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,10 +15,10 @@ public class DisplayEntityData<T> extends BaseEntityData<T> {
|
||||
public static final DisplayEntityData<Integer> TransformationInterpolationDuration = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, 0, VersionHelper.isOrAbove1_20_2());
|
||||
public static final DisplayEntityData<Integer> PositionRotationInterpolationDuration = of(DisplayEntityData.class, EntityDataValue.Serializers$INT, 0, VersionHelper.isOrAbove1_20_2());
|
||||
|
||||
public static final DisplayEntityData<Object> Translation = of(DisplayEntityData.class, EntityDataValue.Serializers$VECTOR3, new Vector3f(0f), true);
|
||||
public static final DisplayEntityData<Object> Scale = of(DisplayEntityData.class, EntityDataValue.Serializers$VECTOR3, new Vector3f(1f), true);
|
||||
public static final DisplayEntityData<Object> RotationLeft = of(DisplayEntityData.class, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f), true);
|
||||
public static final DisplayEntityData<Object> RotationRight = of(DisplayEntityData.class, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f), true);
|
||||
public static final DisplayEntityData<Vector3f> Translation = of(DisplayEntityData.class, EntityDataValue.Serializers$VECTOR3, new Vector3f(0f), true);
|
||||
public static final DisplayEntityData<Vector3f> Scale = of(DisplayEntityData.class, EntityDataValue.Serializers$VECTOR3, new Vector3f(1f), true);
|
||||
public static final DisplayEntityData<Quaternionf> RotationLeft = of(DisplayEntityData.class, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f), true);
|
||||
public static final DisplayEntityData<Quaternionf> RotationRight = of(DisplayEntityData.class, EntityDataValue.Serializers$QUATERNION, new Quaternionf(0f, 0f, 0f, 1f), true);
|
||||
/**
|
||||
* Billboard Constraints (0 = FIXED, 1 = VERTICAL, 2 = HORIZONTAL, 3 = CENTER)
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,7 @@ import net.momirealms.craftengine.core.entity.furniture.*;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.*;
|
||||
@@ -337,6 +337,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
plugin.scheduler().sync().runDelayed(() -> tryLeavingSeat(player, entity), player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
protected void tryLeavingSeat(@NotNull Player player, @NotNull Entity vehicle) {
|
||||
Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
if (baseFurniture == null) return;
|
||||
@@ -350,7 +351,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
plugin.logger().warn("Failed to get vector3f for player " + player.getName() + "'s seat");
|
||||
return;
|
||||
}
|
||||
Vector3f seatPos = MiscUtils.getAsVector3f(vector3f, "seat");
|
||||
Vector3f seatPos = ResourceConfigUtils.getAsVector3f(vector3f, "seat");
|
||||
furniture.removeOccupiedSeat(seatPos);
|
||||
|
||||
if (player.getVehicle() != null) return;
|
||||
@@ -375,6 +376,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
return (entity instanceof ArmorStand || entity instanceof ItemDisplay);
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private boolean isSafeLocation(Location location) {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return false;
|
||||
@@ -386,6 +388,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
return world.getBlockAt(x, y + 1, z).isPassable();
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@Nullable
|
||||
private Location findSafeLocationNearby(Location center) {
|
||||
World world = center.getWorld();
|
||||
|
||||
@@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkRefl
|
||||
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
@@ -84,7 +83,7 @@ public class CustomHitBox extends AbstractHitBox {
|
||||
|
||||
@Override
|
||||
public HitBox create(Map<String, Object> arguments) {
|
||||
Vector3f position = MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
|
||||
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
|
||||
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", 1), "scale");
|
||||
String type = (String) arguments.getOrDefault("entity-type", "slime");
|
||||
EntityType entityType = Registry.ENTITY_TYPE.get(new NamespacedKey("minecraft", type));
|
||||
|
||||
@@ -9,7 +9,6 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
@@ -124,7 +123,7 @@ public class HappyGhastHitBox extends AbstractHitBox {
|
||||
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
|
||||
return new HappyGhastHitBox(
|
||||
HitBoxFactory.getSeats(arguments),
|
||||
MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"),
|
||||
ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"),
|
||||
scale, canUseOn, blocksBuilding, canBeHitByProjectile, hardCollision
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
@@ -93,7 +92,7 @@ public class InteractionHitBox extends AbstractHitBox {
|
||||
|
||||
@Override
|
||||
public HitBox create(Map<String, Object> arguments) {
|
||||
Vector3f position = MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
|
||||
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
|
||||
float width;
|
||||
float height;
|
||||
if (arguments.containsKey("scale")) {
|
||||
|
||||
@@ -280,7 +280,7 @@ public class ShulkerHitBox extends AbstractHitBox {
|
||||
|
||||
@Override
|
||||
public HitBox create(Map<String, Object> arguments) {
|
||||
Vector3f position = MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
|
||||
Vector3f position = ResourceConfigUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position");
|
||||
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", "1"), "scale");
|
||||
byte peek = (byte) ResourceConfigUtils.getAsInt(arguments.getOrDefault("peek", 0), "peek");
|
||||
Direction directionEnum = Optional.ofNullable(arguments.get("direction")).map(it -> Direction.valueOf(it.toString().toUpperCase(Locale.ENGLISH))).orElse(Direction.UP);
|
||||
|
||||
@@ -21,7 +21,6 @@ import net.momirealms.craftengine.core.item.recipe.DatapackRecipeResult;
|
||||
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
|
||||
import net.momirealms.craftengine.core.pack.AbstractPackManager;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.plugin.logger.Debugger;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
@@ -335,7 +334,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
|
||||
@Override
|
||||
public ItemStack buildCustomItemStack(Key id, Player player) {
|
||||
return Optional.ofNullable(this.customItemsById.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null);
|
||||
return Optional.ofNullable(this.customItemsById.get(id)).map(it -> it.buildItemStack(ItemBuildContext.of(player), 1)).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
@@ -11,8 +10,11 @@ import net.momirealms.craftengine.core.item.modifier.ArgumentsModifier;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextKey;
|
||||
import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext;
|
||||
import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.ListTag;
|
||||
@@ -61,7 +63,7 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) {
|
||||
if (!Config.interceptItem()) return Optional.empty();
|
||||
return new OtherItem(wrapped, false).process();
|
||||
return new OtherItem(wrapped, false).process(NetworkTextReplaceContext.of(player));
|
||||
} else {
|
||||
BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get();
|
||||
Object serverItem = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject());
|
||||
@@ -71,7 +73,7 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
}
|
||||
if (!customItem.hasClientBoundDataModifier()) {
|
||||
if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty();
|
||||
return new OtherItem(wrapped, hasDifferentMaterial).process();
|
||||
return new OtherItem(wrapped, hasDifferentMaterial).process(NetworkTextReplaceContext.of(player));
|
||||
} else {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
Tag argumentTag = wrapped.getTag(ArgumentsModifier.ARGUMENTS_TAG);
|
||||
@@ -93,10 +95,10 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
}
|
||||
if (Config.interceptItem()) {
|
||||
if (!tag.containsKey("display.Name")) {
|
||||
processCustomName(wrapped, tag::put);
|
||||
processCustomName(wrapped, tag::put, context);
|
||||
}
|
||||
if (!tag.containsKey("display.Lore")) {
|
||||
processLore(wrapped, tag::put);
|
||||
processLore(wrapped, tag::put, context);
|
||||
}
|
||||
}
|
||||
if (tag.isEmpty()) {
|
||||
@@ -111,13 +113,13 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean processCustomName(Item<ItemStack> item, BiConsumer<String, CompoundTag> callback) {
|
||||
public static boolean processCustomName(Item<ItemStack> item, BiConsumer<String, CompoundTag> callback, Context context) {
|
||||
Optional<String> optionalCustomName = item.customNameJson();
|
||||
if (optionalCustomName.isPresent()) {
|
||||
String line = optionalCustomName.get();
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
if (!tokens.isEmpty()) {
|
||||
item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens)));
|
||||
item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens, context)));
|
||||
callback.accept("display.Name", NetworkItemHandler.pack(Operation.ADD, new StringTag(line)));
|
||||
return true;
|
||||
}
|
||||
@@ -125,18 +127,18 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean processLore(Item<ItemStack> item, BiConsumer<String, CompoundTag> callback) {
|
||||
private static boolean processLore(Item<ItemStack> item, BiConsumer<String, CompoundTag> callback, Context context) {
|
||||
Optional<List<String>> optionalLore = item.loreJson();
|
||||
if (optionalLore.isPresent()) {
|
||||
boolean changed = false;
|
||||
List<String> lore = optionalLore.get();
|
||||
List<String> newLore = new ArrayList<>(lore.size());
|
||||
for (String line : lore) {
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
if (tokens.isEmpty()) {
|
||||
newLore.add(line);
|
||||
} else {
|
||||
newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens)));
|
||||
newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens, context)));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -164,11 +166,11 @@ public final class LegacyNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
this.forceReturn = forceReturn;
|
||||
}
|
||||
|
||||
public Optional<Item<ItemStack>> process() {
|
||||
if (processLore(this.item, (s, c) -> networkTag().put(s, c))) {
|
||||
public Optional<Item<ItemStack>> process(Context context) {
|
||||
if (processLore(this.item, (s, c) -> networkTag().put(s, c), context)) {
|
||||
this.globalChanged = true;
|
||||
}
|
||||
if (processCustomName(this.item, (s, c) -> networkTag().put(s, c))) {
|
||||
if (processCustomName(this.item, (s, c) -> networkTag().put(s, c), context)) {
|
||||
this.globalChanged = true;
|
||||
}
|
||||
if (this.globalChanged) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.*;
|
||||
@@ -8,8 +7,11 @@ import net.momirealms.craftengine.core.item.modifier.ArgumentsModifier;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextKey;
|
||||
import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext;
|
||||
import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
@@ -64,7 +66,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) {
|
||||
if (!Config.interceptItem()) return Optional.empty();
|
||||
return new OtherItem(wrapped, false).process();
|
||||
return new OtherItem(wrapped, false).process(NetworkTextReplaceContext.of(player));
|
||||
} else {
|
||||
BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get();
|
||||
Object serverItem = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject());
|
||||
@@ -74,7 +76,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
}
|
||||
if (!customItem.hasClientBoundDataModifier()) {
|
||||
if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty();
|
||||
return new OtherItem(wrapped, hasDifferentMaterial).process();
|
||||
return new OtherItem(wrapped, hasDifferentMaterial).process(NetworkTextReplaceContext.of(player));
|
||||
} else {
|
||||
CompoundTag customData = Optional.ofNullable(wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
|
||||
CompoundTag arguments = customData.getCompound(ArgumentsModifier.ARGUMENTS_TAG);
|
||||
@@ -97,16 +99,16 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
}
|
||||
if (Config.interceptItem()) {
|
||||
if (!tag.containsKey(ComponentIds.ITEM_NAME)) {
|
||||
if (VersionHelper.isOrAbove1_21_5()) processModernItemName(wrapped, () -> tag);
|
||||
else processLegacyItemName(wrapped, () -> tag);
|
||||
if (VersionHelper.isOrAbove1_21_5()) processModernItemName(wrapped, () -> tag, context);
|
||||
else processLegacyItemName(wrapped, () -> tag, context);
|
||||
}
|
||||
if (!tag.containsKey(ComponentIds.CUSTOM_NAME)) {
|
||||
if (VersionHelper.isOrAbove1_21_5()) processModernCustomName(wrapped, () -> tag);
|
||||
else processLegacyCustomName(wrapped, () -> tag);
|
||||
if (VersionHelper.isOrAbove1_21_5()) processModernCustomName(wrapped, () -> tag, context);
|
||||
else processLegacyCustomName(wrapped, () -> tag, context);
|
||||
}
|
||||
if (!tag.containsKey(ComponentIds.LORE)) {
|
||||
if (VersionHelper.isOrAbove1_21_5()) processModernLore(wrapped, () -> tag);
|
||||
else processLegacyLore(wrapped, () -> tag);
|
||||
if (VersionHelper.isOrAbove1_21_5()) processModernLore(wrapped, () -> tag, context);
|
||||
else processLegacyLore(wrapped, () -> tag, context);
|
||||
}
|
||||
}
|
||||
if (tag.isEmpty()) {
|
||||
@@ -120,18 +122,18 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean processLegacyLore(Item<ItemStack> item, Supplier<CompoundTag> tag) {
|
||||
public static boolean processLegacyLore(Item<ItemStack> item, Supplier<CompoundTag> tag, Context context) {
|
||||
Optional<List<String>> optionalLore = item.loreJson();
|
||||
if (optionalLore.isPresent()) {
|
||||
boolean changed = false;
|
||||
List<String> lore = optionalLore.get();
|
||||
List<String> newLore = new ArrayList<>(lore.size());
|
||||
for (String line : lore) {
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
if (tokens.isEmpty()) {
|
||||
newLore.add(line);
|
||||
} else {
|
||||
newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens)));
|
||||
newLore.add(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens, context)));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -148,13 +150,13 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean processLegacyCustomName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
|
||||
public static boolean processLegacyCustomName(Item<ItemStack> item, Supplier<CompoundTag> tag, Context context) {
|
||||
Optional<String> optionalCustomName = item.customNameJson();
|
||||
if (optionalCustomName.isPresent()) {
|
||||
String line = optionalCustomName.get();
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
if (!tokens.isEmpty()) {
|
||||
item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens)));
|
||||
item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens, context)));
|
||||
tag.get().put(ComponentIds.CUSTOM_NAME, NetworkItemHandler.pack(Operation.ADD, new StringTag(line)));
|
||||
return true;
|
||||
}
|
||||
@@ -162,13 +164,13 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean processLegacyItemName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
|
||||
public static boolean processLegacyItemName(Item<ItemStack> item, Supplier<CompoundTag> tag, Context context) {
|
||||
Optional<String> optionalItemName = item.itemNameJson();
|
||||
if (optionalItemName.isPresent()) {
|
||||
String line = optionalItemName.get();
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(line);
|
||||
if (!tokens.isEmpty()) {
|
||||
item.itemNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens)));
|
||||
item.itemNameJson(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(line), tokens, context)));
|
||||
tag.get().put(ComponentIds.ITEM_NAME, NetworkItemHandler.pack(Operation.ADD, new StringTag(line)));
|
||||
return true;
|
||||
}
|
||||
@@ -176,33 +178,33 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean processModernItemName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
|
||||
public static boolean processModernItemName(Item<ItemStack> item, Supplier<CompoundTag> tag, Context context) {
|
||||
Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.ITEM_NAME);
|
||||
if (nameTag == null) return false;
|
||||
String tagStr = nameTag.getAsString();
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
|
||||
if (!tokens.isEmpty()) {
|
||||
item.setNBTComponent(ComponentKeys.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens)));
|
||||
item.setNBTComponent(ComponentKeys.ITEM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens, context)));
|
||||
tag.get().put(ComponentIds.ITEM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean processModernCustomName(Item<ItemStack> item, Supplier<CompoundTag> tag) {
|
||||
public static boolean processModernCustomName(Item<ItemStack> item, Supplier<CompoundTag> tag, Context context) {
|
||||
Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.CUSTOM_NAME);
|
||||
if (nameTag == null) return false;
|
||||
String tagStr = nameTag.getAsString();
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
|
||||
if (!tokens.isEmpty()) {
|
||||
item.setNBTComponent(ComponentKeys.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens)));
|
||||
item.setNBTComponent(ComponentKeys.CUSTOM_NAME, AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(nameTag), tokens, context)));
|
||||
tag.get().put(ComponentIds.CUSTOM_NAME, NetworkItemHandler.pack(Operation.ADD, nameTag));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean processModernLore(Item<ItemStack> item, Supplier<CompoundTag> tagSupplier) {
|
||||
public static boolean processModernLore(Item<ItemStack> item, Supplier<CompoundTag> tagSupplier, Context context) {
|
||||
Tag loreTag = item.getSparrowNBTComponent(ComponentTypes.LORE);
|
||||
boolean changed = false;
|
||||
if (!(loreTag instanceof ListTag listTag)) {
|
||||
@@ -211,11 +213,11 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
ListTag newLore = new ListTag();
|
||||
for (Tag tag : listTag) {
|
||||
String tagStr = tag.getAsString();
|
||||
Map<String, Component> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
|
||||
Map<String, ComponentProvider> tokens = CraftEngine.instance().fontManager().matchTags(tagStr);
|
||||
if (tokens.isEmpty()) {
|
||||
newLore.add(tag);
|
||||
} else {
|
||||
newLore.add(AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(tag), tokens)));
|
||||
newLore.add(AdventureHelper.componentToNbt(AdventureHelper.replaceText(AdventureHelper.nbtToComponent(tag), tokens, context)));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -238,20 +240,20 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
this.forceReturn = forceReturn;
|
||||
}
|
||||
|
||||
public Optional<Item<ItemStack>> process() {
|
||||
public Optional<Item<ItemStack>> process(Context context) {
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
if (processModernLore(this.item, this::getOrCreateTag))
|
||||
if (processModernLore(this.item, this::getOrCreateTag, context))
|
||||
this.globalChanged = true;
|
||||
if (processModernCustomName(this.item, this::getOrCreateTag))
|
||||
if (processModernCustomName(this.item, this::getOrCreateTag, context))
|
||||
this.globalChanged = true;
|
||||
if (processModernItemName(this.item, this::getOrCreateTag))
|
||||
if (processModernItemName(this.item, this::getOrCreateTag, context))
|
||||
this.globalChanged = true;
|
||||
} else {
|
||||
if (processLegacyLore(this.item, this::getOrCreateTag))
|
||||
if (processLegacyLore(this.item, this::getOrCreateTag, context))
|
||||
this.globalChanged = true;
|
||||
if (processLegacyCustomName(this.item, this::getOrCreateTag))
|
||||
if (processLegacyCustomName(this.item, this::getOrCreateTag, context))
|
||||
this.globalChanged = true;
|
||||
if (processLegacyItemName(this.item, this::getOrCreateTag))
|
||||
if (processLegacyItemName(this.item, this::getOrCreateTag, context))
|
||||
this.globalChanged = true;
|
||||
}
|
||||
if (this.globalChanged) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
@@ -82,12 +82,12 @@ public class AxeItemBehavior extends ItemBehavior {
|
||||
CompoundTag compoundTag = customState.propertiesNbt();
|
||||
ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag);
|
||||
|
||||
BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
org.bukkit.entity.Player bukkitPlayer = null;
|
||||
if (player != null) {
|
||||
bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer());
|
||||
// Call bukkit event
|
||||
EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, clicked.block(), BlockStateUtils.fromBlockData(newState.customBlockState().handle()));
|
||||
EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, clicked.block(), BlockStateUtils.fromBlockData(newState.customBlockState().literalObject()));
|
||||
if (EventUtils.fireAndCheckCancel(event)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class AxeItemBehavior extends ItemBehavior {
|
||||
if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL;
|
||||
BlockPos pos = context.getClickedPos();
|
||||
context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(context.getLevel().serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(context.getLevel().serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().literalObject(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags());
|
||||
clicked.block().getWorld().sendGameEvent(bukkitPlayer, GameEvent.BLOCK_CHANGE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||
Material material = MaterialUtils.getMaterial(item.vanillaId());
|
||||
if (bukkitPlayer != null) {
|
||||
@@ -106,7 +106,7 @@ public class AxeItemBehavior extends ItemBehavior {
|
||||
|
||||
// resend swing if it's not interactable on client side
|
||||
if (!InteractUtils.isInteractable(
|
||||
bukkitPlayer, BlockStateUtils.fromBlockData(customState.vanillaBlockState().handle()),
|
||||
bukkitPlayer, BlockStateUtils.fromBlockData(customState.vanillaBlockState().literalObject()),
|
||||
context.getHitResult(), item
|
||||
) || player.isSecondaryUseActive()) {
|
||||
player.swingHand(context.getHand());
|
||||
|
||||
@@ -9,7 +9,7 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
@@ -73,7 +73,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
if (!context.canPlace()) {
|
||||
return InteractionResult.FAIL;
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
Player player = context.getPlayer();
|
||||
@@ -89,7 +89,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
|
||||
ImmutableBlockState blockStateToPlace = getPlacementState(context, block);
|
||||
if (blockStateToPlace == null) {
|
||||
return InteractionResult.FAIL;
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
BlockPos againstPos = context.getAgainstPos();
|
||||
@@ -111,7 +111,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
} else {
|
||||
ImmutableBlockState customState = optionalCustomState.get();
|
||||
// custom block
|
||||
if (!AdventureModeUtils.canPlace(context.getItem(), context.getLevel(), againstPos, Config.simplifyAdventurePlaceCheck() ? customState.vanillaBlockState().handle() : againstBlockState)) {
|
||||
if (!AdventureModeUtils.canPlace(context.getItem(), context.getLevel(), againstPos, Config.simplifyAdventurePlaceCheck() ? customState.vanillaBlockState().literalObject() : againstBlockState)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
WorldPosition position = new WorldPosition(context.getLevel(), pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5);
|
||||
Cancellable dummy = Cancellable.dummy();
|
||||
PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(bukkitBlock))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(bukkitBlock))
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.EVENT, dummy)
|
||||
.withParameter(DirectContextParameters.HAND, context.getHand())
|
||||
@@ -196,7 +196,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
try {
|
||||
Player cePlayer = context.getPlayer();
|
||||
Object player = cePlayer != null ? cePlayer.serverPlayer() : null;
|
||||
Object blockState = state.customBlockState().handle();
|
||||
Object blockState = state.customBlockState().literalObject();
|
||||
Object blockPos = LocationUtils.toBlockPos(context.getClickedPos());
|
||||
Object voxelShape;
|
||||
if (VersionHelper.isOrAbove1_21_6()) {
|
||||
|
||||
@@ -12,6 +12,7 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
||||
public static final Key COMPOSTABLE_ITEM = Key.from("craftengine:compostable_item");
|
||||
public static final Key AXE_ITEM = Key.from("craftengine:axe_item");
|
||||
public static final Key DOUBLE_HIGH_BLOCK_ITEM = Key.from("craftengine:double_high_block_item");
|
||||
public static final Key WALL_BLOCK_ITEM = Key.from("craftengine:wall_block_item");
|
||||
|
||||
public static void init() {
|
||||
register(EMPTY, EmptyItemBehavior.FACTORY);
|
||||
@@ -22,5 +23,6 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
||||
register(COMPOSTABLE_ITEM, CompostableItemBehavior.FACTORY);
|
||||
register(AXE_ITEM, AxeItemBehavior.FACTORY);
|
||||
register(DOUBLE_HIGH_BLOCK_ITEM, DoubleHighBlockItemBehavior.FACTORY);
|
||||
register(WALL_BLOCK_ITEM, WallBlockItemBehavior.FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.EventUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
@@ -38,7 +38,7 @@ public class CompostableItemBehavior extends ItemBehavior {
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
BukkitBlockInWorld block = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
BukkitExistingBlock block = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
BlockData blockData = block.block().getBlockData();
|
||||
Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData));
|
||||
if (blockOwner != MBlocks.COMPOSTER) return InteractionResult.PASS;
|
||||
|
||||
@@ -6,7 +6,7 @@ import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.InteractUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -40,7 +40,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior {
|
||||
if (player == null) return InteractionResult.PASS;
|
||||
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(clickedPos);
|
||||
BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlockAt(clickedPos);
|
||||
Block block = clicked.block();
|
||||
BlockPos firePos = clickedPos.relative(context.getClickedFace());
|
||||
Direction direction = context.getHorizontalDirection();
|
||||
@@ -77,10 +77,10 @@ public class FlintAndSteelItemBehavior extends ItemBehavior {
|
||||
// 点击对象为自定义方块
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||
// 原版外观也可燃
|
||||
if (BlockStateUtils.isBurnable(immutableBlockState.vanillaBlockState().handle())) {
|
||||
if (BlockStateUtils.isBurnable(immutableBlockState.vanillaBlockState().literalObject())) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle());
|
||||
BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().literalObject());
|
||||
// 点击的是方块上面,则只需要判断shift和可交互
|
||||
if (direction == Direction.UP) {
|
||||
// 客户端层面必须可交互
|
||||
@@ -95,7 +95,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior {
|
||||
} else {
|
||||
// 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音
|
||||
BlockPos belowFirePos = firePos.relative(Direction.DOWN);
|
||||
BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos);
|
||||
BukkitExistingBlock belowFireBlock = (BukkitExistingBlock) context.getLevel().getBlockAt(belowFirePos);
|
||||
boolean belowCanBurn;
|
||||
try {
|
||||
Block belowBlock = belowFireBlock.block();
|
||||
@@ -134,7 +134,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior {
|
||||
for (Direction dir : Direction.values()) {
|
||||
if (dir == relativeDirection) continue;
|
||||
BlockPos relPos = firePos.relative(dir);
|
||||
BukkitBlockInWorld nearByBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(relPos);
|
||||
BukkitExistingBlock nearByBlock = (BukkitExistingBlock) context.getLevel().getBlockAt(relPos);
|
||||
BlockData nearbyBlockData = nearByBlock.block().getBlockData();
|
||||
Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData);
|
||||
int stateID = BlockStateUtils.blockStateToId(nearbyBlockState);
|
||||
|
||||
@@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
@@ -45,11 +47,15 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior {
|
||||
try {
|
||||
if (player == null) return InteractionResult.FAIL;
|
||||
Object blockHitResult = CoreReflections.method$Item$getPlayerPOVHitResult.invoke(null, world.serverWorld(), player.serverPlayer(), CoreReflections.instance$ClipContext$Fluid$SOURCE_ONLY);
|
||||
Object blockPos = CoreReflections.field$BlockHitResul$blockPos.get(blockHitResult);
|
||||
Object blockPos = FastNMS.INSTANCE.field$BlockHitResul$blockPos(blockHitResult);
|
||||
BlockPos above = new BlockPos(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos) + offsetY, FastNMS.INSTANCE.field$Vec3i$z(blockPos));
|
||||
Direction direction = Direction.values()[(int) CoreReflections.method$Direction$ordinal.invoke(CoreReflections.field$BlockHitResul$direction.get(blockHitResult))];
|
||||
boolean miss = CoreReflections.field$BlockHitResul$miss.getBoolean(blockHitResult);
|
||||
Direction direction = DirectionUtils.fromNMSDirection(FastNMS.INSTANCE.field$BlockHitResul$direction(blockHitResult));
|
||||
boolean miss = FastNMS.INSTANCE.field$BlockHitResul$miss(blockHitResult);
|
||||
Vec3d hitPos = LocationUtils.fromVec(CoreReflections.field$HitResult$location.get(blockHitResult));
|
||||
Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.method$BlockGetter$getFluidState(world.serverWorld(), blockPos));
|
||||
if (fluidType != MFluids.WATER && fluidType != MFluids.LAVA) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
if (miss) {
|
||||
return super.useOnBlock(new UseOnContext(player, hand, BlockHitResult.miss(hitPos, direction, above)));
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
public class WallBlockItemBehavior extends BlockItemBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
|
||||
public WallBlockItemBehavior(Key wallBlockId) {
|
||||
super(wallBlockId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
return this.place(new BlockPlaceContext(context));
|
||||
}
|
||||
|
||||
public InteractionResult place(BlockPlaceContext context) {
|
||||
if (context.getClickedFace().stepY() != 0) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
return super.place(context);
|
||||
}
|
||||
|
||||
public static class Factory implements ItemBehaviorFactory {
|
||||
@Override
|
||||
public ItemBehavior create(Pack pack, Path path, Key key, Map<String, Object> arguments) {
|
||||
Object id = arguments.get("block");
|
||||
if (id == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.item.behavior.wall_block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for wall_block_item behavior"));
|
||||
}
|
||||
if (id instanceof Map<?, ?> map) {
|
||||
if (map.containsKey(key.toString())) {
|
||||
// 防呆
|
||||
BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false));
|
||||
} else {
|
||||
BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false));
|
||||
}
|
||||
return new WallBlockItemBehavior(key);
|
||||
} else {
|
||||
return new WallBlockItemBehavior(Key.of(id.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -424,6 +424,7 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
@Override
|
||||
protected Optional<Enchantment> getEnchantment(ComponentItemWrapper item, Key key) {
|
||||
Object enchant = item.getComponentExact(ComponentTypes.ENCHANTMENTS);
|
||||
if (enchant == null) return Optional.empty();
|
||||
try {
|
||||
Map<String, Integer> map = EnchantmentUtils.toMap(enchant);
|
||||
Integer level = map.get(key.toString());
|
||||
|
||||
@@ -190,7 +190,6 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
|
||||
|
||||
@Override
|
||||
protected void maxDamage(LegacyItemWrapper item, Integer damage) {
|
||||
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.item.listener;
|
||||
import io.papermc.paper.event.block.CompostItemEvent;
|
||||
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||
import net.momirealms.craftengine.bukkit.api.event.CustomBlockInteractEvent;
|
||||
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitCustomItem;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
@@ -10,7 +11,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
|
||||
@@ -96,9 +97,10 @@ public class ItemEventListener implements Listener {
|
||||
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation()))
|
||||
.withParameter(DirectContextParameters.HAND, hand)
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.ENTITY, new BukkitEntity(entity))
|
||||
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation()))
|
||||
);
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
customItem.execute(context, EventTrigger.RIGHT_CLICK);
|
||||
@@ -162,7 +164,7 @@ public class ItemEventListener implements Listener {
|
||||
|
||||
// fix client side issues
|
||||
if (action.isRightClick() && hitResult != null &&
|
||||
InteractUtils.willConsume(player, BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle()), hitResult, itemInHand)) {
|
||||
InteractUtils.willConsume(player, BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().literalObject()), hitResult, itemInHand)) {
|
||||
player.updateInventory();
|
||||
//PlayerUtils.resendItemInHand(player);
|
||||
}
|
||||
@@ -171,7 +173,7 @@ public class ItemEventListener implements Listener {
|
||||
// run custom functions
|
||||
CustomBlock customBlock = immutableBlockState.owner().value();
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
|
||||
.withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState)
|
||||
.withParameter(DirectContextParameters.HAND, hand)
|
||||
.withParameter(DirectContextParameters.EVENT, dummy)
|
||||
@@ -253,13 +255,13 @@ public class ItemEventListener implements Listener {
|
||||
if (immutableBlockState != null) {
|
||||
// client won't have sounds if the clientside block is interactable
|
||||
// so we should check and resend sounds on BlockPlaceEvent
|
||||
BlockData craftBlockData = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle());
|
||||
BlockData craftBlockData = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().literalObject());
|
||||
if (InteractUtils.isInteractable(player, craftBlockData, hitResult, itemInHand)) {
|
||||
if (!serverPlayer.isSecondaryUseActive()) {
|
||||
serverPlayer.setResendSound();
|
||||
}
|
||||
} else {
|
||||
if (BlockStateUtils.isReplaceable(immutableBlockState.customBlockState().handle()) && !BlockStateUtils.isReplaceable(immutableBlockState.vanillaBlockState().handle())) {
|
||||
if (BlockStateUtils.isReplaceable(immutableBlockState.customBlockState().literalObject()) && !BlockStateUtils.isReplaceable(immutableBlockState.vanillaBlockState().literalObject())) {
|
||||
serverPlayer.setResendSwing();
|
||||
}
|
||||
}
|
||||
@@ -316,7 +318,7 @@ public class ItemEventListener implements Listener {
|
||||
if (serverPlayer.isSecondaryUseActive() || !InteractUtils.isInteractable(player, blockData, hitResult, itemInHand)) {
|
||||
Cancellable dummy = Cancellable.dummy();
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
|
||||
.withOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState)
|
||||
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
|
||||
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation()))
|
||||
@@ -337,7 +339,7 @@ public class ItemEventListener implements Listener {
|
||||
if (hasCustomItem && action == Action.LEFT_CLICK_BLOCK) {
|
||||
Cancellable dummy = Cancellable.dummy();
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block))
|
||||
.withParameter(DirectContextParameters.BLOCK, new BukkitExistingBlock(block))
|
||||
.withOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, immutableBlockState)
|
||||
.withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
|
||||
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation()))
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.momirealms.craftengine.bukkit.item.recipe;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import io.papermc.paper.potion.PotionMix;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
@@ -69,58 +68,35 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
return recipe;
|
||||
};
|
||||
|
||||
static {
|
||||
try {
|
||||
Key dyeRecipeId = Key.from("armor_dye");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(dyeRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.apply(dyeRecipeId, RecipeInjector.createCustomDyeRecipe(dyeRecipeId));
|
||||
Key repairRecipeId = Key.from("repair_item");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(repairRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.apply(repairRecipeId, RecipeInjector.createRepairItemRecipe(repairRecipeId));
|
||||
Key fireworkStarFadeRecipeId = Key.from("firework_star_fade");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(fireworkStarFadeRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.apply(fireworkStarFadeRecipeId, RecipeInjector.createFireworkStarFadeRecipe(fireworkStarFadeRecipeId));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to inject special recipes", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final List<Object> MODIFIED_INGREDIENTS = new ArrayList<>();
|
||||
private static final Map<Key, Function<Recipe<ItemStack>, Object>> ADD_RECIPE_FOR_MINECRAFT_RECIPE_HOLDER = Map.of(
|
||||
RecipeSerializers.SHAPED, recipe -> {
|
||||
CustomShapedRecipe<ItemStack> shapedRecipe = (CustomShapedRecipe<ItemStack>) recipe;
|
||||
Object mcRecipe = FastNMS.INSTANCE.createShapedRecipe(shapedRecipe);
|
||||
modifyShapedRecipeIngredients(shapedRecipe, mcRecipe);
|
||||
return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe);
|
||||
},
|
||||
RecipeSerializers.SHAPELESS, recipe -> {
|
||||
CustomShapelessRecipe<ItemStack> shapelessRecipe = (CustomShapelessRecipe<ItemStack>) recipe;
|
||||
Object mcRecipe = FastNMS.INSTANCE.createShapelessRecipe(shapelessRecipe);
|
||||
modifyShapelessRecipeIngredients(shapelessRecipe, mcRecipe);
|
||||
return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe);
|
||||
},
|
||||
RecipeSerializers.SMELTING, recipe -> {
|
||||
CustomSmeltingRecipe<ItemStack> smeltingRecipe = (CustomSmeltingRecipe<ItemStack>) recipe;
|
||||
Object mcRecipe = FastNMS.INSTANCE.createSmeltingRecipe(smeltingRecipe);
|
||||
modifyCookingRecipeIngredient(smeltingRecipe, mcRecipe);
|
||||
return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe);
|
||||
},
|
||||
RecipeSerializers.BLASTING, recipe -> {
|
||||
CustomBlastingRecipe<ItemStack> blastingRecipe = (CustomBlastingRecipe<ItemStack>) recipe;
|
||||
Object mcRecipe = FastNMS.INSTANCE.createBlastingRecipe(blastingRecipe);
|
||||
modifyCookingRecipeIngredient(blastingRecipe, mcRecipe);
|
||||
return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe);
|
||||
},
|
||||
RecipeSerializers.SMOKING, recipe -> {
|
||||
CustomSmokingRecipe<ItemStack> smokingRecipe = (CustomSmokingRecipe<ItemStack>) recipe;
|
||||
Object mcRecipe = FastNMS.INSTANCE.createSmokingRecipe(smokingRecipe);
|
||||
modifyCookingRecipeIngredient(smokingRecipe, mcRecipe);
|
||||
return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe);
|
||||
},
|
||||
RecipeSerializers.CAMPFIRE_COOKING, recipe -> {
|
||||
CustomCampfireRecipe<ItemStack> campfireRecipe = (CustomCampfireRecipe<ItemStack>) recipe;
|
||||
Object mcRecipe = FastNMS.INSTANCE.createCampfireRecipe(campfireRecipe);
|
||||
modifyCookingRecipeIngredient(campfireRecipe, mcRecipe);
|
||||
return MINECRAFT_RECIPE_ADDER.apply(recipe.id(), mcRecipe);
|
||||
},
|
||||
RecipeSerializers.STONECUTTING, recipe -> {
|
||||
@@ -219,18 +195,19 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Object> getIngredientLooks(List<UniqueKey> holders) {
|
||||
public static List<Object> getIngredientLooks(List<UniqueKey> holders) {
|
||||
List<Object> itemStacks = new ArrayList<>();
|
||||
for (UniqueKey holder : holders) {
|
||||
Optional<? extends BuildableItem<ItemStack>> buildableItem = BukkitItemManager.instance().getBuildableItem(holder.key());
|
||||
if (buildableItem.isPresent()) {
|
||||
ItemStack itemStack = buildableItem.get().buildItemStack(ItemBuildContext.EMPTY, 1);
|
||||
ItemStack itemStack = buildableItem.get().buildItemStack(ItemBuildContext.empty(), 1);
|
||||
Object nmsStack = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack);
|
||||
itemStacks.add(nmsStack);
|
||||
} else {
|
||||
Item<ItemStack> barrier = BukkitItemManager.instance().createWrappedItem(ItemKeys.BARRIER, null);
|
||||
assert barrier != null;
|
||||
barrier.customNameJson(AdventureHelper.componentToJson(Component.text(holder.key().asString()).color(NamedTextColor.RED)));
|
||||
itemStacks.add(barrier.getLiteralObject());
|
||||
}
|
||||
}
|
||||
return itemStacks;
|
||||
@@ -245,9 +222,9 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
Ingredient<ItemStack> actualIngredient = actualIngredients.get(i);
|
||||
List<Object> items = getIngredientLooks(actualIngredient.items());
|
||||
if (VersionHelper.isOrAbove1_21_4()) {
|
||||
CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (Set<Object>) new ObjectOpenHashSet<>(items));
|
||||
CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (Set<Object>) new CustomIngredientSet(items, actualIngredient));
|
||||
} else if (VersionHelper.isOrAbove1_21_2()) {
|
||||
CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (List<Object>) items);
|
||||
CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (List<Object>) new CustomIngredientList(items, actualIngredient));
|
||||
} else {
|
||||
Object itemStackArray = Array.newInstance(CoreReflections.clazz$ItemStack, items.size());
|
||||
for (int j = 0; j < items.size(); j++) {
|
||||
@@ -255,7 +232,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
}
|
||||
CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (Object) itemStackArray);
|
||||
}
|
||||
MODIFIED_INGREDIENTS.add(ingredient);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,7 +336,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
if (recipe instanceof CustomBrewingRecipe<ItemStack> brewingRecipe) {
|
||||
if (!VersionHelper.isOrAbove1_20_2()) return;
|
||||
PotionMix potionMix = new PotionMix(new NamespacedKey(id.namespace(), id.value()),
|
||||
brewingRecipe.result(ItemBuildContext.EMPTY),
|
||||
brewingRecipe.result(ItemBuildContext.empty()),
|
||||
PotionMix.createPredicateChoice(container -> {
|
||||
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(container);
|
||||
return brewingRecipe.container().test(UniqueIdItem.of(wrapped));
|
||||
@@ -484,6 +460,22 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
this.plugin.logger().warn("Failed to register recipe " + recipe.id().toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 重新注入特殊配方
|
||||
try {
|
||||
Key dyeRecipeId = Key.from("armor_dye");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(dyeRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.apply(dyeRecipeId, RecipeInjector.createCustomDyeRecipe(dyeRecipeId));
|
||||
Key repairRecipeId = Key.from("repair_item");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(repairRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.apply(repairRecipeId, RecipeInjector.createRepairItemRecipe(repairRecipeId));
|
||||
Key fireworkStarFadeRecipeId = Key.from("firework_star_fade");
|
||||
MINECRAFT_RECIPE_REMOVER.accept(fireworkStarFadeRecipeId);
|
||||
MINECRAFT_RECIPE_ADDER.apply(fireworkStarFadeRecipeId, RecipeInjector.createFireworkStarFadeRecipe(fireworkStarFadeRecipeId));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to inject special recipes", e);
|
||||
}
|
||||
|
||||
try {
|
||||
// give flags back on 1.21.2+
|
||||
if (VersionHelper.isOrAbove1_21_2() && this.stolenFeatureFlagSet != null) {
|
||||
@@ -498,20 +490,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
|
||||
// send to players
|
||||
CoreReflections.methodHandle$DedicatedPlayerList$reloadRecipes.invokeExact(CraftBukkitReflections.methodHandle$CraftServer$playerListGetter.invokeExact(Bukkit.getServer()));
|
||||
|
||||
// now we need to remove the fake `exact` choices
|
||||
if (VersionHelper.isOrAbove1_21_4()) {
|
||||
for (Object ingredient : MODIFIED_INGREDIENTS) {
|
||||
CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (Set<Object>) null);
|
||||
}
|
||||
} else if (VersionHelper.isOrAbove1_21_2()) {
|
||||
for (Object ingredient : MODIFIED_INGREDIENTS) {
|
||||
CoreReflections.methodHandle$Ingredient$itemStacksSetter.invokeExact(ingredient, (List<Object>) null);
|
||||
}
|
||||
}
|
||||
|
||||
// clear cache
|
||||
MODIFIED_INGREDIENTS.clear();
|
||||
} catch (Throwable e) {
|
||||
this.plugin.logger().warn("Failed to run delayed recipe tasks", e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.momirealms.craftengine.bukkit.item.recipe;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.core.item.recipe.Ingredient;
|
||||
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class CustomIngredientList extends ArrayList<Object> {
|
||||
private final Ingredient<ItemStack> ingredient;
|
||||
|
||||
public CustomIngredientList(@NotNull Collection<?> c, Ingredient<ItemStack> ingredient) {
|
||||
super(c);
|
||||
this.ingredient = ingredient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o == null || FastNMS.INSTANCE.method$ItemStack$isEmpty(o)) {
|
||||
return false;
|
||||
}
|
||||
return this.ingredient.test(UniqueIdItem.of(BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(o))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.momirealms.craftengine.bukkit.item.recipe;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.core.item.recipe.Ingredient;
|
||||
import net.momirealms.craftengine.core.item.recipe.UniqueIdItem;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class CustomIngredientSet extends HashSet<Object> {
|
||||
private final Ingredient<ItemStack> ingredient;
|
||||
|
||||
public CustomIngredientSet(@NotNull Collection<?> c, Ingredient<ItemStack> ingredient) {
|
||||
super(c);
|
||||
this.ingredient = ingredient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o == null || FastNMS.INSTANCE.method$ItemStack$isEmpty(o)) {
|
||||
return false;
|
||||
}
|
||||
return this.ingredient.test(UniqueIdItem.of(BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(o))));
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import net.momirealms.craftengine.core.item.recipe.input.SmithingInput;
|
||||
import net.momirealms.craftengine.core.item.setting.AnvilRepairItem;
|
||||
import net.momirealms.craftengine.core.item.setting.ItemEquipment;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -270,6 +269,7 @@ public class RecipeEventListener implements Listener {
|
||||
预处理会阻止一些不合理的原版材质造成的合并问题
|
||||
*/
|
||||
private void preProcess(PrepareAnvilEvent event) {
|
||||
if (event.getResult() == null) return;
|
||||
AnvilInventory inventory = event.getInventory();
|
||||
ItemStack first = inventory.getFirstItem();
|
||||
ItemStack second = inventory.getSecondItem();
|
||||
@@ -284,6 +284,10 @@ public class RecipeEventListener implements Listener {
|
||||
}
|
||||
// 如果第二个物品是附魔书,那么忽略
|
||||
if (wrappedSecond.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) {
|
||||
// 禁止不可附魔的物品被附魔书附魔
|
||||
if (firstCustom.isPresent() && !firstCustom.get().settings().canEnchant()) {
|
||||
event.setResult(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -313,12 +317,23 @@ public class RecipeEventListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果禁止在铁砧使用两个相同物品修复
|
||||
firstCustom.ifPresent(it -> {
|
||||
if (it.settings().canRepair() == Tristate.FALSE) {
|
||||
if (firstCustom.isPresent()) {
|
||||
CustomItem<ItemStack> firstCustomItem = firstCustom.get();
|
||||
if (firstCustomItem.settings().repairable().anvilCombine() == Tristate.FALSE) {
|
||||
event.setResult(null);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
Item<ItemStack> wrappedResult = BukkitItemManager.instance().wrap(event.getResult());
|
||||
if (!firstCustomItem.settings().canEnchant()) {
|
||||
Object previousEnchantment = wrappedFirst.getExactComponent(ComponentTypes.ENCHANTMENTS);
|
||||
if (previousEnchantment != null) {
|
||||
wrappedResult.setExactComponent(ComponentTypes.ENCHANTMENTS, previousEnchantment);
|
||||
} else {
|
||||
wrappedResult.resetComponent(ComponentTypes.ENCHANTMENTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -356,7 +371,7 @@ public class RecipeEventListener implements Listener {
|
||||
Key firstId = wrappedFirst.id();
|
||||
Optional<CustomItem<ItemStack>> optionalCustomTool = wrappedFirst.getCustomItem();
|
||||
// 物品无法被修复
|
||||
if (optionalCustomTool.isPresent() && optionalCustomTool.get().settings().canRepair() == Tristate.FALSE) {
|
||||
if (optionalCustomTool.isPresent() && optionalCustomTool.get().settings().repairable().anvilRepair() == Tristate.FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -477,14 +492,12 @@ public class RecipeEventListener implements Listener {
|
||||
*/
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
private void processRename(PrepareAnvilEvent event) {
|
||||
if (event.getResult() == null) return;
|
||||
AnvilInventory inventory = event.getInventory();
|
||||
ItemStack first = inventory.getFirstItem();
|
||||
if (ItemStackUtils.isEmpty(first)) {
|
||||
return;
|
||||
}
|
||||
if (event.getResult() == null) {
|
||||
return;
|
||||
}
|
||||
Item<ItemStack> wrappedFirst = BukkitItemManager.instance().wrap(first);
|
||||
wrappedFirst.getCustomItem().ifPresent(item -> {
|
||||
if (!item.settings().renameable()) {
|
||||
@@ -599,7 +612,36 @@ public class RecipeEventListener implements Listener {
|
||||
if (input == null) return;
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
|
||||
inventory.setResult(craftingTableRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
|
||||
if (craftingTableRecipe.hasVisualResult()) {
|
||||
inventory.setResult(craftingTableRecipe.assembleVisual(input, ItemBuildContext.of(serverPlayer)));
|
||||
} else {
|
||||
inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer)));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onCraftingFinish(CraftItemEvent event) {
|
||||
if (!Config.enableRecipeSystem()) return;
|
||||
org.bukkit.inventory.Recipe recipe = event.getRecipe();
|
||||
if (!(recipe instanceof CraftingRecipe craftingRecipe)) return;
|
||||
Key recipeId = Key.of(craftingRecipe.getKey().namespace(), craftingRecipe.getKey().value());
|
||||
Optional<Recipe<ItemStack>> optionalRecipe = this.recipeManager.recipeById(recipeId);
|
||||
// 也许是其他插件注册的配方,直接无视
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
CraftingInventory inventory = event.getInventory();
|
||||
if (!(optionalRecipe.get() instanceof CustomCraftingTableRecipe<ItemStack> craftingTableRecipe)) {
|
||||
return;
|
||||
}
|
||||
if (!craftingTableRecipe.hasVisualResult()) {
|
||||
return;
|
||||
}
|
||||
CraftingInput<ItemStack> input = getCraftingInput(inventory);
|
||||
if (input == null) return;
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player);
|
||||
inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer)));
|
||||
}
|
||||
|
||||
private CraftingInput<ItemStack> getCraftingInput(CraftingInventory inventory) {
|
||||
@@ -651,7 +693,7 @@ public class RecipeEventListener implements Listener {
|
||||
SmithingInput<ItemStack> input = getSmithingInput(inventory);
|
||||
if (smithingTrimRecipe.matches(input)) {
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), new ItemBuildContext(BukkitAdaptors.adapt(player), ContextHolder.EMPTY));
|
||||
ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), ItemBuildContext.of(BukkitAdaptors.adapt(player)));
|
||||
event.setResult(result);
|
||||
} else {
|
||||
event.setResult(null);
|
||||
@@ -675,7 +717,7 @@ public class RecipeEventListener implements Listener {
|
||||
SmithingInput<ItemStack> input = getSmithingInput(inventory);
|
||||
if (smithingTransformRecipe.matches(input)) {
|
||||
Player player = InventoryUtils.getPlayerFromInventoryEvent(event);
|
||||
ItemStack processed = smithingTransformRecipe.assemble(input, new ItemBuildContext(BukkitAdaptors.adapt(player), ContextHolder.EMPTY));
|
||||
ItemStack processed = smithingTransformRecipe.assemble(input, ItemBuildContext.of(BukkitAdaptors.adapt(player)));
|
||||
event.setResult(processed);
|
||||
} else {
|
||||
event.setResult(null);
|
||||
|
||||
@@ -55,7 +55,6 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onEntityDeath(EntityDeathEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.pack;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.BukkitAdaptors;
|
||||
import net.momirealms.craftengine.bukkit.api.event.AsyncResourcePackCacheEvent;
|
||||
import net.momirealms.craftengine.bukkit.api.event.AsyncResourcePackGenerateEvent;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.feature.ReloadCommand;
|
||||
@@ -28,10 +29,17 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
|
||||
private final BukkitCraftEngine plugin;
|
||||
|
||||
public BukkitPackManager(BukkitCraftEngine plugin) {
|
||||
super(plugin, (rf, zp) -> {
|
||||
AsyncResourcePackGenerateEvent endEvent = new AsyncResourcePackGenerateEvent(rf, zp);
|
||||
EventUtils.fireAndForget(endEvent);
|
||||
});
|
||||
super(
|
||||
plugin,
|
||||
(cd) -> {
|
||||
AsyncResourcePackCacheEvent cacheEvent = new AsyncResourcePackCacheEvent(cd);
|
||||
EventUtils.fireAndForget(cacheEvent);
|
||||
},
|
||||
(rf, zp) -> {
|
||||
AsyncResourcePackGenerateEvent endEvent = new AsyncResourcePackGenerateEvent(rf, zp);
|
||||
EventUtils.fireAndForget(endEvent);
|
||||
}
|
||||
);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@@ -45,6 +53,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (Config.sendPackOnJoin() && !VersionHelper.isOrAbove1_20_2()) {
|
||||
Player player = BukkitAdaptors.adapt(event.getPlayer());
|
||||
if (player == null) return;
|
||||
this.sendResourcePack(player);
|
||||
}
|
||||
}
|
||||
@@ -81,7 +90,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
|
||||
return;
|
||||
}
|
||||
if (!Config.sendPackOnUpload()) return;
|
||||
CraftEngine.instance().logger().info("Complete uploading resource pack");
|
||||
CraftEngine.instance().logger().info("Completed uploading resource pack");
|
||||
for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) {
|
||||
sendResourcePack(player);
|
||||
}
|
||||
@@ -98,7 +107,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
|
||||
return;
|
||||
}
|
||||
if (dataList.size() == 1) {
|
||||
ResourcePackDownloadData data = dataList.get(0);
|
||||
ResourcePackDownloadData data = dataList.getFirst();
|
||||
player.sendPacket(ResourcePackUtils.createPacket(data.uuid(), data.url(), data.sha1()), true);
|
||||
player.addResourcePackUUID(data.uuid());
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user