mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-19 15:09:15 +00:00
11
README.md
11
README.md
@@ -6,14 +6,11 @@
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/Xiao-MoMi/craft-engine/">
|
||||
<img src="https://sloc.xyz/github/Xiao-MoMi/craft-engine/?category=code" alt="Scc Count Badge"/>
|
||||
</a>
|
||||
<a href="https://deepwiki.com/Xiao-MoMi/craft-engine">
|
||||
<img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki">
|
||||
</a>
|
||||
<a href="https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine" alt="GitBook">
|
||||
<img src="https://img.shields.io/badge/Docs-User Manual-D2691E" alt="Gitbook"/>
|
||||
<img src="https://img.shields.io/badge/📙-User Manual-D2691E" alt="Gitbook"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -55,7 +52,7 @@ The code you contribute will be open-sourced under the GPLv3 license. If you pre
|
||||
### 🌍 Translations
|
||||
1. Clone this repository.
|
||||
2. Create a new language file in: `/common-files/src/main/resources/translations`
|
||||
3. Once done, submit a **pull request** for review. We appreciate your contributions!
|
||||
3. Once done, submit a **pull request** to **dev** branch for review. We appreciate your contributions!
|
||||
|
||||
## Differences Between Versions
|
||||
| Version | Official Support | Max Players | Dev Builds |
|
||||
@@ -79,7 +76,7 @@ repositories {
|
||||
```
|
||||
```kotlin
|
||||
dependencies {
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.56")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.56")
|
||||
compileOnly("net.momirealms:craft-engine-core:0.0.57")
|
||||
compileOnly("net.momirealms:craft-engine-bukkit:0.0.57")
|
||||
}
|
||||
```
|
||||
@@ -27,7 +27,7 @@ subprojects {
|
||||
expand(rootProject.properties)
|
||||
}
|
||||
|
||||
filesMatching(arrayListOf("commands.yml", "config.yml", "*/*.yml", "ignite.mod.json")) {
|
||||
filesMatching(arrayListOf("commands.yml", "config.yml")) {
|
||||
expand(
|
||||
Pair("project_version", rootProject.properties["project_version"]),
|
||||
Pair("config_version", rootProject.properties["config_version"]),
|
||||
|
||||
@@ -7,7 +7,7 @@ repositories {
|
||||
maven("https://repo.rapture.pw/repository/maven-releases/") // slime world
|
||||
maven("https://repo.infernalsuite.com/repository/maven-snapshots/") // slime world
|
||||
maven("https://repo.momirealms.net/releases/")
|
||||
maven("https://mvn.lumine.io/repository/maven-public/") // model engine
|
||||
maven("https://mvn.lumine.io/repository/maven-public/") // model engine mythic mobs
|
||||
maven("https://nexus.phoenixdevt.fr/repository/maven-public/") // mmoitems
|
||||
maven("https://repo.viaversion.com") // via
|
||||
maven("https://repo.skriptlang.org/releases/") // skript
|
||||
@@ -47,6 +47,8 @@ dependencies {
|
||||
compileOnly(platform("com.intellectualsites.bom:bom-newest:1.52"))
|
||||
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core")
|
||||
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit") { isTransitive = false }
|
||||
// MythicMobs
|
||||
compileOnly("io.lumine:Mythic-Dist:5.9.0")
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -3,11 +3,13 @@ package net.momirealms.craftengine.bukkit.compatibility;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.bettermodel.BetterModelModel;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.MMOItemsProvider;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.MythicMobsProvider;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsProvider;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.leveler.AuraSkillsLevelerProvider;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineModel;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineUtils;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicMobsListener;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook;
|
||||
@@ -104,6 +106,12 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
|
||||
}
|
||||
if (this.isPluginEnabled("AuraSkills")) {
|
||||
this.registerLevelerProvider("AuraSkills", new AuraSkillsLevelerProvider());
|
||||
logHook("AuraSkills");
|
||||
}
|
||||
if (this.isPluginEnabled("MythicMobs")) {
|
||||
BukkitItemManager.instance().registerExternalItemProvider(new MythicMobsProvider());
|
||||
new MythicMobsListener(this.plugin);
|
||||
logHook("MythicMobs");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.item;
|
||||
|
||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import net.momirealms.craftengine.core.item.ExternalItemProvider;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class MythicMobsProvider implements ExternalItemProvider<ItemStack> {
|
||||
private MythicBukkit mythicBukkit;
|
||||
|
||||
@Override
|
||||
public String plugin() {
|
||||
return "MythicMobs";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemStack build(String id, ItemBuildContext context) {
|
||||
if (mythicBukkit == null || mythicBukkit.isClosed()) {
|
||||
this.mythicBukkit = MythicBukkit.inst();
|
||||
}
|
||||
return mythicBukkit.getItemManager().getItemStack(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.mythicmobs;
|
||||
|
||||
import io.lumine.mythic.api.adapters.AbstractItemStack;
|
||||
import io.lumine.mythic.api.adapters.AbstractPlayer;
|
||||
import io.lumine.mythic.api.config.MythicLineConfig;
|
||||
import io.lumine.mythic.api.drops.DropMetadata;
|
||||
import io.lumine.mythic.api.drops.IItemDrop;
|
||||
import io.lumine.mythic.api.skills.SkillCaster;
|
||||
import io.lumine.mythic.bukkit.BukkitAdapter;
|
||||
import io.lumine.mythic.bukkit.adapters.BukkitItemStack;
|
||||
import io.lumine.mythic.core.drops.droppables.ItemDrop;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.MCUtils;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public class CraftEngineItemDrop extends ItemDrop implements IItemDrop {
|
||||
private final CustomItem<ItemStack> customItem;
|
||||
private static final Constructor<?> constructor$BukkitItemStack = ReflectionUtils.getConstructor(BukkitItemStack.class, ItemStack.class);
|
||||
private static final boolean useReflection = constructor$BukkitItemStack != null;
|
||||
|
||||
public CraftEngineItemDrop(String line, MythicLineConfig config, CustomItem<ItemStack> customItem) {
|
||||
super(line, config);
|
||||
this.customItem = customItem;
|
||||
CraftEngine.instance().debug(() -> "[MM调试] " + customItem.id() + " 注册成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractItemStack getDrop(DropMetadata dropMetadata, double amount) {
|
||||
CraftEngine.instance().debug(() -> "[MM调试] getDrop() dropMetadata={" + dropMetadata + "}, amount={" + amount + "}");
|
||||
ItemBuildContext context = ItemBuildContext.EMPTY;
|
||||
SkillCaster caster = dropMetadata.getCaster();
|
||||
if (caster != null && caster.getEntity() instanceof AbstractPlayer abstractPlayer) {
|
||||
Entity bukkitEntity = abstractPlayer.getBukkitEntity();
|
||||
if (bukkitEntity instanceof Player bukkitPlayer) {
|
||||
var player = BukkitCraftEngine.instance().adapt(bukkitPlayer);
|
||||
context = ItemBuildContext.of(player);
|
||||
}
|
||||
}
|
||||
int amountInt = MCUtils.fastFloor(amount + 0.5F);
|
||||
ItemStack itemStack = this.customItem.buildItemStack(context, amountInt);
|
||||
return adapt(itemStack).amount(amountInt);
|
||||
}
|
||||
|
||||
private static AbstractItemStack adapt(ItemStack itemStack) {
|
||||
if (useReflection) {
|
||||
try {
|
||||
return (AbstractItemStack) constructor$BukkitItemStack.newInstance(itemStack);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("adapt(ItemStack itemStack) error: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return BukkitAdapter.adapt(itemStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.mythicmobs;
|
||||
|
||||
import io.lumine.mythic.api.config.MythicLineConfig;
|
||||
import io.lumine.mythic.bukkit.events.MythicDropLoadEvent;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class MythicMobsListener implements Listener {
|
||||
private final BukkitCraftEngine plugin;
|
||||
|
||||
public MythicMobsListener(BukkitCraftEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onMythicDropLoad(MythicDropLoadEvent event) {
|
||||
if (!event.getDropName().equalsIgnoreCase("craftengine")) return;
|
||||
String argument = event.getArgument();
|
||||
plugin.debug(() -> "[MM调试] " + argument);
|
||||
Key itemId = Key.of(argument);
|
||||
this.plugin.itemManager().getCustomItem(itemId).ifPresent(customItem -> {
|
||||
String line = event.getContainer().getConfigLine();
|
||||
MythicLineConfig config = event.getConfig();
|
||||
event.register(new CraftEngineItemDrop(line, config, customItem));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,8 @@ public class ImageExpansion extends PlaceholderExpansion {
|
||||
int codepoint;
|
||||
if (param.length == 4) {
|
||||
codepoint = image.codepointAt(Integer.parseInt(param[2]), Integer.parseInt(param[3]));
|
||||
} else if (param.length == 3) {
|
||||
codepoint = image.codepointAt(Integer.parseInt(param[2]), 0);
|
||||
} else if (param.length == 2) {
|
||||
codepoint = image.codepointAt(0,0);
|
||||
} else {
|
||||
|
||||
@@ -7,14 +7,13 @@ import ch.njol.skript.lang.SkriptParser;
|
||||
import ch.njol.skript.lang.util.SimpleExpression;
|
||||
import ch.njol.util.Kleenean;
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineItems;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ExprCustomItem extends SimpleExpression<ItemStack> {
|
||||
|
||||
public static void register() {
|
||||
@@ -36,7 +35,8 @@ public class ExprCustomItem extends SimpleExpression<ItemStack> {
|
||||
String itemId = this.itemId.getSingle(e);
|
||||
if (itemId == null)
|
||||
return null;
|
||||
return new ItemStack[] {Objects.requireNonNull(CraftEngineItems.byId(Key.of(itemId))).buildItemStack(ItemBuildContext.EMPTY)};
|
||||
CustomItem<ItemStack> customItem = CraftEngineItems.byId(Key.of(itemId));
|
||||
return customItem == null ? null : new ItemStack[] {customItem.buildItemStack(ItemBuildContext.EMPTY)};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,7 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ExprEntityFurnitureID extends SimplePropertyExpression<Object, String> {
|
||||
|
||||
@@ -15,8 +15,11 @@ public class ExprEntityFurnitureID extends SimplePropertyExpression<Object, Stri
|
||||
|
||||
@Override
|
||||
public @Nullable String convert(Object object) {
|
||||
if (object instanceof Entity entity && CraftEngineFurniture.isFurniture(entity))
|
||||
return Objects.requireNonNull(CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity)).id().toString();
|
||||
if (object instanceof Entity entity && CraftEngineFurniture.isFurniture(entity)) {
|
||||
return Optional.ofNullable(CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity))
|
||||
.map(it -> it.id().toString())
|
||||
.orElse(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,27 +71,47 @@ paper {
|
||||
required = false
|
||||
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
|
||||
}
|
||||
register("NeigeItems") {
|
||||
required = false
|
||||
}
|
||||
register("MMOItems") {
|
||||
required = false
|
||||
}
|
||||
register("ModelEngine") {
|
||||
required = false
|
||||
}
|
||||
register("BetterModel") {
|
||||
required = false
|
||||
}
|
||||
register("AuraSkills") {
|
||||
required = false
|
||||
}
|
||||
register("LuckPerms") {
|
||||
required = false
|
||||
}
|
||||
register("ViaVersion") {
|
||||
required = false
|
||||
}
|
||||
register("LuckPerms") { required = false }
|
||||
register("ViaVersion") { required = false }
|
||||
|
||||
// external models
|
||||
register("ModelEngine") { required = false }
|
||||
register("BetterModel") { required = false }
|
||||
|
||||
// external items
|
||||
register("NeigeItems") { required = false }
|
||||
register("MMOItems") { required = false }
|
||||
register("MythicMobs") { required = false }
|
||||
|
||||
// leveler
|
||||
register("AuraSkills") { required = false }
|
||||
|
||||
// anti grief lib
|
||||
register("Dominion") { required = false }
|
||||
register("WorldGuard") { required = false }
|
||||
register("Kingdoms") { required = false }
|
||||
register("Lands") { required = false }
|
||||
register("IridiumSkyblock") { required = false }
|
||||
register("CrashClaim") { required = false }
|
||||
register("GriefDefender") { required = false }
|
||||
register("HuskClaims") { required = false }
|
||||
register("BentoBox") { required = false }
|
||||
register("HuskTowns") { required = false }
|
||||
register("PlotSquared") { required = false }
|
||||
register("Residence") { required = false }
|
||||
register("SuperiorSkyblock2") { required = false }
|
||||
register("Towny") { required = false }
|
||||
register("FabledSkyBlock") { required = false }
|
||||
register("GriefPrevention") { required = false }
|
||||
register("RedProtect") { required = false }
|
||||
register("Landlord") { required = false }
|
||||
register("uSkyBlock") { required = false }
|
||||
register("XClaim") { required = false }
|
||||
register("UltimateClaims") { required = false }
|
||||
register("UltimateClans") { required = false }
|
||||
register("PreciousStones") { required = false }
|
||||
register("hClaims") { required = false }
|
||||
register("Factions") { required = false }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public class PaperCraftEngineBootstrap implements PluginBootstrap {
|
||||
new ModernEventHandler(context, this.plugin).register();
|
||||
} else {
|
||||
try {
|
||||
logger.info("Patching the server...");
|
||||
RuntimePatcher.patch(this.plugin);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to patch server", e);
|
||||
|
||||
@@ -52,7 +52,7 @@ public final class CraftEngineFurniture {
|
||||
public static BukkitFurniture place(Location location, Key furnitureId) {
|
||||
CustomFurniture furniture = byId(furnitureId);
|
||||
if (furniture == null) return null;
|
||||
return place(location, furnitureId, furniture.getAnyPlacement());
|
||||
return place(location, furnitureId, furniture.getAnyAnchorType());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,6 @@ import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -371,19 +370,18 @@ public class BlockEventListener implements Listener {
|
||||
// for vanilla blocks
|
||||
if (event.getChangedType() == Material.NOTE_BLOCK) {
|
||||
Block block = event.getBlock();
|
||||
Block sourceBlock = event.getSourceBlock();
|
||||
if (block.getX() == sourceBlock.getX() && block.getX() == sourceBlock.getZ()) {
|
||||
World world = block.getWorld();
|
||||
Location location = block.getLocation();
|
||||
Block sourceBlock = event.getSourceBlock();
|
||||
BlockFace direction = sourceBlock.getFace(block);
|
||||
if (direction == BlockFace.UP || direction == BlockFace.DOWN) {
|
||||
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world);
|
||||
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
|
||||
Object blockPos = LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
||||
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos);
|
||||
if (direction == BlockFace.UP) {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, 0);
|
||||
if (block.getY() > sourceBlock.getY()) {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, Config.maxNoteBlockChainUpdate());
|
||||
} else {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, 0);
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, Config.maxNoteBlockChainUpdate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,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.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.RegistryUtils;
|
||||
@@ -31,7 +32,6 @@ import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.pack.ResourceLocation;
|
||||
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
|
||||
@@ -45,7 +45,6 @@ import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -93,11 +92,9 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
this.blockParser = new BlockParser();
|
||||
this.initVanillaRegistry();
|
||||
this.loadMappingsAndAdditionalBlocks();
|
||||
if (!plugin.requiresRestart()) {
|
||||
this.registerBlocks();
|
||||
this.registerEmptyBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
@@ -163,9 +160,9 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
for (Map.Entry<Integer, List<String>> entry : this.clientBoundTags.entrySet()) {
|
||||
list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.instance$Registries$BLOCK, list));
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
this.plugin.networkManager().sendPacket(this.plugin.adapt(player), packet);
|
||||
Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.BLOCK, list));
|
||||
for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) {
|
||||
player.sendPacket(packet, false);
|
||||
}
|
||||
// 如果空,那么新来的玩家就没必要收到更新包了
|
||||
if (list.isEmpty()) {
|
||||
@@ -276,19 +273,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
|
||||
private void initVanillaRegistry() {
|
||||
int vanillaStateCount;
|
||||
if (this.plugin.hasMod()) {
|
||||
try {
|
||||
Class<?> modClass = ReflectionUtils.getClazz(CraftEngine.MOD_CLASS);
|
||||
Field amountField = ReflectionUtils.getDeclaredField(modClass, "vanillaRegistrySize");
|
||||
vanillaStateCount = amountField.getInt(null);
|
||||
} catch (Exception e) {
|
||||
vanillaStateCount = RegistryUtils.currentBlockRegistrySize();
|
||||
this.plugin.logger().severe("Fatal error", e);
|
||||
}
|
||||
} else {
|
||||
vanillaStateCount = RegistryUtils.currentBlockRegistrySize();
|
||||
}
|
||||
int vanillaStateCount = RegistryUtils.currentBlockRegistrySize();
|
||||
this.plugin.logger().info("Vanilla block count: " + vanillaStateCount);
|
||||
BlockStateUtils.init(vanillaStateCount);
|
||||
}
|
||||
@@ -512,10 +497,13 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.model.invalid_path", modelPath);
|
||||
}
|
||||
json.addProperty("model", modelPath);
|
||||
if (singleModelMap.containsKey("x")) json.addProperty("x", ResourceConfigUtils.getAsInt(singleModelMap.get("x"), "x"));
|
||||
if (singleModelMap.containsKey("y")) json.addProperty("y", ResourceConfigUtils.getAsInt(singleModelMap.get("y"), "y"));
|
||||
if (singleModelMap.containsKey("x"))
|
||||
json.addProperty("x", ResourceConfigUtils.getAsInt(singleModelMap.get("x"), "x"));
|
||||
if (singleModelMap.containsKey("y"))
|
||||
json.addProperty("y", ResourceConfigUtils.getAsInt(singleModelMap.get("y"), "y"));
|
||||
if (singleModelMap.containsKey("uvlock")) json.addProperty("uvlock", (boolean) singleModelMap.get("uvlock"));
|
||||
if (singleModelMap.containsKey("weight")) json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight"));
|
||||
if (singleModelMap.containsKey("weight"))
|
||||
json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight"));
|
||||
Map<String, Object> generationMap = MiscUtils.castToMap(singleModelMap.get("generation"), true);
|
||||
if (generationMap != null) {
|
||||
prepareModelGeneration(ModelGeneration.of(Key.of(modelPath), generationMap));
|
||||
@@ -591,6 +579,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
Object resourceLocation = KeyUtils.toResourceLocation(BlockKeys.NOTE_BLOCK);
|
||||
Object block = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation);
|
||||
Object stateDefinition = CoreReflections.field$Block$StateDefinition.get(block);
|
||||
@SuppressWarnings("unchecked")
|
||||
ImmutableList<Object> states = (ImmutableList<Object>) CoreReflections.field$StateDefinition$states.get(stateDefinition);
|
||||
for (Object state : states) {
|
||||
BlockStateUtils.CLIENT_SIDE_NOTE_BLOCKS.put(state, new Object());
|
||||
@@ -723,14 +712,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
Object blockHolder;
|
||||
Object resourceLocation = createResourceLocation(realBlockKey);
|
||||
|
||||
if (this.plugin.hasMod()) {
|
||||
newRealBlock = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation);
|
||||
newBlockState = getOnlyBlockState(newRealBlock);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<Object> optionalHolder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.BLOCK, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, resourceLocation));
|
||||
blockHolder = optionalHolder.get();
|
||||
} else {
|
||||
try {
|
||||
newRealBlock = BlockGenerator.generateBlock(clientSideBlockType, clientSideBlock, blockProperties);
|
||||
} catch (Throwable throwable) {
|
||||
@@ -744,7 +725,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
newBlockState = getOnlyBlockState(newRealBlock);
|
||||
CoreReflections.method$IdMapper$add.invoke(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, newBlockState);
|
||||
}
|
||||
|
||||
if (isNoteBlock) {
|
||||
BlockStateUtils.CLIENT_SIDE_NOTE_BLOCKS.put(newBlockState, new Object());
|
||||
@@ -782,7 +762,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
private Object createBlockProperties(Key realBlockKey) throws Exception {
|
||||
Object blockProperties = CoreReflections.method$BlockBehaviour$Properties$of.invoke(null);
|
||||
Object realBlockResourceLocation = createResourceLocation(realBlockKey);
|
||||
Object realBlockResourceKey = CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, realBlockResourceLocation);
|
||||
Object realBlockResourceKey = CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.BLOCK, realBlockResourceLocation);
|
||||
if (CoreReflections.field$BlockBehaviour$Properties$id != null) {
|
||||
CoreReflections.field$BlockBehaviour$Properties$id.set(blockProperties, realBlockResourceKey);
|
||||
}
|
||||
|
||||
@@ -129,13 +129,12 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
// init cache
|
||||
CoreReflections.method$BlockStateBase$initCache.invoke(mcBlockState);
|
||||
// set block light
|
||||
if (settings.blockLight() != -1) {
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(state.vanillaBlockState().handle());
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
CoreReflections.field$BlockStateBase$lightBlock.set(mcBlockState, settings.blockLight());
|
||||
CoreReflections.field$BlockStateBase$lightBlock.set(mcBlockState, blockLight);
|
||||
} else {
|
||||
Object cache = CoreReflections.field$BlockStateBase$cache.get(mcBlockState);
|
||||
CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, settings.blockLight());
|
||||
}
|
||||
CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, blockLight);
|
||||
}
|
||||
// set fluid later
|
||||
if (settings.fluidState()) {
|
||||
@@ -151,7 +150,7 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(state.customBlockState().registryId());
|
||||
Set<Object> tags = new HashSet<>();
|
||||
for (Key tag : settings.tags()) {
|
||||
tags.add(CoreReflections.method$TagKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, KeyUtils.toResourceLocation(tag)));
|
||||
tags.add(CoreReflections.method$TagKey$create.invoke(null, MRegistries.BLOCK, KeyUtils.toResourceLocation(tag)));
|
||||
}
|
||||
CoreReflections.field$Holder$Reference$tags.set(holder, tags);
|
||||
// set burning properties
|
||||
|
||||
@@ -65,7 +65,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
|
||||
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object world = args[1];
|
||||
Object blockPos = args[2];
|
||||
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,7 +86,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
|
||||
return state;
|
||||
}
|
||||
if (this.delay != 0) {
|
||||
CoreReflections.method$LevelAccessor$scheduleTick.invoke(level, blockPos, thisBlock, this.delay);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(level, blockPos, thisBlock, this.delay);
|
||||
return state;
|
||||
}
|
||||
if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) {
|
||||
|
||||
@@ -36,7 +36,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
public void onPlace(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object world = args[1];
|
||||
Object blockPos = args[2];
|
||||
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,7 +50,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior {
|
||||
world = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2);
|
||||
return args[0];
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior {
|
||||
boolean lit = state.get(this.litProperty);
|
||||
if (lit != FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) {
|
||||
if (lit) {
|
||||
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 4);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 4);
|
||||
} else {
|
||||
// TODO Call Event
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2);
|
||||
|
||||
@@ -85,7 +85,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior {
|
||||
LeavesBlockBehavior behavior = optionalBehavior.get();
|
||||
int distance = behavior.getDistanceAt(neighborState) + 1;
|
||||
if (distance != 1 || behavior.getDistance(thisState) != distance) {
|
||||
CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
private void generateTree(Object world, Object blockPos, Object blockState, Object randomSource) throws Exception {
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.instance$Registries$CONFIGURED_FEATURE);
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.CONFIGURED_FEATURE);
|
||||
if (registry == null) return;
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createFeatureKey(treeFeature()));
|
||||
|
||||
@@ -7,20 +7,21 @@ public interface EntityData<T> {
|
||||
Object serializer();
|
||||
int id();
|
||||
T defaultValue();
|
||||
Object entityDataAccessor();
|
||||
|
||||
default Object createEntityDataIfNotDefaultValue(T value) {
|
||||
if (defaultValue().equals(value)) return null;
|
||||
return EntityDataValue.create(id(), serializer(), value);
|
||||
return EntityDataValue.create(id(), serializer(), entityDataAccessor(), value);
|
||||
}
|
||||
|
||||
default void addEntityDataIfNotDefaultValue(T value, List<Object> list) {
|
||||
if (!defaultValue().equals(value)) {
|
||||
list.add(EntityDataValue.create(id(), serializer(), value));
|
||||
list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value));
|
||||
}
|
||||
}
|
||||
|
||||
default void addEntityData(T value, List<Object> list) {
|
||||
list.add(EntityDataValue.create(id(), serializer(), value));
|
||||
list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value));
|
||||
}
|
||||
|
||||
static <T> EntityData<T> of(int id, Object serializer, T defaultValue) {
|
||||
|
||||
@@ -98,8 +98,7 @@ public class EntityDataValue {
|
||||
throw new IllegalAccessError("Utility class");
|
||||
}
|
||||
|
||||
public static Object create(int id, Object serializer, Object value) {
|
||||
Object entityDataAccessor = FastNMS.INSTANCE.constructor$EntityDataAccessor(id, serializer);
|
||||
public static Object create(int id, Object serializer, Object entityDataAccessor, Object value) {
|
||||
return FastNMS.INSTANCE.method$SynchedEntityData$DataValue$create(entityDataAccessor, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package net.momirealms.craftengine.bukkit.entity.data;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
|
||||
public class SimpleEntityData<T> implements EntityData<T> {
|
||||
private final int id;
|
||||
private final Object serializer;
|
||||
private final T defaultValue;
|
||||
private final Object entityDataAccessor;
|
||||
|
||||
public SimpleEntityData(int id, Object serializer, T defaultValue) {
|
||||
this.id = id;
|
||||
this.serializer = serializer;
|
||||
this.defaultValue = defaultValue;
|
||||
this.entityDataAccessor = FastNMS.INSTANCE.constructor$EntityDataAccessor(id, serializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,4 +29,9 @@ public class SimpleEntityData<T> implements EntityData<T> {
|
||||
public T defaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object entityDataAccessor() {
|
||||
return entityDataAccessor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.*;
|
||||
public class BukkitFurniture implements Furniture {
|
||||
private final Key id;
|
||||
private final CustomFurniture furniture;
|
||||
private final AnchorType anchorType;
|
||||
private final CustomFurniture.Placement placement;
|
||||
private FurnitureExtraData extraData;
|
||||
// location
|
||||
private final Location location;
|
||||
@@ -61,7 +61,7 @@ public class BukkitFurniture implements Furniture {
|
||||
this.id = furniture.id();
|
||||
this.extraData = extraData;
|
||||
this.baseEntityId = baseEntity.getEntityId();
|
||||
this.anchorType = extraData.anchorType().orElse(furniture.getAnyPlacement());
|
||||
|
||||
this.location = baseEntity.getLocation();
|
||||
this.baseEntity = new WeakReference<>(baseEntity);
|
||||
this.furniture = furniture;
|
||||
@@ -70,7 +70,7 @@ public class BukkitFurniture implements Furniture {
|
||||
List<Integer> mainEntityIds = new IntArrayList();
|
||||
mainEntityIds.add(this.baseEntityId);
|
||||
|
||||
CustomFurniture.Placement placement = furniture.getPlacement(anchorType);
|
||||
this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType));
|
||||
// bind external furniture
|
||||
Optional<ExternalModel> optionalExternal = placement.externalModel();
|
||||
if (optionalExternal.isPresent()) {
|
||||
@@ -171,7 +171,7 @@ public class BukkitFurniture implements Furniture {
|
||||
|
||||
@NotNull
|
||||
public Location dropLocation() {
|
||||
Optional<Vector3f> dropOffset = config().getPlacement(this.anchorType).dropOffset();
|
||||
Optional<Vector3f> dropOffset = this.placement.dropOffset();
|
||||
if (dropOffset.isEmpty()) {
|
||||
return location();
|
||||
}
|
||||
@@ -275,7 +275,7 @@ public class BukkitFurniture implements Furniture {
|
||||
|
||||
@Override
|
||||
public @NotNull AnchorType anchorType() {
|
||||
return this.anchorType;
|
||||
return this.placement.anchorType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -49,7 +49,7 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement {
|
||||
Vector3f offset = conjugated.transform(new Vector3f(position()));
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.xRot(),
|
||||
MEntityTypes.instance$EntityType$ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
));
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(dyedColor)));
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY);
|
||||
public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION);
|
||||
public static Class<?> COLLISION_ENTITY_CLASS = Interaction.class;
|
||||
public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.instance$EntityType$INTERACTION;
|
||||
public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.INTERACTION;
|
||||
public static ColliderType COLLISION_ENTITY_TYPE = ColliderType.INTERACTION;
|
||||
private static BukkitFurnitureManager instance;
|
||||
private final BukkitCraftEngine plugin;
|
||||
@@ -70,7 +70,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
public BukkitFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) {
|
||||
Optional<AnchorType> optionalAnchorType = extraData.anchorType();
|
||||
if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) {
|
||||
extraData.anchorType(furniture.getAnyPlacement());
|
||||
extraData.anchorType(furniture.getAnyAnchorType());
|
||||
}
|
||||
Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> {
|
||||
ItemDisplay display = (ItemDisplay) entity;
|
||||
@@ -92,7 +92,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
@Override
|
||||
public void delayedInit() {
|
||||
COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class;
|
||||
NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.instance$EntityType$INTERACTION : MEntityTypes.instance$EntityType$OAK_BOAT;
|
||||
NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.INTERACTION : MEntityTypes.OAK_BOAT;
|
||||
COLLISION_ENTITY_TYPE = Config.colliderType();
|
||||
Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.javaPlugin());
|
||||
Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin());
|
||||
|
||||
@@ -62,7 +62,7 @@ public class InteractionHitBox extends AbstractHitBox {
|
||||
float yaw = position.xRot();
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw,
|
||||
MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), true);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true);
|
||||
if (canUseItemOn()) {
|
||||
|
||||
@@ -61,7 +61,7 @@ public class ShulkerHitBox extends AbstractHitBox {
|
||||
if (interactionEntity) {
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f, z - offset.z, 0, yaw,
|
||||
MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), true);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true);
|
||||
if (canUseOn) {
|
||||
@@ -80,7 +80,7 @@ public class ShulkerHitBox extends AbstractHitBox {
|
||||
if (interactionEntity) {
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f - shulkerHeight + scale, z - offset.z, 0, yaw,
|
||||
MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), true);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true);
|
||||
if (canUseOn) {
|
||||
@@ -102,14 +102,14 @@ public class ShulkerHitBox extends AbstractHitBox {
|
||||
// first interaction
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f, z - offset.z, 0, yaw,
|
||||
MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), true);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true);
|
||||
// second interaction
|
||||
double distance = shulkerHeight - scale;
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityIds[3], UUID.randomUUID(), x + offset.x + shulkerDirection.stepX() * distance, y + offset.y - 0.005f, z - offset.z + shulkerDirection.stepZ() * distance, 0, yaw,
|
||||
MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), true);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[3], List.copyOf(cachedInteractionValues)), true);
|
||||
if (canUseOn) {
|
||||
@@ -213,11 +213,11 @@ public class ShulkerHitBox extends AbstractHitBox {
|
||||
double processedY = (fractionalPart >= 0.5) ? integerPart + 1 : originalY;
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityIds[0], UUID.randomUUID(), x + offset.x, originalY, z - offset.z, 0, yaw,
|
||||
MEntityTypes.instance$EntityType$ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), false);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityIds[1], UUID.randomUUID(), x + offset.x, processedY, z - offset.z, 0, yaw,
|
||||
MEntityTypes.instance$EntityType$SHULKER, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
MEntityTypes.SHULKER, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
), false);
|
||||
packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[1], List.copyOf(this.cachedShulkerValues)), false);
|
||||
// add passengers
|
||||
|
||||
@@ -11,4 +11,9 @@ public class BukkitCustomProjectile extends AbstractCustomProjectile {
|
||||
public BukkitCustomProjectile(ProjectileMeta meta, Projectile projectile, Item<ItemStack> projectileItem) {
|
||||
super(meta, new BukkitProjectile(projectile), projectileItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitProjectile projectile() {
|
||||
return (BukkitProjectile) super.projectile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
private static BukkitProjectileManager instance;
|
||||
private final BukkitCraftEngine plugin;
|
||||
private final Map<Integer, BukkitCustomProjectile> projectiles;
|
||||
// 会被netty线程访问
|
||||
private final Map<Integer, BukkitCustomProjectile> projectiles = new ConcurrentHashMap<>();
|
||||
|
||||
public BukkitProjectileManager(BukkitCraftEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
this.projectiles = new ConcurrentHashMap<>();
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,8 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
wrapped.getCustomItem().ifPresent(it -> {
|
||||
ProjectileMeta meta = it.settings().projectileMeta();
|
||||
if (meta != null) {
|
||||
this.projectiles.put(projectile.getEntityId(), new BukkitCustomProjectile(meta, projectile, wrapped));
|
||||
BukkitCustomProjectile customProjectile = new BukkitCustomProjectile(meta, projectile, wrapped);
|
||||
this.projectiles.put(projectile.getEntityId(), customProjectile);
|
||||
new ProjectileInjectTask(projectile);
|
||||
}
|
||||
});
|
||||
@@ -161,7 +162,8 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
public class ProjectileInjectTask implements Runnable {
|
||||
private final Projectile projectile;
|
||||
private final SchedulerTask task;
|
||||
private boolean injected;
|
||||
private Object cachedServerEntity;
|
||||
private int lastInjectedInterval = 0;
|
||||
|
||||
public ProjectileInjectTask(Projectile projectile) {
|
||||
this.projectile = projectile;
|
||||
@@ -178,32 +180,42 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
this.task.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(this.projectile);
|
||||
if (!this.injected) {
|
||||
// 获取server entity
|
||||
if (this.cachedServerEntity == null) {
|
||||
Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity);
|
||||
if (trackedEntity == null) {
|
||||
return;
|
||||
if (trackedEntity == null) return;
|
||||
Object serverEntity = FastNMS.INSTANCE.field$ChunkMap$TrackedEntity$serverEntity(trackedEntity);
|
||||
if (serverEntity == null) return;
|
||||
this.cachedServerEntity = serverEntity;
|
||||
}
|
||||
Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity);
|
||||
if (serverEntity == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
CoreReflections.field$ServerEntity$updateInterval.set(serverEntity, 1);
|
||||
this.injected = true;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to update server entity tracking interval", e);
|
||||
}
|
||||
}
|
||||
if (canSpawnParticle(nmsEntity)) {
|
||||
|
||||
boolean inGround = FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity);
|
||||
if (canSpawnParticle(nmsEntity, inGround)) {
|
||||
this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0);
|
||||
}
|
||||
if (inGround) {
|
||||
updateProjectileUpdateInterval(Integer.MAX_VALUE);
|
||||
} else {
|
||||
updateProjectileUpdateInterval(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canSpawnParticle(Object nmsEntity) {
|
||||
private void updateProjectileUpdateInterval(int updateInterval) {
|
||||
if (this.lastInjectedInterval == updateInterval) return;
|
||||
try {
|
||||
CoreReflections.methodHandle$ServerEntity$updateIntervalSetter.invokeExact(this.cachedServerEntity, updateInterval);
|
||||
this.lastInjectedInterval = updateInterval;
|
||||
} catch (Throwable e) {
|
||||
BukkitProjectileManager.this.plugin.logger().warn("Failed to update server entity update interval for " + this.projectile.getType().getKey() + "[" + this.projectile.getUniqueId() + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canSpawnParticle(Object nmsEntity, boolean inGround) {
|
||||
if (!FastNMS.INSTANCE.field$Entity$wasTouchingWater(nmsEntity)) return false;
|
||||
if (CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity)) {
|
||||
return !FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity);
|
||||
return !inGround;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.*;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
@@ -10,7 +10,6 @@ import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -19,22 +18,23 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
private final Material material;
|
||||
private final Object item;
|
||||
private final Object clientItem;
|
||||
|
||||
public BukkitCustomItem(Holder<Key> id, Key materialKey, Material material,
|
||||
public BukkitCustomItem(Holder<Key> id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey,
|
||||
List<ItemBehavior> behaviors,
|
||||
List<ItemDataModifier<ItemStack>> modifiers, List<ItemDataModifier<ItemStack>> clientBoundModifiers,
|
||||
ItemSettings settings,
|
||||
Map<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||
super(id, materialKey, behaviors, modifiers, clientBoundModifiers, settings, events);
|
||||
this.material = material;
|
||||
super(id, materialKey, clientBoundMaterialKey, behaviors, modifiers, clientBoundModifiers, settings, events);
|
||||
this.item = item;
|
||||
this.clientItem = clientItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack buildItemStack(ItemBuildContext context, int count) {
|
||||
ItemStack item = new ItemStack(this.material);
|
||||
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(this.item, count));
|
||||
Item<ItemStack> wrapped = BukkitCraftEngine.instance().itemManager().wrap(item);
|
||||
wrapped.count(count);
|
||||
for (ItemDataModifier<ItemStack> modifier : this.modifiers) {
|
||||
modifier.apply(wrapped, context);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
|
||||
@Override
|
||||
public Item<ItemStack> buildItem(ItemBuildContext context) {
|
||||
ItemStack item = new ItemStack(this.material);
|
||||
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(this.item, 1));
|
||||
Item<ItemStack> wrapped = BukkitCraftEngine.instance().itemManager().wrap(item);
|
||||
for (ItemDataModifier<ItemStack> modifier : dataModifiers()) {
|
||||
modifier.apply(wrapped, context);
|
||||
@@ -51,23 +51,33 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
return BukkitCraftEngine.instance().itemManager().wrap(wrapped.load());
|
||||
}
|
||||
|
||||
public static Builder<ItemStack> builder(Material material) {
|
||||
return new BuilderImpl(material);
|
||||
public Object clientItem() {
|
||||
return clientItem;
|
||||
}
|
||||
|
||||
public Object item() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public static Builder<ItemStack> builder(Object item, Object clientBoundItem) {
|
||||
return new BuilderImpl(item, clientBoundItem);
|
||||
}
|
||||
|
||||
public static class BuilderImpl implements Builder<ItemStack> {
|
||||
private Holder<Key> id;
|
||||
private Key materialKey;
|
||||
private final Material material;
|
||||
private Key itemKey;
|
||||
private final Object item;
|
||||
private Key clientBoundItemKey;
|
||||
private final Object clientBoundItem;
|
||||
private final Map<EventTrigger, List<Function<PlayerOptionalContext>>> events = new EnumMap<>(EventTrigger.class);
|
||||
private final List<ItemBehavior> behaviors = new ArrayList<>(4);
|
||||
private final List<ItemDataModifier<ItemStack>> modifiers = new ArrayList<>(4);
|
||||
private final List<ItemDataModifier<ItemStack>> clientBoundModifiers = new ArrayList<>(4);
|
||||
private ItemSettings settings;
|
||||
|
||||
public BuilderImpl(Material material) {
|
||||
this.material = material;
|
||||
this.materialKey = KeyUtils.namespacedKey2Key(material.getKey());
|
||||
public BuilderImpl(Object item, Object clientBoundItem) {
|
||||
this.item = item;
|
||||
this.clientBoundItem = clientBoundItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,9 +86,15 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<ItemStack> clientBoundMaterial(Key clientBoundMaterial) {
|
||||
this.clientBoundItemKey = clientBoundMaterial;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<ItemStack> material(Key material) {
|
||||
this.materialKey = material;
|
||||
this.itemKey = material;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -133,7 +149,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
@Override
|
||||
public CustomItem<ItemStack> build() {
|
||||
this.modifiers.addAll(this.settings.modifiers());
|
||||
return new BukkitCustomItem(this.id, this.materialKey, this.material, List.copyOf(this.behaviors),
|
||||
return new BukkitCustomItem(this.id, this.item, this.clientBoundItem, this.itemKey, this.clientBoundItemKey, List.copyOf(this.behaviors),
|
||||
List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import com.saicone.rtag.item.ItemTagStream;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
|
||||
import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener;
|
||||
@@ -12,6 +13,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
|
||||
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
@@ -43,6 +45,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
static {
|
||||
registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS);
|
||||
registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET);
|
||||
registerVanillaItemExtraBehavior(FlintAndSteelItemBehavior.INSTANCE, ItemKeys.FLINT_AND_STEEL);
|
||||
}
|
||||
|
||||
private static BukkitItemManager instance;
|
||||
@@ -198,9 +201,19 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CustomItem.Builder<ItemStack> createPlatformItemBuilder(Holder<Key> id, Key materialId) {
|
||||
Material material = ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(materialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString()));
|
||||
return BukkitCustomItem.builder(material).material(materialId).id(id);
|
||||
protected CustomItem.Builder<ItemStack> createPlatformItemBuilder(Holder<Key> id, Key materialId, Key clientBoundMaterialId) {
|
||||
Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(materialId));
|
||||
Object clientBoundItem = materialId == clientBoundMaterialId ? item : FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(clientBoundMaterialId));
|
||||
if (item == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString());
|
||||
}
|
||||
if (clientBoundItem == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.item.invalid_material", clientBoundMaterialId.toString());
|
||||
}
|
||||
return BukkitCustomItem.builder(item, clientBoundItem)
|
||||
.id(id)
|
||||
.material(materialId)
|
||||
.clientBoundMaterial(clientBoundMaterialId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -214,7 +227,7 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
.orElseGet(() -> ((WritableRegistry<Key>) BuiltInRegistries.OPTIMIZED_ITEM_ID)
|
||||
.register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id));
|
||||
Object resourceLocation = KeyUtils.toResourceLocation(id.namespace(), id.value());
|
||||
Object mcHolder = ((Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.ITEM, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$ITEM, resourceLocation))).get();
|
||||
Object mcHolder = ((Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.ITEM, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.ITEM, resourceLocation))).get();
|
||||
Set<Object> tags = (Set<Object>) CoreReflections.field$Holder$Reference$tags.get(mcHolder);
|
||||
for (Object tag : tags) {
|
||||
Key tagId = Key.of(CoreReflections.field$TagKey$location.get(tag).toString());
|
||||
|
||||
@@ -111,6 +111,9 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
private void setComponentInternal(Object type, DynamicOps ops, Object value) {
|
||||
if (value == null) return;
|
||||
Object componentType = ensureDataComponentType(type);
|
||||
if (componentType == null) {
|
||||
return;
|
||||
}
|
||||
Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType);
|
||||
try {
|
||||
DataResult<Object> result = codec.parse(ops, value);
|
||||
@@ -162,4 +165,9 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
public void count(int amount) {
|
||||
this.item.setAmount(Math.max(amount, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shrink(int amount) {
|
||||
count(count() - amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,18 +8,9 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
|
||||
private final RtagItem rtagItem;
|
||||
private int count;
|
||||
|
||||
public LegacyItemWrapper(RtagItem rtagItem, int count) {
|
||||
public LegacyItemWrapper(RtagItem rtagItem) {
|
||||
this.rtagItem = rtagItem;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem() {
|
||||
ItemStack itemStack = this.rtagItem.getItem();
|
||||
itemStack.setAmount(this.count);
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
public boolean setTag(Object value, Object... path) {
|
||||
@@ -49,12 +40,12 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
|
||||
}
|
||||
|
||||
public int count() {
|
||||
return this.count;
|
||||
return getItem().getAmount();
|
||||
}
|
||||
|
||||
public void count(int amount) {
|
||||
if (amount < 0) amount = 0;
|
||||
this.count = amount;
|
||||
getItem().setAmount(amount);
|
||||
}
|
||||
|
||||
public Object getExactTag(Object... path) {
|
||||
@@ -75,9 +66,12 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
|
||||
|
||||
@Override
|
||||
public ItemStack load() {
|
||||
ItemStack itemStack = this.rtagItem.load();
|
||||
itemStack.setAmount(Math.max(this.count, 0));
|
||||
return itemStack;
|
||||
return this.rtagItem.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem() {
|
||||
return this.rtagItem.getItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,6 +81,13 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
|
||||
|
||||
@Override
|
||||
public ItemWrapper<ItemStack> copyWithCount(int count) {
|
||||
return new LegacyItemWrapper(new RtagItem(this.rtagItem.loadCopy()), count);
|
||||
ItemStack copied = this.rtagItem.loadCopy();
|
||||
copied.setAmount(count);
|
||||
return new LegacyItemWrapper(new RtagItem(copied));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shrink(int amount) {
|
||||
this.count(count() - amount);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -25,11 +26,25 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
|
||||
|
||||
@Override
|
||||
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
|
||||
if (!wrapped.hasTag(NETWORK_ITEM_TAG)) return Optional.empty();
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
boolean hasDifferentMaterial = false;
|
||||
if (optionalCustomItem.isPresent()) {
|
||||
BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get();
|
||||
if (customItem.item() != FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject())) {
|
||||
wrapped = wrapped.unsafeTransmuteCopy(customItem.item(), wrapped.count());
|
||||
hasDifferentMaterial = true;
|
||||
}
|
||||
}
|
||||
if (!wrapped.hasTag(NETWORK_ITEM_TAG)) {
|
||||
if (hasDifferentMaterial) {
|
||||
return Optional.of(wrapped);
|
||||
}
|
||||
}
|
||||
CompoundTag networkData = (CompoundTag) wrapped.getNBTTag(NETWORK_ITEM_TAG);
|
||||
if (networkData == null) return Optional.empty();
|
||||
wrapped.removeTag(NETWORK_ITEM_TAG);
|
||||
@@ -46,12 +61,16 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) {
|
||||
if (!Config.interceptItem()) return Optional.empty();
|
||||
return new OtherItem(wrapped).process();
|
||||
return new OtherItem(wrapped, false).process();
|
||||
} else {
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get();
|
||||
boolean hasDifferentMaterial = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()) != customItem.clientItem();
|
||||
if (hasDifferentMaterial) {
|
||||
wrapped = wrapped.unsafeTransmuteCopy(customItem.clientItem(), wrapped.count());
|
||||
}
|
||||
if (!customItem.hasClientBoundDataModifier()) {
|
||||
if (!Config.interceptItem()) return Optional.empty();
|
||||
return new OtherItem(wrapped).process();
|
||||
if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty();
|
||||
return new OtherItem(wrapped, hasDifferentMaterial).process();
|
||||
} else {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
Tag argumentTag = wrapped.getNBTTag(ArgumentModifier.ARGUMENTS_TAG);
|
||||
@@ -77,7 +96,12 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
|
||||
processLore(wrapped, tag::put);
|
||||
}
|
||||
}
|
||||
if (tag.isEmpty()) return Optional.empty();
|
||||
if (tag.isEmpty()) {
|
||||
if (hasDifferentMaterial) {
|
||||
return Optional.of(wrapped);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
wrapped.setTag(tag, NETWORK_ITEM_TAG);
|
||||
return Optional.of(wrapped);
|
||||
}
|
||||
@@ -130,9 +154,11 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
|
||||
private final Item<ItemStack> item;
|
||||
private boolean globalChanged = false;
|
||||
private CompoundTag networkTag;
|
||||
private final boolean forceReturn;
|
||||
|
||||
public OtherItem(Item<ItemStack> item) {
|
||||
public OtherItem(Item<ItemStack> item, boolean forceReturn) {
|
||||
this.item = item;
|
||||
this.forceReturn = forceReturn;
|
||||
}
|
||||
|
||||
public Optional<Item<ItemStack>> process() {
|
||||
@@ -145,6 +171,8 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler<ItemStack> {
|
||||
if (this.globalChanged) {
|
||||
this.item.setTag(this.networkTag, NETWORK_ITEM_TAG);
|
||||
return Optional.of(this.item);
|
||||
} else if (this.forceReturn) {
|
||||
return Optional.of(this.item);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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.*;
|
||||
import net.momirealms.craftengine.core.item.modifier.ArgumentModifier;
|
||||
@@ -30,8 +31,22 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
public Optional<Item<ItemStack>> c2s(Item<ItemStack> wrapped) {
|
||||
Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA);
|
||||
if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty();
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
boolean hasDifferentMaterial = false;
|
||||
if (optionalCustomItem.isPresent()) {
|
||||
BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get();
|
||||
if (customItem.item() != FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject())) {
|
||||
wrapped = wrapped.unsafeTransmuteCopy(customItem.item(), wrapped.count());
|
||||
hasDifferentMaterial = true;
|
||||
}
|
||||
}
|
||||
CompoundTag networkData = compoundTag.getCompound(NETWORK_ITEM_TAG);
|
||||
if (networkData == null) return Optional.empty();
|
||||
if (networkData == null) {
|
||||
if (hasDifferentMaterial) {
|
||||
return Optional.of(wrapped);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
compoundTag.remove(NETWORK_ITEM_TAG);
|
||||
for (Map.Entry<String, Tag> entry : networkData.entrySet()) {
|
||||
if (entry.getValue() instanceof CompoundTag tag) {
|
||||
@@ -48,12 +63,16 @@ 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).process();
|
||||
return new OtherItem(wrapped, false).process();
|
||||
} else {
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get();
|
||||
boolean hasDifferentMaterial = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()) != customItem.clientItem();
|
||||
if (hasDifferentMaterial) {
|
||||
wrapped = wrapped.unsafeTransmuteCopy(customItem.clientItem(), wrapped.count());
|
||||
}
|
||||
if (!customItem.hasClientBoundDataModifier()) {
|
||||
if (!Config.interceptItem()) return Optional.empty();
|
||||
return new OtherItem(wrapped).process();
|
||||
if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty();
|
||||
return new OtherItem(wrapped, hasDifferentMaterial).process();
|
||||
} else {
|
||||
CompoundTag customData = Optional.ofNullable(wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag());
|
||||
CompoundTag arguments = customData.getCompound(ArgumentModifier.ARGUMENTS_TAG);
|
||||
@@ -86,7 +105,10 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
else processLegacyLore(wrapped, () -> tag);
|
||||
}
|
||||
}
|
||||
if (tag.isEmpty()) return Optional.empty();
|
||||
if (tag.isEmpty()) {
|
||||
if (hasDifferentMaterial) return Optional.of(wrapped);
|
||||
return Optional.empty();
|
||||
}
|
||||
customData.put(NETWORK_ITEM_TAG, tag);
|
||||
wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, customData);
|
||||
return Optional.of(wrapped);
|
||||
@@ -203,11 +225,13 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
|
||||
static class OtherItem {
|
||||
private final Item<ItemStack> item;
|
||||
private final boolean forceReturn;
|
||||
private boolean globalChanged = false;
|
||||
private CompoundTag tag;
|
||||
|
||||
public OtherItem(Item<ItemStack> item) {
|
||||
public OtherItem(Item<ItemStack> item, boolean forceReturn) {
|
||||
this.item = item;
|
||||
this.forceReturn = forceReturn;
|
||||
}
|
||||
|
||||
public Optional<Item<ItemStack>> process() {
|
||||
@@ -231,6 +255,8 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler<ItemSt
|
||||
customData.put(NETWORK_ITEM_TAG, getOrCreateTag());
|
||||
this.item.setNBTComponent(ComponentKeys.CUSTOM_DATA, customData);
|
||||
return Optional.of(this.item);
|
||||
} else if (this.forceReturn) {
|
||||
return Optional.of(this.item);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
||||
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
|
||||
public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item");
|
||||
public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item");
|
||||
public static final Key HAT_ITEM = Key.from("craftengine:hat_item");
|
||||
public static final Key FLINT_AND_STEEL_ITEM = Key.from("craftengine:flint_and_steel_item");
|
||||
public static final Key COMPOSTABLE_ITEM = Key.from("craftengine:compostable_item");
|
||||
|
||||
public static void init() {
|
||||
register(EMPTY, EmptyItemBehavior.FACTORY);
|
||||
@@ -19,5 +20,7 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
||||
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
|
||||
register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY);
|
||||
register(BUCKET_ITEM, BucketItemBehavior.FACTORY);
|
||||
register(FLINT_AND_STEEL_ITEM, FlintAndSteelItemBehavior.FACTORY);
|
||||
register(COMPOSTABLE_ITEM, CompostableItemBehavior.FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package net.momirealms.craftengine.bukkit.item.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.EventUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
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.UseOnContext;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.RandomUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Levelled;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
public class CompostableItemBehavior extends ItemBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final double chance;
|
||||
|
||||
public CompostableItemBehavior(double chance) {
|
||||
this.chance = chance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
BukkitBlockInWorld block = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
BlockData blockData = block.block().getBlockData();
|
||||
Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData));
|
||||
if (blockOwner != MBlocks.COMPOSTER) return InteractionResult.PASS;
|
||||
if (!(blockData instanceof Levelled levelled)) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
int maxLevel = levelled.getMaximumLevel();
|
||||
int currentLevel = levelled.getLevel();
|
||||
if (currentLevel >= maxLevel) return InteractionResult.PASS;
|
||||
boolean willRaise = (currentLevel == 0) && (this.chance > 0) || (RandomUtils.generateRandomDouble(0, 1) < this.chance);
|
||||
|
||||
if (willRaise) {
|
||||
levelled.setLevel(currentLevel + 1);
|
||||
EntityChangeBlockEvent event = new EntityChangeBlockEvent((Entity) context.getPlayer().platformPlayer(), block.block(), levelled);
|
||||
if (EventUtils.fireAndCheckCancel(event)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
block.block().setBlockData(levelled);
|
||||
}
|
||||
|
||||
context.getLevel().levelEvent(WorldEvents.COMPOSTER_COMPOSTS, context.getClickedPos(), willRaise ? 1 : 0);
|
||||
((World) context.getLevel().platformWorld()).sendGameEvent((Entity) context.getPlayer().platformPlayer(), GameEvent.BLOCK_CHANGE, new Vector(block.x() + 0.5, block.y() + 0.5, block.z() + 0.5));
|
||||
if (currentLevel + 1 == 7) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), blockOwner, 20);
|
||||
}
|
||||
if (!context.getPlayer().canInstabuild()) {
|
||||
context.getItem().shrink(1);
|
||||
}
|
||||
context.getPlayer().swingHand(context.getHand());
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static class Factory implements ItemBehaviorFactory {
|
||||
@Override
|
||||
public ItemBehavior create(Pack pack, Path path, Key key, Map<String, Object> arguments) {
|
||||
double chance = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("chance", 0.55), "chance");
|
||||
return new CompostableItemBehavior(chance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
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.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.sound.SoundSource;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.RandomUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
public class FlintAndSteelItemBehavior extends ItemBehavior {
|
||||
public static final FlintAndSteelItemBehavior INSTANCE = new FlintAndSteelItemBehavior();
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private static final Key FLINT_SOUND = Key.of("item.flintandsteel.use");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(clickedPos);
|
||||
Block block = clicked.block();
|
||||
BlockPos firePos = clickedPos.relative(context.getClickedFace());
|
||||
Direction direction = context.getHorizontalDirection();
|
||||
|
||||
// 最基础的判断能不能着火,不能着火都是扯蛋
|
||||
try {
|
||||
if (!(boolean) CoreReflections.method$BaseFireBlock$canBePlacedAt.invoke(null, context.getLevel().serverWorld(), LocationUtils.toBlockPos(firePos), DirectionUtils.toNMSDirection(direction))) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to call BaseFireBlock$canBePlacedAt", e);
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
// 判断点击的方块是否可燃
|
||||
BlockData clickedBlockData = block.getBlockData();
|
||||
Object clickedBlockState = BlockStateUtils.blockDataToBlockState(clickedBlockData);
|
||||
boolean isClickedBlockBurnable;
|
||||
try {
|
||||
isClickedBlockBurnable = BlockStateUtils.isBurnable(clickedBlockState) ||
|
||||
(context.getClickedFace() == Direction.UP && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
clickedBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e);
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer();
|
||||
// 点击对象直接可燃,则忽略
|
||||
if (isClickedBlockBurnable) {
|
||||
int stateId = BlockStateUtils.blockStateToId(clickedBlockState);
|
||||
if (BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
// 点击对象为自定义方块
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||
// 原版外观也可燃
|
||||
if (BlockStateUtils.isBurnable(immutableBlockState.vanillaBlockState().handle())) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle());
|
||||
// 点击的是方块上面,则只需要判断shift和可交互
|
||||
if (direction == Direction.UP) {
|
||||
// 客户端层面必须可交互
|
||||
if (!InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState,
|
||||
context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
// 且没有shift
|
||||
if (!player.isSecondaryUseActive()) {
|
||||
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
|
||||
}
|
||||
} else {
|
||||
// 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音
|
||||
BlockPos belowFirePos = firePos.relative(Direction.DOWN);
|
||||
BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos);
|
||||
boolean belowCanBurn;
|
||||
try {
|
||||
Block belowBlock = belowFireBlock.block();
|
||||
belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) ||
|
||||
(boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e);
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
// 客户端觉得这玩意可交互,就会忽略声音
|
||||
if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
// 如果按住了shift,则代表尝试对侧面方块点火
|
||||
if (player.isSecondaryUseActive()) {
|
||||
// 如果底部不能燃烧,则燃烧点位为侧面,需要补发
|
||||
if (!belowCanBurn) {
|
||||
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
} else {
|
||||
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
|
||||
}
|
||||
} else {
|
||||
// 如果底部方块不可燃烧才补发
|
||||
if (!belowCanBurn) {
|
||||
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果点击的方块不可燃烧,但是服务端却认为可以放置火源,则可燃烧的方块一定位于火源的六个方向之一。
|
||||
Direction relativeDirection = direction.opposite();
|
||||
for (Direction dir : Direction.values()) {
|
||||
if (dir == relativeDirection) continue;
|
||||
BlockPos relPos = firePos.relative(dir);
|
||||
BukkitBlockInWorld nearByBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(relPos);
|
||||
BlockData nearbyBlockData = nearByBlock.block().getBlockData();
|
||||
Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData);
|
||||
int stateID = BlockStateUtils.blockStateToId(nearbyBlockState);
|
||||
if (BlockStateUtils.isVanillaBlock(stateID)) {
|
||||
if (BlockStateUtils.isBurnable(nearbyBlockState)) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
try {
|
||||
if (dir == Direction.DOWN && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
nearbyBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(relPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL)) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e);
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
public static class Factory implements ItemBehaviorFactory {
|
||||
@Override
|
||||
public ItemBehavior create(Pack pack, Path path, Key id, Map<String, Object> arguments) {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,13 @@ package net.momirealms.craftengine.bukkit.item.factory;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.saicone.rtag.item.ItemTagStream;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.ItemTags;
|
||||
import net.momirealms.craftengine.core.item.EquipmentData;
|
||||
import net.momirealms.craftengine.core.item.ItemFactory;
|
||||
import net.momirealms.craftengine.core.item.ItemWrapper;
|
||||
import net.momirealms.craftengine.core.item.JukeboxPlayable;
|
||||
import net.momirealms.craftengine.core.item.setting.EquipmentData;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
|
||||
@@ -4,11 +4,16 @@ import com.google.gson.JsonElement;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
|
||||
import net.momirealms.craftengine.bukkit.util.EnchantmentUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.Enchantment;
|
||||
import net.momirealms.craftengine.core.item.Trim;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -38,29 +43,136 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
return new ComponentItemWrapper(item);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Object getJavaTag(ComponentItemWrapper item, Object... path) {
|
||||
throw new UnsupportedOperationException("This feature is not available on 1.20.5+");
|
||||
Map<String, Object> rootMap = (Map<String, Object>) item.getJavaComponent(ComponentTypes.CUSTOM_DATA).orElse(null);
|
||||
if (rootMap == null) return null;
|
||||
Object currentObj = rootMap;
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) return null;
|
||||
String key = pathSegment.toString();
|
||||
currentObj = ((Map<String, Object>) currentObj).get(key);
|
||||
if (currentObj == null) return null;
|
||||
if (i == path.length - 1) {
|
||||
return currentObj;
|
||||
}
|
||||
if (!(currentObj instanceof Map)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return currentObj;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Tag getNBTTag(ComponentItemWrapper item, Object... path) {
|
||||
throw new UnsupportedOperationException("This feature is not available on 1.20.5+");
|
||||
CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null);
|
||||
if (rootTag == null) return null;
|
||||
Tag currentTag = rootTag;
|
||||
for (int i = 0; i < path.length; i++) {
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) return null;
|
||||
CompoundTag t = (CompoundTag) currentTag;
|
||||
String key = pathSegment.toString();
|
||||
currentTag = t.get(key);
|
||||
if (currentTag == null) return null;
|
||||
if (i == path.length - 1) {
|
||||
return currentTag;
|
||||
}
|
||||
if (!(currentTag instanceof CompoundTag)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return currentTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setTag(ComponentItemWrapper item, Object value, Object... path) {
|
||||
throw new UnsupportedOperationException("This feature is not available on 1.20.5+");
|
||||
Tag valueTag;
|
||||
if (value instanceof Tag tag) {
|
||||
valueTag = tag;
|
||||
} else if (value instanceof JsonElement je) {
|
||||
valueTag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, je);
|
||||
} else if (CoreReflections.clazz$Tag.isInstance(value)) {
|
||||
valueTag = MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, value);
|
||||
} else {
|
||||
assert MRegistryOps.JAVA != null;
|
||||
valueTag = MRegistryOps.JAVA.convertTo(MRegistryOps.SPARROW_NBT, value);
|
||||
}
|
||||
|
||||
CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(new CompoundTag());
|
||||
|
||||
if (path == null || path.length == 0) {
|
||||
if (valueTag instanceof CompoundTag) {
|
||||
rootTag = (CompoundTag) valueTag;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot set non-CompoundTag as root without path");
|
||||
}
|
||||
} else {
|
||||
CompoundTag currentTag = rootTag;
|
||||
for (int i = 0; i < path.length - 1; i++) {
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) throw new NullPointerException("Path segment cannot be null");
|
||||
|
||||
String key = pathSegment.toString();
|
||||
Tag nextTag = currentTag.get(key);
|
||||
|
||||
if (!(nextTag instanceof CompoundTag)) {
|
||||
nextTag = new CompoundTag();
|
||||
currentTag.put(key, nextTag);
|
||||
}
|
||||
currentTag = (CompoundTag) nextTag;
|
||||
}
|
||||
|
||||
String finalKey = path[path.length - 1].toString();
|
||||
currentTag.put(finalKey, valueTag);
|
||||
}
|
||||
|
||||
item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasTag(ComponentItemWrapper item, Object... path) {
|
||||
throw new UnsupportedOperationException("This feature is not available on 1.20.5+");
|
||||
return getNBTTag(item, path) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeTag(ComponentItemWrapper item, Object... path) {
|
||||
throw new UnsupportedOperationException("This feature is not available on 1.20.5+");
|
||||
CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null);
|
||||
if (rootTag == null || path == null || path.length == 0) return false;
|
||||
|
||||
if (path.length == 1) {
|
||||
String key = path[0].toString();
|
||||
if (rootTag.containsKey(key)) {
|
||||
rootTag.remove(key);
|
||||
item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CompoundTag parentTag = rootTag;
|
||||
for (int i = 0; i < path.length - 1; i++) {
|
||||
Object pathSegment = path[i];
|
||||
if (pathSegment == null) return false;
|
||||
|
||||
String key = pathSegment.toString();
|
||||
Tag childTag = parentTag.get(key);
|
||||
|
||||
if (!(childTag instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
parentTag = (CompoundTag) childTag;
|
||||
}
|
||||
|
||||
String finalKey = path[path.length - 1].toString();
|
||||
if (parentTag.containsKey(finalKey)) {
|
||||
parentTag.remove(finalKey);
|
||||
item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -397,9 +509,9 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
protected ComponentItemWrapper mergeCopy(ComponentItemWrapper item1, ComponentItemWrapper item2) {
|
||||
Object itemStack1 = item1.getLiteralObject();
|
||||
Object itemStack2 = item2.getLiteralObject();
|
||||
Object itemStack3 = FastNMS.INSTANCE.method$ItemStack$transmuteCopy(itemStack1, itemStack2);
|
||||
Object itemStack3 = FastNMS.INSTANCE.method$ItemStack$transmuteCopy(itemStack1, FastNMS.INSTANCE.method$ItemStack$getItem(itemStack2), item2.count());
|
||||
FastNMS.INSTANCE.method$ItemStack$applyComponents(itemStack3, FastNMS.INSTANCE.method$ItemStack$getComponentsPatch(itemStack2));
|
||||
return new ComponentItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack3), item2.count());
|
||||
return new ComponentItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack3));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -409,7 +521,21 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
|
||||
try {
|
||||
FastNMS.INSTANCE.method$ItemStack$applyComponents(itemStack1, FastNMS.INSTANCE.method$ItemStack$getComponentsPatch(itemStack2));
|
||||
} catch (Exception e) {
|
||||
plugin.logger().warn("Failed to merge item", e);
|
||||
this.plugin.logger().warn("Failed to merge item", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentItemWrapper transmuteCopy(ComponentItemWrapper item, Key newItem, int amount) {
|
||||
Object itemStack1 = item.getLiteralObject();
|
||||
Object itemStack2 = FastNMS.INSTANCE.method$ItemStack$transmuteCopy(itemStack1, FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(newItem)), amount);
|
||||
return new ComponentItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentItemWrapper unsafeTransmuteCopy(ComponentItemWrapper item, Object newItem, int amount) {
|
||||
Object itemStack1 = item.getLiteralObject();
|
||||
Object itemStack2 = FastNMS.INSTANCE.method$ItemStack$transmuteCopy(itemStack1, newItem, amount);
|
||||
return new ComponentItemWrapper(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack2));
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.item.factory;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
|
||||
import net.momirealms.craftengine.core.item.EquipmentData;
|
||||
import net.momirealms.craftengine.core.item.setting.EquipmentData;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -6,6 +6,9 @@ import com.saicone.rtag.tag.TagBase;
|
||||
import com.saicone.rtag.tag.TagCompound;
|
||||
import com.saicone.rtag.tag.TagList;
|
||||
import net.momirealms.craftengine.bukkit.item.LegacyItemWrapper;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.Enchantment;
|
||||
import net.momirealms.craftengine.core.item.Trim;
|
||||
import net.momirealms.craftengine.core.item.modifier.IdModifier;
|
||||
@@ -29,7 +32,7 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
|
||||
|
||||
@Override
|
||||
protected LegacyItemWrapper wrapInternal(ItemStack item) {
|
||||
return new LegacyItemWrapper(new RtagItem(item), item.getAmount());
|
||||
return new LegacyItemWrapper(new RtagItem(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -305,18 +308,32 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
|
||||
@Override
|
||||
protected LegacyItemWrapper mergeCopy(LegacyItemWrapper item1, LegacyItemWrapper item2) {
|
||||
Object itemStack = ItemObject.copy(item2.getLiteralObject());
|
||||
ItemObject.setCustomDataTag(itemStack, TagCompound.clone(ItemObject.getCustomDataTag(item1.getLiteralObject())));
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(itemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject())));
|
||||
// one more step than vanilla
|
||||
TagCompound.merge(ItemObject.getCustomDataTag(itemStack), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true);
|
||||
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(itemStack)), item2.count());
|
||||
TagCompound.merge(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(itemStack), FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()), true, true);
|
||||
return new LegacyItemWrapper(new RtagItem(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void merge(LegacyItemWrapper item1, LegacyItemWrapper item2) {
|
||||
// load previous changes on nms items
|
||||
item1.load();
|
||||
TagCompound.merge(ItemObject.getCustomDataTag(item1.getLiteralObject()), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true);
|
||||
TagCompound.merge(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject()), FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()), true, true);
|
||||
// update wrapped item
|
||||
item1.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LegacyItemWrapper transmuteCopy(LegacyItemWrapper item, Key newItem, int amount) {
|
||||
Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(newItem)), amount);
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject())));
|
||||
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LegacyItemWrapper unsafeTransmuteCopy(LegacyItemWrapper item, Object newItem, int amount) {
|
||||
Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(newItem, amount);
|
||||
FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject())));
|
||||
return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack)));
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public class DebugStickListener implements Listener {
|
||||
ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.empty").arguments(Component.text(blockId))), true);
|
||||
player.sendPacket(systemChatPacket, false);
|
||||
} else {
|
||||
LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand), itemInHand.getAmount());
|
||||
LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand));
|
||||
Object storedData = wrapped.getJavaTag("craftengine:debug_stick_state");
|
||||
if (storedData == null) storedData = new HashMap<>();
|
||||
if (storedData instanceof Map<?,?> map) {
|
||||
|
||||
@@ -15,12 +15,12 @@ import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.item.setting.FoodData;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.util.Cancellable;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.BlockHitResult;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
@@ -28,11 +28,16 @@ import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockIgniteEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.FoodLevelChangeEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
@@ -49,6 +54,28 @@ public class ItemEventListener implements Listener {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onInteractEntity(PlayerInteractEntityEvent event) {
|
||||
BukkitServerPlayer serverPlayer = this.plugin.adapt(event.getPlayer());
|
||||
if (serverPlayer == null) return;
|
||||
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
||||
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(hand);
|
||||
|
||||
if (itemInHand == null) return;
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) return;
|
||||
|
||||
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)
|
||||
);
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
customItem.execute(context, EventTrigger.RIGHT_CLICK);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onInteractBlock(PlayerInteractEvent event) {
|
||||
Action action = event.getAction();
|
||||
@@ -62,6 +89,7 @@ public class ItemEventListener implements Listener {
|
||||
}
|
||||
|
||||
BukkitServerPlayer serverPlayer = this.plugin.adapt(player);
|
||||
if (serverPlayer == null) return;
|
||||
InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
||||
// 如果本tick内主手已被处理,则不处理副手
|
||||
// 这是因为客户端可能会同时发主副手交互包,但实际上只能处理其中一个
|
||||
@@ -318,18 +346,47 @@ public class ItemEventListener implements Listener {
|
||||
if (optionalCustomItem.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Cancellable dummy = Cancellable.dummy();
|
||||
Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled);
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.ITEM_IN_HAND, wrapped)
|
||||
.withParameter(DirectContextParameters.EVENT, dummy)
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND)
|
||||
);
|
||||
customItem.execute(context, EventTrigger.CONSUME);
|
||||
if (dummy.isCancelled()) {
|
||||
event.setCancelled(true);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
if (event.getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||
Key replacement = customItem.settings().consumeReplacement();
|
||||
if (replacement == null) {
|
||||
event.setReplacement(null);
|
||||
} else {
|
||||
ItemStack replacementItem = this.plugin.itemManager().buildItemStack(replacement, this.plugin.adapt(event.getPlayer()));
|
||||
event.setReplacement(replacementItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOW)
|
||||
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
||||
if (VersionHelper.isOrAbove1_20_5()) return;
|
||||
if (!(event.getEntity() instanceof Player player)) return;
|
||||
ItemStack consumedItem = event.getItem();
|
||||
if (ItemUtils.isEmpty(consumedItem)) return;
|
||||
Item<ItemStack> wrapped = this.plugin.itemManager().wrap(consumedItem);
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
FoodData foodData = customItem.settings().foodData();
|
||||
if (foodData == null) return;
|
||||
event.setCancelled(true);
|
||||
int oldFoodLevel = player.getFoodLevel();
|
||||
if (foodData.nutrition() != 0) player.setFoodLevel(MCUtils.clamp(oldFoodLevel + foodData.nutrition(), 0, 20));
|
||||
float oldSaturation = player.getSaturation();
|
||||
if (foodData.saturation() != 0) player.setSaturation(MCUtils.clamp(oldSaturation, 0, 10));
|
||||
}
|
||||
|
||||
private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) {
|
||||
@@ -344,4 +401,17 @@ public class ItemEventListener implements Listener {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onEntityDamage(EntityDamageEvent event) {
|
||||
if (event.getEntityType() == EntityType.ITEM && event.getEntity() instanceof org.bukkit.entity.Item item) {
|
||||
Optional.ofNullable(this.plugin.itemManager().wrap(item.getItemStack()))
|
||||
.flatMap(Item::getCustomItem)
|
||||
.ifPresent(it -> {
|
||||
if (it.settings().invulnerable().contains(DamageCauseUtils.fromBukkit(event.getCause()))) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.MaterialUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.RecipeUtils;
|
||||
@@ -45,9 +46,9 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
// 将自定义配方转为“广义”配方,接受更加宽容的输入
|
||||
// 部分过程借助bukkit完成,部分直接通过nms方法注册
|
||||
private static final Map<Key, BukkitRecipeConvertor<? extends Recipe<ItemStack>>> MIXED_RECIPE_CONVERTORS = new HashMap<>();
|
||||
private static Object nmsRecipeManager;
|
||||
private static final List<Object> injectedIngredients = new ArrayList<>();
|
||||
private static final IdentityHashMap<Recipe<ItemStack>, Object> recipeToMcRecipeHolder = new IdentityHashMap<>();
|
||||
private static final IdentityHashMap<Recipe<ItemStack>, Object> CE_RECIPE_2_NMS_HOLDER = new IdentityHashMap<>();
|
||||
private static Object nmsRecipeManager;
|
||||
|
||||
private static void registerNMSSmithingRecipe(Object recipe) {
|
||||
try {
|
||||
@@ -265,7 +266,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
}
|
||||
|
||||
public Object nmsRecipeHolderByRecipe(Recipe<ItemStack> recipe) {
|
||||
return recipeToMcRecipeHolder.get(recipe);
|
||||
if (super.isReloading) return null;
|
||||
return CE_RECIPE_2_NMS_HOLDER.get(recipe);
|
||||
}
|
||||
|
||||
public static Object nmsRecipeManager() {
|
||||
@@ -287,6 +289,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
@Override
|
||||
public void load() {
|
||||
if (!Config.enableRecipeSystem()) return;
|
||||
super.isReloading = true;
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
try {
|
||||
this.stolenFeatureFlagSet = CoreReflections.field$RecipeManager$featureflagset.get(nmsRecipeManager);
|
||||
@@ -308,7 +311,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
} catch (ReflectiveOperationException e) {
|
||||
this.plugin.logger().warn("Failed to unregister recipes", e);
|
||||
}
|
||||
recipeToMcRecipeHolder.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -320,6 +322,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
@Override
|
||||
public void disable() {
|
||||
unload();
|
||||
CE_RECIPE_2_NMS_HOLDER.clear();
|
||||
HandlerList.unregisterAll(this.recipeEventListener);
|
||||
if (this.crafterEventListener != null) {
|
||||
HandlerList.unregisterAll(this.crafterEventListener);
|
||||
@@ -473,6 +476,15 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
|
||||
// clear cache
|
||||
injectedIngredients.clear();
|
||||
|
||||
CE_RECIPE_2_NMS_HOLDER.clear();
|
||||
// create mappings
|
||||
for (Map.Entry<Key, Recipe<ItemStack>> entry : this.byId.entrySet()) {
|
||||
Optional<Object> nmsRecipe = getOptionalNMSRecipe(entry.getKey());
|
||||
nmsRecipe.ifPresent(o -> CE_RECIPE_2_NMS_HOLDER.put(entry.getValue(), o));
|
||||
}
|
||||
|
||||
super.isReloading = false;
|
||||
} catch (Exception e) {
|
||||
this.plugin.logger().warn("Failed to run delayed recipe tasks", e);
|
||||
}
|
||||
@@ -691,7 +703,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
return optionalItem.map(itemStackCustomItem -> MaterialUtils.getMaterial(itemStackCustomItem.material())).orElse(null);
|
||||
}
|
||||
|
||||
private static List<Object> getIngredientLooks(List<Holder<Key>> holders) throws ReflectiveOperationException {
|
||||
private static List<Object> getIngredientLooks(List<Holder<Key>> holders) {
|
||||
List<Object> itemStacks = new ArrayList<>();
|
||||
for (Holder<Key> holder : holders) {
|
||||
ItemStack itemStack = BukkitItemManager.instance().getBuildableItem(holder.value()).get().buildItemStack(ItemBuildContext.EMPTY, 1);
|
||||
@@ -710,8 +722,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
.map(Optional::get)
|
||||
.toList();
|
||||
|
||||
Object shapedRecipe = getNMSRecipe(id);
|
||||
recipeToMcRecipeHolder.put(recipe, shapedRecipe);
|
||||
Object shapedRecipe = getOptionalNMSRecipe(id).get();
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
shapedRecipe = CoreReflections.field$RecipeHolder$recipe.get(shapedRecipe);
|
||||
}
|
||||
@@ -731,8 +742,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
try {
|
||||
List<Ingredient<ItemStack>> actualIngredients = recipe.ingredientsInUse();
|
||||
|
||||
Object shapelessRecipe = getNMSRecipe(id);
|
||||
recipeToMcRecipeHolder.put(recipe, shapelessRecipe);
|
||||
Object shapelessRecipe = getOptionalNMSRecipe(id).get();
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
shapelessRecipe = CoreReflections.field$RecipeHolder$recipe.get(shapelessRecipe);
|
||||
}
|
||||
@@ -751,8 +761,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
private static void injectCookingRecipe(Key id, CustomCookingRecipe<ItemStack> recipe) {
|
||||
try {
|
||||
Ingredient<ItemStack> actualIngredient = recipe.ingredient();
|
||||
Object smeltingRecipe = getNMSRecipe(id);
|
||||
recipeToMcRecipeHolder.put(recipe, smeltingRecipe);
|
||||
Object smeltingRecipe = getOptionalNMSRecipe(id).get();
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
smeltingRecipe = CoreReflections.field$RecipeHolder$recipe.get(smeltingRecipe);
|
||||
}
|
||||
@@ -771,23 +780,17 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
|
||||
// 获取nms配方,请注意1.20.1获取配方本身,而1.20.2+获取的是配方的holder
|
||||
// recipe on 1.20.1 and holder on 1.20.2+
|
||||
private static Object getNMSRecipe(Key id) throws ReflectiveOperationException {
|
||||
private static Optional<Object> getOptionalNMSRecipe(Key id) throws ReflectiveOperationException {
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
Object resourceKey = CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value()));
|
||||
Object resourceKey = FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(id));
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<Object> optional = (Optional<Object>) CoreReflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceKey);
|
||||
if (optional.isEmpty()) {
|
||||
throw new IllegalArgumentException("Recipe " + id + " not found");
|
||||
}
|
||||
return optional.get();
|
||||
return optional;
|
||||
} else {
|
||||
Object resourceLocation = KeyUtils.toResourceLocation(id);
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<Object> optional = (Optional<Object>) CoreReflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceLocation);
|
||||
if (optional.isEmpty()) {
|
||||
throw new IllegalArgumentException("Recipe " + id + " not found");
|
||||
}
|
||||
return optional.get();
|
||||
return optional;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.item.recipe.Recipe;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.CraftingInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput;
|
||||
import net.momirealms.craftengine.core.item.recipe.input.SmithingInput;
|
||||
import net.momirealms.craftengine.core.item.setting.AnvilRepairItem;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
@@ -32,6 +33,7 @@ import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Campfire;
|
||||
import org.bukkit.block.Furnace;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -789,6 +791,49 @@ public class RecipeEventListener implements Listener {
|
||||
return new Pair<>(first, second);
|
||||
}
|
||||
|
||||
// 不是完美的解决方案,仍然需要更多的探讨
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onCraft(CraftItemEvent event) {
|
||||
org.bukkit.inventory.Recipe recipe = event.getRecipe();
|
||||
if (!(recipe instanceof ShapelessRecipe) && !(recipe instanceof ShapedRecipe)) return;
|
||||
HumanEntity humanEntity = event.getWhoClicked();
|
||||
if (!(humanEntity instanceof Player player)) return;
|
||||
CraftingInventory inventory = event.getInventory();
|
||||
ItemStack result = inventory.getResult();
|
||||
if (result == null) return;
|
||||
ItemStack[] usedItems = inventory.getMatrix();
|
||||
ItemStack[] replacements = new ItemStack[usedItems.length];
|
||||
boolean hasReplacement = false;
|
||||
for (int i = 0; i < usedItems.length; i++) {
|
||||
ItemStack usedItem = usedItems[i];
|
||||
if (ItemUtils.isEmpty(usedItem)) continue;
|
||||
if (usedItem.getAmount() != 1) continue;
|
||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(usedItem);
|
||||
if (wrapped == null) continue;
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
if (optionalCustomItem.isPresent()) {
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
Key remainingItem = customItem.settings().craftRemainder();
|
||||
if (remainingItem != null) {
|
||||
replacements[i] = BukkitItemManager.instance().buildItemStack(remainingItem, this.plugin.adapt(player));
|
||||
hasReplacement = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasReplacement) return;
|
||||
Runnable delayedTask = () -> {
|
||||
for (int i = 0; i < replacements.length; i++) {
|
||||
if (replacements[i] == null) continue;
|
||||
inventory.setItem(i + 1, replacements[i]);
|
||||
}
|
||||
};
|
||||
if (VersionHelper.isFolia()) {
|
||||
player.getScheduler().run(this.plugin.javaPlugin(), (t) -> delayedTask.run(), () -> {});
|
||||
} else {
|
||||
this.plugin.scheduler().sync().runDelayed(delayedTask);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onCraftingRecipe(PrepareItemCraftEvent event) {
|
||||
if (!Config.enableRecipeSystem()) return;
|
||||
@@ -843,7 +888,7 @@ public class RecipeEventListener implements Listener {
|
||||
try {
|
||||
player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to get inventory viewer", e);
|
||||
this.plugin.logger().warn("Failed to get inventory viewer", e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -854,14 +899,18 @@ public class RecipeEventListener implements Listener {
|
||||
if (ceRecipe != null) {
|
||||
inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
|
||||
serverPlayer.setLastUsedRecipe(ceRecipe.id());
|
||||
if (!ceRecipe.id().equals(recipeId)) {
|
||||
correctCraftingRecipeUsed(inventory, ceRecipe);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe);
|
||||
if (ceRecipe != null) {
|
||||
inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY)));
|
||||
serverPlayer.setLastUsedRecipe(ceRecipe.id());
|
||||
if (!ceRecipe.id().equals(recipeId)) {
|
||||
correctCraftingRecipeUsed(inventory, ceRecipe);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// clear result if not met
|
||||
@@ -869,9 +918,8 @@ public class RecipeEventListener implements Listener {
|
||||
}
|
||||
|
||||
private void correctCraftingRecipeUsed(CraftingInventory inventory, Recipe<ItemStack> recipe) {
|
||||
Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe);
|
||||
Object holderOrRecipe = this.recipeManager.nmsRecipeHolderByRecipe(recipe);
|
||||
if (holderOrRecipe == null) {
|
||||
// it's a vanilla recipe but not injected
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -922,20 +970,21 @@ public class RecipeEventListener implements Listener {
|
||||
CustomSmithingTransformRecipe<ItemStack> transformRecipe = (CustomSmithingTransformRecipe<ItemStack>) ceRecipe;
|
||||
ItemStack processed = transformRecipe.assemble(new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY), this.itemManager.wrap(base));
|
||||
event.setResult(processed);
|
||||
if (!ceRecipe.id().equals(recipeId)) {
|
||||
correctSmithingRecipeUsed(inventory, ceRecipe);
|
||||
}
|
||||
}
|
||||
|
||||
private void correctSmithingRecipeUsed(SmithingInventory inventory, Recipe<ItemStack> recipe) {
|
||||
Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe);
|
||||
Object holderOrRecipe = this.recipeManager.nmsRecipeHolderByRecipe(recipe);
|
||||
if (holderOrRecipe == null) {
|
||||
// it's a vanilla recipe but not injected
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Object resultInventory = CraftBukkitReflections.field$CraftResultInventory$resultInventory.get(inventory);
|
||||
CoreReflections.field$ResultContainer$recipeUsed.set(resultInventory, holderOrRecipe);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.logger().warn("Failed to correct used recipe", e);
|
||||
this.plugin.logger().warn("Failed to correct used recipe", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Path;
|
||||
@@ -68,8 +67,6 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
private SchedulerTask tickTask;
|
||||
private boolean successfullyLoaded = false;
|
||||
private boolean successfullyEnabled = false;
|
||||
private boolean requiresRestart = false;
|
||||
private boolean hasMod = false;
|
||||
private AntiGriefLib antiGrief;
|
||||
private JavaPlugin javaPlugin;
|
||||
private final Path dataFolderPath;
|
||||
@@ -90,16 +87,6 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
super.logger = logger;
|
||||
super.platform = new BukkitPlatform();
|
||||
super.scheduler = new BukkitSchedulerAdapter(this);
|
||||
// find mod class if present
|
||||
Class<?> modClass = ReflectionUtils.getClazz(MOD_CLASS);
|
||||
if (modClass != null) {
|
||||
Field isSuccessfullyRegistered = ReflectionUtils.getDeclaredField(modClass, "isSuccessfullyRegistered");
|
||||
try {
|
||||
requiresRestart = !(boolean) isSuccessfullyRegistered.get(null);
|
||||
hasMod = true;
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
Class<?> compatibilityClass = Objects.requireNonNull(ReflectionUtils.getClazz(COMPATIBILITY_CLASS), "Compatibility class not found");
|
||||
try {
|
||||
super.compatibilityManager = (CompatibilityManager) Objects.requireNonNull(ReflectionUtils.getConstructor(compatibilityClass, 0)).newInstance(this);
|
||||
@@ -132,7 +119,6 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
if (super.blockManager == null) {
|
||||
injectRegistries();
|
||||
}
|
||||
if (this.requiresRestart) return;
|
||||
try {
|
||||
WorldStorageInjector.init();
|
||||
} catch (Exception e) {
|
||||
@@ -177,17 +163,6 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
return;
|
||||
}
|
||||
this.successfullyEnabled = true;
|
||||
if (this.requiresRestart) {
|
||||
logger().warn(" ");
|
||||
logger().warn(" ");
|
||||
logger().warn(" ");
|
||||
logger().warn("This is the first time you have installed CraftEngine. A restart is required to apply the changes.");
|
||||
logger().warn(" ");
|
||||
logger().warn(" ");
|
||||
logger().warn(" ");
|
||||
Bukkit.getServer().shutdown();
|
||||
return;
|
||||
}
|
||||
if (!this.successfullyLoaded) {
|
||||
logger().severe(" ");
|
||||
logger().severe(" ");
|
||||
@@ -390,14 +365,6 @@ public class BukkitCraftEngine extends CraftEngine {
|
||||
);
|
||||
}
|
||||
|
||||
public boolean hasMod() {
|
||||
return hasMod;
|
||||
}
|
||||
|
||||
public boolean requiresRestart() {
|
||||
return requiresRestart;
|
||||
}
|
||||
|
||||
public AntiGriefLib antiGrief() {
|
||||
if (this.antiGrief == null) {
|
||||
this.antiGrief = AntiGriefLib.builder(this.javaPlugin)
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin;
|
||||
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.Platform;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BukkitPlatform implements Platform {
|
||||
|
||||
@Override
|
||||
public void dispatchCommand(String command) {
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object nbt2Java(String nbt) {
|
||||
try {
|
||||
Object tag = FastNMS.INSTANCE.method$TagParser$parseCompoundFully("{\"root\":" + nbt + "}");
|
||||
Map<String, Object> map = (Map<String, Object>) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag);
|
||||
return map.get("root");
|
||||
} catch (CommandSyntaxException e) {
|
||||
CraftEngine.instance().debug(e::getMessage);
|
||||
throw new LocalizedResourceConfigException("warning.config.template.argument.default_value.invalid_syntax", e, nbt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
|
||||
new DebugSpawnFurnitureCommand(this, plugin),
|
||||
new DebugTargetBlockCommand(this, plugin),
|
||||
new DebugIsSectionInjectedCommand(this, plugin),
|
||||
new DebugMigrateTemplatesCommand(this, plugin),
|
||||
new DebugEntityId2UUIDCommand(this, plugin),
|
||||
new TotemAnimationCommand(this, plugin),
|
||||
new EnableResourceCommand(this, plugin),
|
||||
new DisableResourceCommand(this, plugin),
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.bukkit.parser.WorldParser;
|
||||
import org.incendo.cloud.parser.standard.IntegerParser;
|
||||
|
||||
public class DebugEntityId2UUIDCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public DebugEntityId2UUIDCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
|
||||
super(commandManager, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.required("world", WorldParser.worldParser())
|
||||
.required("entityId", IntegerParser.integerParser())
|
||||
.handler(context -> {
|
||||
World world = context.get("world");
|
||||
int entityId = context.get("entityId");
|
||||
Entity entity = FastNMS.INSTANCE.getBukkitEntityById(world, entityId);
|
||||
if (entity == null) {
|
||||
context.sender().sendMessage("entity not found");
|
||||
return;
|
||||
}
|
||||
Location location = entity.getLocation();
|
||||
context.sender().sendMessage(
|
||||
String.format(
|
||||
"""
|
||||
===========================
|
||||
uuid: %s
|
||||
name: %s
|
||||
location: %s,%s,%s
|
||||
type: %s
|
||||
===========================
|
||||
""",
|
||||
entity.getUniqueId(),
|
||||
entity.getName(),
|
||||
location.x(), location.y(), location.z(),
|
||||
entity.getType()
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "debug_entity_id_to_uuid";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import net.momirealms.craftengine.core.util.FileUtils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.incendo.cloud.Command;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DebugMigrateTemplatesCommand extends BukkitCommandFeature<CommandSender> {
|
||||
private static final Pattern PATTERN = Pattern.compile("(?<!\\$)\\{([^}]+)}");
|
||||
|
||||
public DebugMigrateTemplatesCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
|
||||
super(commandManager, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.handler(context -> {
|
||||
for (Pack pack : BukkitCraftEngine.instance().packManager().loadedPacks()) {
|
||||
for (Path file : FileUtils.getYmlConfigsDeeply(pack.configurationFolder())) {
|
||||
try {
|
||||
Files.writeString(file, replacePlaceholders(Files.readString(file)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
context.sender().sendMessage("Done");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "debug_migrate_templates";
|
||||
}
|
||||
|
||||
private static String replacePlaceholders(String input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
Matcher matcher = PATTERN.matcher(input);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (matcher.find()) {
|
||||
// 将 {xxx} 替换为 ${xxx}
|
||||
matcher.appendReplacement(sb, "\\${" + matcher.group(1) + "}");
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class DebugSpawnFurnitureCommand extends BukkitCommandFeature<CommandSend
|
||||
}
|
||||
Location location = context.get("location");
|
||||
CustomFurniture customFurniture = optionalCustomFurniture.get();
|
||||
AnchorType anchorType = (AnchorType) context.optional("anchor-type").orElse(customFurniture.getAnyPlacement());
|
||||
AnchorType anchorType = (AnchorType) context.optional("anchor-type").orElse(customFurniture.getAnyAnchorType());
|
||||
boolean playSound = context.flags().hasFlag("silent");
|
||||
CraftEngineFurniture.place(location, customFurniture, anchorType, playSound);
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ public class DisableResourceCommand extends BukkitCommandFeature<CommandSender>
|
||||
return;
|
||||
}
|
||||
}
|
||||
YamlDocument document = plugin().config().loadYamlData(packMetaPath.toFile());
|
||||
YamlDocument document = plugin().config().loadYamlData(packMetaPath);
|
||||
document.set("enable", false);
|
||||
try {
|
||||
document.save(packMetaPath.toFile());
|
||||
|
||||
@@ -52,7 +52,7 @@ public class EnableResourceCommand extends BukkitCommandFeature<CommandSender> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
YamlDocument document = plugin().config().loadYamlData(packMetaPath.toFile());
|
||||
YamlDocument document = plugin().config().loadYamlData(packMetaPath);
|
||||
document.set("enable", true);
|
||||
try {
|
||||
document.save(packMetaPath.toFile());
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.util.NoteBlockChainUpdateUtils;
|
||||
import net.momirealms.craftengine.core.block.*;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.ObjectHolder;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
@@ -36,6 +37,7 @@ public final class BlockGenerator {
|
||||
private static Field field$CraftEngineBlock$behavior;
|
||||
private static Field field$CraftEngineBlock$shape;
|
||||
private static Field field$CraftEngineBlock$isNoteBlock;
|
||||
private static Field field$CraftEngineBlock$isTripwire;
|
||||
|
||||
public static void init() throws ReflectiveOperationException {
|
||||
ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);
|
||||
@@ -48,6 +50,7 @@ public final class BlockGenerator {
|
||||
.defineField("behaviorHolder", ObjectHolder.class, Visibility.PUBLIC)
|
||||
.defineField("shapeHolder", ObjectHolder.class, Visibility.PUBLIC)
|
||||
.defineField("isClientSideNoteBlock", boolean.class, Visibility.PUBLIC)
|
||||
.defineField("isClientSideTripwire", boolean.class, Visibility.PUBLIC)
|
||||
// should always implement this interface
|
||||
.implement(CoreReflections.clazz$Fallable)
|
||||
.implement(CoreReflections.clazz$BonemealableBlock)
|
||||
@@ -55,13 +58,15 @@ public final class BlockGenerator {
|
||||
// internal interfaces
|
||||
.implement(BehaviorHolder.class)
|
||||
.implement(ShapeHolder.class)
|
||||
.implement(NoteBlockIndicator.class)
|
||||
.implement(ChainUpdateBlockIndicator.class)
|
||||
.method(ElementMatchers.named("getBehaviorHolder"))
|
||||
.intercept(FieldAccessor.ofField("behaviorHolder"))
|
||||
.method(ElementMatchers.named("getShapeHolder"))
|
||||
.intercept(FieldAccessor.ofField("shapeHolder"))
|
||||
.method(ElementMatchers.named("isNoteBlock"))
|
||||
.intercept(FieldAccessor.ofField("isClientSideNoteBlock"))
|
||||
.method(ElementMatchers.named("isTripwire"))
|
||||
.intercept(FieldAccessor.ofField("isClientSideTripwire"))
|
||||
// getShape
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$getShape))
|
||||
.intercept(MethodDelegation.to(GetShapeInterceptor.INSTANCE))
|
||||
@@ -142,6 +147,7 @@ public final class BlockGenerator {
|
||||
field$CraftEngineBlock$behavior = clazz$CraftEngineBlock.getField("behaviorHolder");
|
||||
field$CraftEngineBlock$shape = clazz$CraftEngineBlock.getField("shapeHolder");
|
||||
field$CraftEngineBlock$isNoteBlock = clazz$CraftEngineBlock.getField("isClientSideNoteBlock");
|
||||
field$CraftEngineBlock$isTripwire = clazz$CraftEngineBlock.getField("isClientSideTripwire");
|
||||
}
|
||||
|
||||
public static Object generateBlock(Key replacedBlock, Object ownerBlock, Object properties) throws Throwable {
|
||||
@@ -155,19 +161,29 @@ public final class BlockGenerator {
|
||||
field$CraftEngineBlock$behavior.set(newBlockInstance, behaviorHolder);
|
||||
field$CraftEngineBlock$shape.set(newBlockInstance, shapeHolder);
|
||||
field$CraftEngineBlock$isNoteBlock.set(newBlockInstance, replacedBlock.equals(BlockKeys.NOTE_BLOCK));
|
||||
field$CraftEngineBlock$isTripwire.set(newBlockInstance, replacedBlock.equals(BlockKeys.TRIPWIRE));
|
||||
return newBlockInstance;
|
||||
}
|
||||
|
||||
public static class UpdateShapeInterceptor {
|
||||
public static final UpdateShapeInterceptor INSTANCE = new UpdateShapeInterceptor();
|
||||
public static final int levelIndex = VersionHelper.isOrAbove1_21_2() ? 1 : 3;
|
||||
public static final int directionIndex = VersionHelper.isOrAbove1_21_2() ? 4 : 1;
|
||||
public static final int posIndex = VersionHelper.isOrAbove1_21_2() ? 3 : 4;
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
if (((NoteBlockIndicator) thisObj).isNoteBlock() && CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) {
|
||||
ChainUpdateBlockIndicator indicator = (ChainUpdateBlockIndicator) thisObj;
|
||||
if (indicator.isNoteBlock()) {
|
||||
if (CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) {
|
||||
startNoteBlockChain(args);
|
||||
}
|
||||
} else if (indicator.isTripwire()) {
|
||||
if (CoreReflections.clazz$ServerLevel.isInstance(args[posIndex])) {
|
||||
|
||||
}
|
||||
}
|
||||
try {
|
||||
return holder.value().updateShape(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
@@ -175,30 +191,20 @@ public final class BlockGenerator {
|
||||
return args[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void startNoteBlockChain(Object[] args) throws ReflectiveOperationException {
|
||||
Object direction;
|
||||
Object serverLevel;
|
||||
Object blockPos;
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
direction = args[4];
|
||||
serverLevel = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
direction = args[1];
|
||||
serverLevel = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
int id = (int) CoreReflections.field$Direction$data3d.get(direction);
|
||||
private static void startNoteBlockChain(Object[] args) {
|
||||
Object direction = args[directionIndex];
|
||||
Object serverLevel = args[levelIndex];
|
||||
Object blockPos = args[posIndex];
|
||||
// Y axis
|
||||
if (id == 0 || id == 1) {
|
||||
if (direction == CoreReflections.instance$Direction$DOWN) {
|
||||
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
|
||||
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos);
|
||||
if (id == 1) {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, 0);
|
||||
} else {
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, 0);
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, Config.maxNoteBlockChainUpdate());
|
||||
} else if (direction == CoreReflections.instance$Direction$UP) {
|
||||
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel);
|
||||
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos);
|
||||
NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, Config.maxNoteBlockChainUpdate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ public interface InjectedCacheCheck {
|
||||
|
||||
void recipeType(Object recipeType);
|
||||
|
||||
Key customRecipeType();
|
||||
|
||||
void customRecipeType(Key customRecipeType);
|
||||
|
||||
Object lastRecipe();
|
||||
|
||||
void lastRecipe(Object lastRecipe);
|
||||
|
||||
@@ -16,6 +16,8 @@ import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRecipeTypes;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe;
|
||||
import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem;
|
||||
@@ -28,7 +30,6 @@ import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class RecipeInjector {
|
||||
@@ -41,17 +42,23 @@ public class RecipeInjector {
|
||||
.name("net.momirealms.craftengine.bukkit.entity.InjectedCacheChecker")
|
||||
.implement(CoreReflections.clazz$RecipeManager$CachedCheck)
|
||||
.implement(InjectedCacheCheck.class)
|
||||
|
||||
.defineField("recipeType", Object.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("recipeType"))
|
||||
.intercept(FieldAccessor.ofField("recipeType"))
|
||||
|
||||
.defineField("customRecipeType", Key.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("customRecipeType"))
|
||||
.intercept(FieldAccessor.ofField("customRecipeType"))
|
||||
|
||||
.defineField("lastRecipe", Object.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("lastRecipe"))
|
||||
.intercept(FieldAccessor.ofField("lastRecipe"))
|
||||
.method(ElementMatchers.named("setLastRecipe"))
|
||||
.intercept(FieldAccessor.ofField("lastRecipe"))
|
||||
|
||||
.defineField("lastCustomRecipe", Key.class, Visibility.PUBLIC)
|
||||
.method(ElementMatchers.named("lastCustomRecipe"))
|
||||
.intercept(FieldAccessor.ofField("lastCustomRecipe"))
|
||||
|
||||
.method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a")))
|
||||
.intercept(MethodDelegation.to(
|
||||
VersionHelper.isOrAbove1_21_2() ?
|
||||
@@ -73,50 +80,60 @@ public class RecipeInjector {
|
||||
if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected
|
||||
Object recipeType = FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$recipeType(entity);
|
||||
InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker);
|
||||
injectedChecker.recipeType(recipeType);
|
||||
if (recipeType == MRecipeTypes.SMELTING) {
|
||||
injectedChecker.customRecipeType(RecipeTypes.SMELTING);
|
||||
injectedChecker.recipeType(MRecipeTypes.SMELTING);
|
||||
} else if (recipeType == MRecipeTypes.BLASTING) {
|
||||
injectedChecker.customRecipeType(RecipeTypes.BLASTING);
|
||||
injectedChecker.recipeType(MRecipeTypes.BLASTING);
|
||||
} else if (recipeType == MRecipeTypes.SMOKING) {
|
||||
injectedChecker.customRecipeType(RecipeTypes.SMOKING);
|
||||
injectedChecker.recipeType(MRecipeTypes.SMOKING);
|
||||
} else {
|
||||
throw new IllegalStateException("RecipeType " + recipeType + " not supported");
|
||||
}
|
||||
CoreReflections.field$AbstractFurnaceBlockEntity$quickCheck.set(entity, injectedChecker);
|
||||
} else if (!VersionHelper.isOrAbove1_21_2() && CoreReflections.clazz$CampfireBlockEntity.isInstance(entity)) {
|
||||
Object quickCheck = CoreReflections.field$CampfireBlockEntity$quickCheck.get(entity);
|
||||
if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected
|
||||
InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker);
|
||||
injectedChecker.customRecipeType(RecipeTypes.CAMPFIRE_COOKING);
|
||||
injectedChecker.recipeType(MRecipeTypes.CAMPFIRE_COOKING);
|
||||
CoreReflections.field$CampfireBlockEntity$quickCheck.set(entity, injectedChecker);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public static class GetRecipeForMethodInterceptor1_20 {
|
||||
public static final GetRecipeForMethodInterceptor1_20 INSTANCE = new GetRecipeForMethodInterceptor1_20();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception {
|
||||
Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager();
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj;
|
||||
Object type = injectedCacheCheck.recipeType();
|
||||
Object lastRecipe = injectedCacheCheck.lastRecipe();
|
||||
Optional<Pair<Object, Object>> optionalRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe);
|
||||
if (optionalRecipe.isPresent()) {
|
||||
Pair<Object, Object> pair = optionalRecipe.get();
|
||||
Object resourceLocation = pair.getFirst();
|
||||
Key recipeId = Key.of(resourceLocation.toString());
|
||||
Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe();
|
||||
Optional<Pair<Object, Object>> optionalRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation);
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Pair<Object, Object> resourceLocationAndRecipe = optionalRecipe.get();
|
||||
Object rawRecipeResourceLocation = resourceLocationAndRecipe.getFirst();
|
||||
Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString());
|
||||
BukkitRecipeManager recipeManager = BukkitRecipeManager.instance();
|
||||
|
||||
ItemStack itemStack;
|
||||
List<Object> items;
|
||||
if (type == MRecipeTypes.CAMPFIRE_COOKING) {
|
||||
items = (List<Object>) CoreReflections.field$SimpleContainer$items.get(args[0]);
|
||||
} else {
|
||||
items = (List<Object>) CoreReflections.field$AbstractFurnaceBlockEntity$items.get(args[0]);
|
||||
}
|
||||
itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(items.get(0));
|
||||
|
||||
// it's a recipe from other plugins
|
||||
boolean isCustom = recipeManager.isCustomRecipe(recipeId);
|
||||
boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey);
|
||||
if (!isCustom) {
|
||||
injectedCacheCheck.lastRecipe(resourceLocation);
|
||||
return Optional.of(pair.getSecond());
|
||||
injectedCacheCheck.lastRecipe(rawRecipeResourceLocation);
|
||||
return Optional.of(resourceLocationAndRecipe.getSecond());
|
||||
}
|
||||
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(
|
||||
injectedCacheCheck.recipeType() == MRecipeTypes.CAMPFIRE_COOKING ?
|
||||
FastNMS.INSTANCE.field$SimpleContainer$items(args[0]).getFirst() :
|
||||
FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$getItem(args[0], 0)
|
||||
);
|
||||
|
||||
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
|
||||
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
|
||||
if (idHolder.isEmpty()) {
|
||||
@@ -124,64 +141,47 @@ public class RecipeInjector {
|
||||
}
|
||||
|
||||
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
|
||||
CustomCookingRecipe<ItemStack> ceRecipe;
|
||||
Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe();
|
||||
if (type == MRecipeTypes.SMELTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.BLASTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.SMOKING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.CAMPFIRE_COOKING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
|
||||
if (ceRecipe == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// Cache recipes, it might be incorrect on reloading
|
||||
injectedCacheCheck.lastCustomRecipe(ceRecipe.id());
|
||||
// It doesn't matter at all
|
||||
injectedCacheCheck.lastRecipe(resourceLocation);
|
||||
return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(pair.getSecond()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
if (!ceRecipe.id().equals(rawRecipeKey)) {
|
||||
injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id()));
|
||||
}
|
||||
return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public static class GetRecipeForMethodInterceptor1_20_5 {
|
||||
public static final GetRecipeForMethodInterceptor1_20_5 INSTANCE = new GetRecipeForMethodInterceptor1_20_5();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception {
|
||||
Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager();
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj;
|
||||
Object type = injectedCacheCheck.recipeType();
|
||||
Object lastRecipe = injectedCacheCheck.lastRecipe();
|
||||
Optional<Object> optionalRecipe = (Optional<Object>) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe);
|
||||
if (optionalRecipe.isPresent()) {
|
||||
Object holder = optionalRecipe.get();
|
||||
Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder);
|
||||
Key recipeId = Key.of(id.toString());
|
||||
BukkitRecipeManager recipeManager = BukkitRecipeManager.instance();
|
||||
|
||||
ItemStack itemStack;
|
||||
List<Object> items;
|
||||
if (type == MRecipeTypes.CAMPFIRE_COOKING) {
|
||||
items = (List<Object>) CoreReflections.field$SimpleContainer$items.get(args[0]);
|
||||
} else {
|
||||
items = (List<Object>) CoreReflections.field$AbstractFurnaceBlockEntity$items.get(args[0]);
|
||||
Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe();
|
||||
Optional<Object> optionalRecipe = (Optional<Object>) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation);
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(items.get(0));
|
||||
|
||||
// it's a recipe from other plugins
|
||||
boolean isCustom = recipeManager.isCustomRecipe(recipeId);
|
||||
Object rawRecipeHolder = optionalRecipe.get();
|
||||
Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$RecipeHolder$id(rawRecipeHolder);
|
||||
Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString());
|
||||
|
||||
BukkitRecipeManager recipeManager = BukkitRecipeManager.instance();
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(
|
||||
injectedCacheCheck.recipeType() == MRecipeTypes.CAMPFIRE_COOKING ?
|
||||
FastNMS.INSTANCE.field$SimpleContainer$items(args[0]).getFirst() :
|
||||
FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$getItem(args[0], 0)
|
||||
);
|
||||
|
||||
boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey);
|
||||
if (!isCustom) {
|
||||
injectedCacheCheck.lastRecipe(id);
|
||||
injectedCacheCheck.lastRecipe(rawRecipeResourceLocation);
|
||||
return optionalRecipe;
|
||||
}
|
||||
|
||||
@@ -192,59 +192,45 @@ public class RecipeInjector {
|
||||
}
|
||||
|
||||
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
|
||||
CustomCookingRecipe<ItemStack> ceRecipe;
|
||||
Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe();
|
||||
if (type == MRecipeTypes.SMELTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.BLASTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.SMOKING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.CAMPFIRE_COOKING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
|
||||
if (ceRecipe == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// Cache recipes, it might be incorrect on reloading
|
||||
injectedCacheCheck.lastCustomRecipe(ceRecipe.id());
|
||||
// It doesn't matter at all
|
||||
injectedCacheCheck.lastRecipe(id);
|
||||
return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
if (!ceRecipe.id().equals(rawRecipeKey)) {
|
||||
injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id()));
|
||||
}
|
||||
return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public static class GetRecipeForMethodInterceptor1_21 {
|
||||
public static final GetRecipeForMethodInterceptor1_21 INSTANCE = new GetRecipeForMethodInterceptor1_21();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception {
|
||||
Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager();
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj;
|
||||
Object type = injectedCacheCheck.recipeType();
|
||||
Object lastRecipe = injectedCacheCheck.lastRecipe();
|
||||
Optional<Object> optionalRecipe = (Optional<Object>) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe);
|
||||
if (optionalRecipe.isPresent()) {
|
||||
Object holder = optionalRecipe.get();
|
||||
Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder);
|
||||
Key recipeId = Key.of(id.toString());
|
||||
BukkitRecipeManager recipeManager = BukkitRecipeManager.instance();
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.field$SingleRecipeInput$item.get(args[0]));
|
||||
Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe();
|
||||
Optional<Object> optionalRecipe = (Optional<Object>) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation);
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// it's a recipe from other plugins
|
||||
boolean isCustom = recipeManager.isCustomRecipe(recipeId);
|
||||
Object rawRecipeHolder = optionalRecipe.get();
|
||||
Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$RecipeHolder$id(rawRecipeHolder);
|
||||
Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString());
|
||||
|
||||
BukkitRecipeManager recipeManager = BukkitRecipeManager.instance();
|
||||
boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey);
|
||||
if (!isCustom) {
|
||||
injectedCacheCheck.lastRecipe(id);
|
||||
injectedCacheCheck.lastRecipe(rawRecipeResourceLocation);
|
||||
return optionalRecipe;
|
||||
}
|
||||
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0]));
|
||||
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
|
||||
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
|
||||
if (idHolder.isEmpty()) {
|
||||
@@ -252,60 +238,49 @@ public class RecipeInjector {
|
||||
}
|
||||
|
||||
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
|
||||
CustomCookingRecipe<ItemStack> ceRecipe;
|
||||
Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe();
|
||||
if (type == MRecipeTypes.SMELTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.BLASTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.SMOKING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.CAMPFIRE_COOKING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
|
||||
if (ceRecipe == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// Cache recipes, it might be incorrect on reloading
|
||||
injectedCacheCheck.lastCustomRecipe(ceRecipe.id());
|
||||
// It doesn't matter at all
|
||||
injectedCacheCheck.lastRecipe(id);
|
||||
return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
if (!ceRecipe.id().equals(rawRecipeKey)) {
|
||||
injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id()));
|
||||
}
|
||||
return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public static class GetRecipeForMethodInterceptor1_21_2 {
|
||||
public static final GetRecipeForMethodInterceptor1_21_2 INSTANCE = new GetRecipeForMethodInterceptor1_21_2();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception {
|
||||
Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager();
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args) {
|
||||
InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj;
|
||||
Object type = injectedCacheCheck.recipeType();
|
||||
Object lastRecipe = injectedCacheCheck.lastRecipe();
|
||||
Optional<Object> optionalRecipe = (Optional<Object>) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe);
|
||||
if (optionalRecipe.isPresent()) {
|
||||
Object holder = optionalRecipe.get();
|
||||
Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder);
|
||||
Object resourceLocation = FastNMS.INSTANCE.field$ResourceKey$location(id);
|
||||
Key recipeId = Key.of(resourceLocation.toString());
|
||||
BukkitRecipeManager recipeManager = BukkitRecipeManager.instance();
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.field$SingleRecipeInput$item.get(args[0]));
|
||||
Object lastRecipeResourceKey = injectedCacheCheck.lastRecipe();
|
||||
Optional<Object> optionalRecipe = (Optional<Object>) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceKey);
|
||||
if (optionalRecipe.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// it's a recipe from other plugins
|
||||
boolean isCustom = recipeManager.isCustomRecipe(recipeId);
|
||||
// 获取配方的基础信息
|
||||
Object recipeHolder = optionalRecipe.get();
|
||||
Object rawRecipeResourceKey = FastNMS.INSTANCE.field$RecipeHolder$id(recipeHolder);
|
||||
Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$ResourceKey$location(rawRecipeResourceKey);
|
||||
Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString());
|
||||
|
||||
BukkitRecipeManager recipeManager = BukkitRecipeManager.instance();
|
||||
// 来自其他插件注册的自定义配方
|
||||
boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey);
|
||||
if (!isCustom) {
|
||||
injectedCacheCheck.lastRecipe(id);
|
||||
injectedCacheCheck.lastRecipe(rawRecipeResourceKey);
|
||||
return optionalRecipe;
|
||||
}
|
||||
|
||||
// 获取唯一内存地址id
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0]));
|
||||
Item<ItemStack> wrappedItem = BukkitItemManager.instance().wrap(itemStack);
|
||||
Optional<Holder.Reference<Key>> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id());
|
||||
if (idHolder.isEmpty()) {
|
||||
@@ -313,29 +288,19 @@ public class RecipeInjector {
|
||||
}
|
||||
|
||||
SingleItemInput<ItemStack> input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack));
|
||||
CustomCookingRecipe<ItemStack> ceRecipe;
|
||||
Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe();
|
||||
if (type == MRecipeTypes.SMELTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.BLASTING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe);
|
||||
} else if (type == MRecipeTypes.SMOKING) {
|
||||
ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
CustomCookingRecipe<ItemStack> ceRecipe = (CustomCookingRecipe<ItemStack>) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe());
|
||||
// 这个ce配方并不存在,那么应该返回空
|
||||
if (ceRecipe == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
// Cache recipes, it might be incorrect on reloading
|
||||
// 记录上一次使用的配方(ce)
|
||||
injectedCacheCheck.lastCustomRecipe(ceRecipe.id());
|
||||
// It doesn't matter at all
|
||||
injectedCacheCheck.lastRecipe(id);
|
||||
return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
// 更新上一次使用的配方(nms)
|
||||
if (!ceRecipe.id().equals(rawRecipeKey)) {
|
||||
injectedCacheCheck.lastRecipe(FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(ceRecipe.id())));
|
||||
}
|
||||
return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ 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.BlockStateWrapper;
|
||||
import net.momirealms.craftengine.core.block.EmptyBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
@@ -220,23 +221,36 @@ public class WorldStorageInjector {
|
||||
CESection section = holder.ceSection();
|
||||
// 如果是原版方块
|
||||
if (BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
// 那么应该情况自定义块
|
||||
// 那么应该清空自定义块
|
||||
ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE);
|
||||
// 如果先前不是空气则标记
|
||||
// 处理 自定义块 -> 原版块
|
||||
if (!previous.isEmpty()) {
|
||||
holder.ceChunk().setDirty(true);
|
||||
if (Config.enableLightSystem()) {
|
||||
updateLightIfChanged(holder, previousState, newState, newState, x, y, z);
|
||||
// 自定义块到原版块,只需要判断旧块是否和客户端一直
|
||||
BlockStateWrapper wrapper = previous.vanillaBlockState();
|
||||
if (wrapper != null) {
|
||||
updateLight(holder, wrapper.handle(), previousState, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId);
|
||||
ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState);
|
||||
if (previousImmutableBlockState == immutableBlockState) return;
|
||||
// 处理 自定义块到自定义块或原版块到自定义块
|
||||
holder.ceChunk().setDirty(true);
|
||||
// 不可能!绝对不可能!
|
||||
if (immutableBlockState.isEmpty()) return;
|
||||
// 如果新方块的光照属性和客户端认为的不同
|
||||
if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) {
|
||||
updateLightIfChanged(holder, previousState, immutableBlockState.vanillaBlockState().handle(), newState, x, y, z);
|
||||
if (Config.enableLightSystem()) {
|
||||
if (previousImmutableBlockState.isEmpty()) {
|
||||
// 原版块到自定义块,只需要判断新块是否和客户端视觉一致
|
||||
updateLight(holder, immutableBlockState.vanillaBlockState().handle(), newState, x, y, z);
|
||||
} else {
|
||||
// 自定义块到自定义块
|
||||
updateLight$complex(holder, immutableBlockState.vanillaBlockState().handle(), newState, previousState, x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -244,17 +258,31 @@ public class WorldStorageInjector {
|
||||
}
|
||||
}
|
||||
|
||||
protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object oldServerSideState, Object clientSideState, Object serverSideState, int x, int y, int z) {
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
protected static void updateLight(@This InjectedHolder thisObj, Object clientState, Object serverState, int x, int y, int z) {
|
||||
CEWorld world = thisObj.ceChunk().world();
|
||||
Object blockPos = LocationUtils.toBlockPos(x, y, z);
|
||||
Object serverWorld = world.world().serverWorld();
|
||||
if (clientSideState != serverSideState && FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(clientSideState, serverSideState, serverWorld, blockPos)) {
|
||||
if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(serverState, clientState, serverWorld, blockPos)) {
|
||||
SectionPos sectionPos = thisObj.cePos();
|
||||
List<SectionPos> pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15);
|
||||
world.sectionLightUpdated(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
protected static void updateLight$complex(@This InjectedHolder thisObj, Object newClientState, Object newServerState, Object oldServerState, int x, int y, int z) {
|
||||
CEWorld world = thisObj.ceChunk().world();
|
||||
Object blockPos = LocationUtils.toBlockPos(x, y, z);
|
||||
Object serverWorld = world.world().serverWorld();
|
||||
// 如果客户端新状态和服务端新状态光照属性不同
|
||||
if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newClientState, newServerState, serverWorld, blockPos)) {
|
||||
SectionPos sectionPos = thisObj.cePos();
|
||||
List<SectionPos> pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15);
|
||||
world.sectionLightUpdated(pos);
|
||||
return;
|
||||
}
|
||||
if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(oldServerSideState, serverSideState, serverWorld, blockPos)) {
|
||||
if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newServerState, oldServerState, serverWorld, blockPos)) {
|
||||
SectionPos sectionPos = thisObj.cePos();
|
||||
List<SectionPos> pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15);
|
||||
world.sectionLightUpdated(pos);
|
||||
|
||||
@@ -82,7 +82,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
|
||||
private static final String CONNECTION_HANDLER_NAME = "craftengine_connection_handler";
|
||||
private static final String SERVER_CHANNEL_HANDLER_NAME = "craftengine_server_channel_handler";
|
||||
private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_packet_handler";
|
||||
private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_channel_handler";
|
||||
private static final String PACKET_ENCODER = "craftengine_encoder";
|
||||
private static final String PACKET_DECODER = "craftengine_decoder";
|
||||
|
||||
@@ -147,9 +147,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
registerNMSPacketConsumer(PacketConsumers.SET_CREATIVE_SLOT, NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.LOGIN, NetworkReflections.clazz$ClientboundLoginPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.RESPAWN, NetworkReflections.clazz$ClientboundRespawnPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.INTERACT_ENTITY, NetworkReflections.clazz$ServerboundInteractPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, NetworkReflections.clazz$ClientboundEntityPositionSyncPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
|
||||
registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, NetworkReflections.clazz$ServerboundPickItemFromEntityPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, NetworkReflections.clazz$ServerboundRenameItemPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket);
|
||||
@@ -161,6 +159,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, NetworkReflections.clazz$ServerboundResourcePackPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, NetworkReflections.clazz$ClientboundEntityEventPacket);
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot);
|
||||
registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos);
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket());
|
||||
@@ -177,7 +176,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1);
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY, this.packetIds.clientboundAddEntityPacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket());
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket());
|
||||
@@ -187,6 +186,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
|
||||
registerS2CByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket());
|
||||
registerC2SByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket());
|
||||
registerC2SByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, this.packetIds.serverboundContainerClickPacket());
|
||||
registerC2SByteBufPacketConsumer(PacketConsumers.INTERACT_ENTITY, this.packetIds.serverboundInteractPacket());
|
||||
}
|
||||
|
||||
public static BukkitNetworkManager instance() {
|
||||
|
||||
@@ -70,7 +70,6 @@ import org.bukkit.util.RayTraceResult;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -85,7 +84,7 @@ public class PacketConsumers {
|
||||
public static void initEntities(int registrySize) {
|
||||
ADD_ENTITY_HANDLERS = new BukkitNetworkManager.Handlers[registrySize];
|
||||
Arrays.fill(ADD_ENTITY_HANDLERS, BukkitNetworkManager.Handlers.DO_NOTHING);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$FALLING_BLOCK$registryId] = (user, event) -> {
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.FALLING_BLOCK$registryId] = (user, event) -> {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
int id = buf.readVarInt();
|
||||
UUID uuid = buf.readUUID();
|
||||
@@ -122,28 +121,27 @@ public class PacketConsumers {
|
||||
}
|
||||
};
|
||||
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM_DISPLAY$registryId] = simpleAddEntityHandler(ItemDisplayPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$EGG$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$POTION$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
}
|
||||
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM_DISPLAY$registryId] = (user, event) -> {
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
int id = buf.readVarInt();
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id);
|
||||
@@ -153,10 +151,12 @@ public class PacketConsumers {
|
||||
if (Config.hideBaseEntity() && !furniture.hasExternalModel()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} else {
|
||||
user.entityPacketHandlers().put(id, ItemDisplayPacketHandler.INSTANCE);
|
||||
}
|
||||
};
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$INTERACTION$registryId] = (user, event) -> {
|
||||
if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.instance$EntityType$INTERACTION) return;
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.INTERACTION$registryId] = (user, event) -> {
|
||||
if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.INTERACTION) return;
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
int id = buf.readVarInt();
|
||||
// Cancel collider entity packet
|
||||
@@ -166,8 +166,8 @@ public class PacketConsumers {
|
||||
user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE);
|
||||
}
|
||||
};
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$OAK_BOAT$registryId] = (user, event) -> {
|
||||
if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.instance$EntityType$OAK_BOAT) return;
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> {
|
||||
if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.OAK_BOAT) return;
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
int id = buf.readVarInt();
|
||||
// Cancel collider entity packet
|
||||
@@ -1106,13 +1106,13 @@ public class PacketConsumers {
|
||||
Object blockPos = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$pos(packet);
|
||||
BlockPos pos = LocationUtils.fromBlockPos(blockPos);
|
||||
if (VersionHelper.isFolia()) {
|
||||
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
|
||||
platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> {
|
||||
try {
|
||||
handlePlayerActionPacketOnMainThread(player, world, pos, packet);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e);
|
||||
}
|
||||
}, world, pos.x() >> 4, pos.z() >> 4);
|
||||
}, () -> {});
|
||||
} else {
|
||||
handlePlayerActionPacketOnMainThread(player, world, pos, packet);
|
||||
}
|
||||
@@ -1172,21 +1172,21 @@ public class PacketConsumers {
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> HELLO_C2S = (user, event, packet) -> {
|
||||
try {
|
||||
BukkitServerPlayer player = (BukkitServerPlayer) user;
|
||||
String name = (String) NetworkReflections.field$ServerboundHelloPacket$name.get(packet);
|
||||
String name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet);
|
||||
player.setName(name);
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
UUID uuid = (UUID) NetworkReflections.field$ServerboundHelloPacket$uuid.get(packet);
|
||||
UUID uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
|
||||
player.setUUID(uuid);
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<UUID> uuid = (Optional<UUID>) NetworkReflections.field$ServerboundHelloPacket$uuid.get(packet);
|
||||
Optional<UUID> uuid = (Optional<UUID>) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet);
|
||||
if (uuid.isPresent()) {
|
||||
player.setUUID(uuid.get());
|
||||
} else {
|
||||
player.setUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundHelloPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -1223,10 +1223,10 @@ public class PacketConsumers {
|
||||
player.clearView();
|
||||
Object dimensionKey;
|
||||
if (!VersionHelper.isOrAbove1_20_2()) {
|
||||
dimensionKey = NetworkReflections.field$ClientboundRespawnPacket$dimension.get(packet);
|
||||
dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet);
|
||||
} else {
|
||||
Object commonInfo = NetworkReflections.field$ClientboundRespawnPacket$commonPlayerSpawnInfo.get(packet);
|
||||
dimensionKey = NetworkReflections.field$CommonPlayerSpawnInfo$dimension.get(commonInfo);
|
||||
Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
|
||||
dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
|
||||
}
|
||||
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
|
||||
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
|
||||
@@ -1237,7 +1237,7 @@ public class PacketConsumers {
|
||||
} else {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -1251,10 +1251,10 @@ public class PacketConsumers {
|
||||
if (BukkitNetworkManager.hasViaVersion()) {
|
||||
user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid()));
|
||||
}
|
||||
dimensionKey = NetworkReflections.field$ClientboundLoginPacket$dimension.get(packet);
|
||||
dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet);
|
||||
} else {
|
||||
Object commonInfo = NetworkReflections.field$ClientboundLoginPacket$commonPlayerSpawnInfo.get(packet);
|
||||
dimensionKey = NetworkReflections.field$CommonPlayerSpawnInfo$dimension.get(commonInfo);
|
||||
Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet);
|
||||
dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo);
|
||||
}
|
||||
Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey);
|
||||
World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString())));
|
||||
@@ -1265,7 +1265,7 @@ public class PacketConsumers {
|
||||
} else {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -1282,25 +1282,25 @@ public class PacketConsumers {
|
||||
player.platformPlayer().getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> {
|
||||
try {
|
||||
handleSetCreativeSlotPacketOnMainThread(player, packet);
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e);
|
||||
}
|
||||
}, () -> {});
|
||||
} else {
|
||||
handleSetCreativeSlotPacketOnMainThread(player, packet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Exception {
|
||||
private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Throwable {
|
||||
Player bukkitPlayer = player.platformPlayer();
|
||||
if (bukkitPlayer == null) return;
|
||||
if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return;
|
||||
int slot = VersionHelper.isOrAbove1_20_5() ? NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getShort(packet) : NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getInt(packet);
|
||||
int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet);
|
||||
if (slot < 36 || slot > 44) return;
|
||||
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$itemStack.get(packet));
|
||||
ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet));
|
||||
if (ItemUtils.isEmpty(item)) return;
|
||||
if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) {
|
||||
return;
|
||||
@@ -1373,14 +1373,14 @@ public class PacketConsumers {
|
||||
if (!user.isOnline()) return;
|
||||
Player player = (Player) user.platformPlayer();
|
||||
if (player == null) return;
|
||||
Object pos = NetworkReflections.field$ServerboundPickItemFromBlockPacket$pos.get(packet);
|
||||
Object pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet);
|
||||
if (VersionHelper.isFolia()) {
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(pos);
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(pos);
|
||||
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
|
||||
try {
|
||||
handlePickItemFromBlockPacketOnMainThread(player, pos);
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e);
|
||||
}
|
||||
}, player.getWorld(), x >> 4, z >> 4);
|
||||
@@ -1388,17 +1388,17 @@ public class PacketConsumers {
|
||||
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
|
||||
try {
|
||||
handlePickItemFromBlockPacketOnMainThread(player, pos);
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Exception {
|
||||
private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Throwable {
|
||||
Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld());
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos);
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
@@ -1411,7 +1411,7 @@ public class PacketConsumers {
|
||||
// 1.21.4+
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> PICK_ITEM_FROM_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = (int) NetworkReflections.field$ServerboundPickItemFromEntityPacket$id.get(packet);
|
||||
int entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet);
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
|
||||
if (furniture == null) return;
|
||||
Player player = (Player) user.platformPlayer();
|
||||
@@ -1420,7 +1420,7 @@ public class PacketConsumers {
|
||||
player.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> {
|
||||
try {
|
||||
handlePickItemFromEntityOnMainThread(player, furniture);
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e);
|
||||
}
|
||||
}, () -> {});
|
||||
@@ -1428,23 +1428,23 @@ public class PacketConsumers {
|
||||
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
|
||||
try {
|
||||
handlePickItemFromEntityOnMainThread(player, furniture);
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Exception {
|
||||
private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Throwable {
|
||||
Key itemId = furniture.config().settings().itemId();
|
||||
if (itemId == null) return;
|
||||
pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity()));
|
||||
}
|
||||
|
||||
private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws IllegalAccessException, InvocationTargetException {
|
||||
private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws Throwable {
|
||||
ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player));
|
||||
if (itemStack == null) {
|
||||
CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item");
|
||||
@@ -1453,15 +1453,15 @@ public class PacketConsumers {
|
||||
assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null;
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke(
|
||||
CoreReflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)),
|
||||
CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)),
|
||||
FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true);
|
||||
} else {
|
||||
CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke(
|
||||
CoreReflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack));
|
||||
CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack));
|
||||
}
|
||||
}
|
||||
|
||||
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> ADD_ENTITY_BYTEBUFFER = (user, event) -> {
|
||||
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> ADD_ENTITY = (user, event) -> {
|
||||
try {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
buf.readVarInt();
|
||||
@@ -1509,83 +1509,108 @@ public class PacketConsumers {
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> INTERACT_ENTITY = (user, event, packet) -> {
|
||||
public static final BiConsumer<NetWorkUser, ByteBufPacketEvent> INTERACT_ENTITY = (user, event) -> {
|
||||
try {
|
||||
Player player = (Player) user.platformPlayer();
|
||||
if (player == null) return;
|
||||
int entityId;
|
||||
if (BukkitNetworkManager.hasModelEngine()) {
|
||||
int fakeId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet);
|
||||
entityId = CraftEngine.instance().compatibilityManager().interactionToBaseEntity(fakeId);
|
||||
} else {
|
||||
entityId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet);
|
||||
}
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
int entityId = BukkitNetworkManager.hasModelEngine() ?
|
||||
CraftEngine.instance().compatibilityManager().interactionToBaseEntity(buf.readVarInt()) :
|
||||
buf.readVarInt();
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
|
||||
if (furniture == null) return;
|
||||
Object action = NetworkReflections.field$ServerboundInteractPacket$action.get(packet);
|
||||
Object actionType = NetworkReflections.method$ServerboundInteractPacket$Action$getType.invoke(action);
|
||||
if (actionType == null) return;
|
||||
Location location = furniture.baseEntity().getLocation();
|
||||
int actionType = buf.readVarInt();
|
||||
BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user;
|
||||
if (serverPlayer.isSpectatorMode()) return;
|
||||
BukkitCraftEngine.instance().scheduler().sync().run(() -> {
|
||||
if (actionType == NetworkReflections.instance$ServerboundInteractPacket$ActionType$ATTACK) {
|
||||
// todo 冒险模式破坏工具白名单
|
||||
if (serverPlayer.isAdventureMode()) return;
|
||||
if (furniture.isValid()) {
|
||||
if (!BukkitCraftEngine.instance().antiGrief().canBreak(player, location)) {
|
||||
return;
|
||||
}
|
||||
FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture);
|
||||
if (EventUtils.fireAndCheckCancel(breakEvent)) {
|
||||
return;
|
||||
Player platformPlayer = serverPlayer.platformPlayer();
|
||||
Location location = furniture.baseEntity().getLocation();
|
||||
|
||||
Runnable mainThreadTask;
|
||||
if (actionType == 1) {
|
||||
// ATTACK
|
||||
boolean usingSecondaryAction = buf.readBoolean();
|
||||
if (entityId != furniture.baseEntityId()) {
|
||||
event.setChanged(true);
|
||||
buf.clear();
|
||||
buf.writeVarInt(event.packetID());
|
||||
buf.writeVarInt(furniture.baseEntityId());
|
||||
buf.writeVarInt(actionType);
|
||||
buf.writeBoolean(usingSecondaryAction);
|
||||
}
|
||||
|
||||
mainThreadTask = () -> {
|
||||
// todo 冒险模式破坏工具白名单
|
||||
if (serverPlayer.isAdventureMode() ||
|
||||
!furniture.isValid() ||
|
||||
!BukkitCraftEngine.instance().antiGrief().canBreak(platformPlayer, location)
|
||||
) return;
|
||||
|
||||
FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture);
|
||||
if (EventUtils.fireAndCheckCancel(breakEvent))
|
||||
return;
|
||||
|
||||
Cancellable cancellable = Cancellable.of(breakEvent::isCancelled, breakEvent::setCancelled);
|
||||
// execute functions
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FURNITURE, furniture)
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.HAND, InteractionHand.MAIN_HAND)
|
||||
.withParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND))
|
||||
.withParameter(DirectContextParameters.POSITION, furniture.position())
|
||||
);
|
||||
furniture.config().execute(context, EventTrigger.LEFT_CLICK);
|
||||
furniture.config().execute(context, EventTrigger.BREAK);
|
||||
if (cancellable.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true);
|
||||
};
|
||||
} else if (actionType == 2) {
|
||||
// INTERACT_AT
|
||||
float x = buf.readFloat();
|
||||
float y = buf.readFloat();
|
||||
float z = buf.readFloat();
|
||||
Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z);
|
||||
InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
||||
boolean usingSecondaryAction = buf.readBoolean();
|
||||
if (entityId != furniture.baseEntityId()) {
|
||||
event.setChanged(true);
|
||||
buf.clear();
|
||||
buf.writeVarInt(event.packetID());
|
||||
buf.writeVarInt(furniture.baseEntityId());
|
||||
buf.writeVarInt(actionType);
|
||||
buf.writeFloat(x).writeFloat(y).writeFloat(z);
|
||||
buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1);
|
||||
buf.writeBoolean(usingSecondaryAction);
|
||||
}
|
||||
} else if (actionType == NetworkReflections.instance$ServerboundInteractPacket$ActionType$INTERACT_AT) {
|
||||
InteractionHand hand;
|
||||
Location interactionPoint;
|
||||
try {
|
||||
Object interactionHand = NetworkReflections.field$ServerboundInteractPacket$InteractionAtLocationAction$hand.get(action);
|
||||
hand = interactionHand == CoreReflections.instance$InteractionHand$MAIN_HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND;
|
||||
Object vec3 = NetworkReflections.field$ServerboundInteractPacket$InteractionAtLocationAction$location.get(action);
|
||||
|
||||
double x = FastNMS.INSTANCE.field$Vec3$x(vec3);
|
||||
double y = FastNMS.INSTANCE.field$Vec3$y(vec3);
|
||||
double z = FastNMS.INSTANCE.field$Vec3$z(vec3);
|
||||
interactionPoint = new Location(location.getWorld(), x, y, z);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Failed to get interaction hand from interact packet", e);
|
||||
}
|
||||
mainThreadTask = () -> {
|
||||
FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint);
|
||||
if (EventUtils.fireAndCheckCancel(interactEvent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
|
||||
Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled);
|
||||
// execute functions
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.EVENT, cancellable)
|
||||
.withParameter(DirectContextParameters.FURNITURE, furniture)
|
||||
.withParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand)
|
||||
.withParameter(DirectContextParameters.HAND, hand)
|
||||
.withParameter(DirectContextParameters.POSITION, furniture.position())
|
||||
);
|
||||
furniture.config().execute(context, EventTrigger.RIGHT_CLICK);
|
||||
if (cancellable.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.isSneaking()) {
|
||||
// 必须从网络包层面处理,否则无法获取交互的具体实体
|
||||
if (serverPlayer.isSecondaryUseActive() && itemInHand != null) {
|
||||
// try placing another furniture above it
|
||||
AABB hitBox = furniture.aabbByEntityId(entityId);
|
||||
if (hitBox == null) return;
|
||||
Item<ItemStack> itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND);
|
||||
if (itemInHand == null) return;
|
||||
Optional<CustomItem<ItemStack>> optionalCustomitem = itemInHand.getCustomItem();
|
||||
Location eyeLocation = player.getEyeLocation();
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = itemInHand.getCustomItem();
|
||||
Location eyeLocation = platformPlayer.getEyeLocation();
|
||||
Vector direction = eyeLocation.getDirection();
|
||||
Location endLocation = eyeLocation.clone();
|
||||
endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange()));
|
||||
@@ -1594,8 +1619,8 @@ public class PacketConsumers {
|
||||
return;
|
||||
}
|
||||
EntityHitResult hitResult = result.get();
|
||||
if (optionalCustomitem.isPresent() && !optionalCustomitem.get().behaviors().isEmpty()) {
|
||||
for (ItemBehavior behavior : optionalCustomitem.get().behaviors()) {
|
||||
if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) {
|
||||
for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) {
|
||||
if (behavior instanceof FurnitureItemBehavior) {
|
||||
behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(hitResult.hitLocation(), hitResult.direction(), BlockPos.fromVec3d(hitResult.hitLocation()), false)));
|
||||
return;
|
||||
@@ -1604,7 +1629,12 @@ public class PacketConsumers {
|
||||
}
|
||||
// now simulate vanilla item behavior
|
||||
serverPlayer.setResendSound();
|
||||
FastNMS.INSTANCE.simulateInteraction(serverPlayer.serverPlayer(), DirectionUtils.toNMSDirection(hitResult.direction()), hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, LocationUtils.toBlockPos(hitResult.blockPos()));
|
||||
FastNMS.INSTANCE.simulateInteraction(
|
||||
serverPlayer.serverPlayer(),
|
||||
DirectionUtils.toNMSDirection(hitResult.direction()),
|
||||
hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z,
|
||||
LocationUtils.toBlockPos(hitResult.blockPos())
|
||||
);
|
||||
} else {
|
||||
furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> {
|
||||
if (furniture.tryOccupySeat(seatPos)) {
|
||||
@@ -1612,9 +1642,30 @@ public class PacketConsumers {
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
} else if (actionType == 0) {
|
||||
int hand = buf.readVarInt();
|
||||
boolean usingSecondaryAction = buf.readBoolean();
|
||||
if (entityId != furniture.baseEntityId()) {
|
||||
event.setChanged(true);
|
||||
buf.clear();
|
||||
buf.writeVarInt(event.packetID());
|
||||
buf.writeVarInt(furniture.baseEntityId());
|
||||
buf.writeVarInt(actionType);
|
||||
buf.writeVarInt(hand);
|
||||
buf.writeBoolean(usingSecondaryAction);
|
||||
}
|
||||
}, player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (VersionHelper.isFolia()) {
|
||||
platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), t -> mainThreadTask.run(), () -> {});
|
||||
} else {
|
||||
BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundInteractPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -1699,20 +1750,20 @@ public class PacketConsumers {
|
||||
if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) {
|
||||
return;
|
||||
}
|
||||
String message = (String) NetworkReflections.field$ServerboundRenameItemPacket$name.get(packet);
|
||||
String message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet);
|
||||
if (message != null && !message.isEmpty()) {
|
||||
// check bypass
|
||||
FontManager manager = CraftEngine.instance().fontManager();
|
||||
IllegalCharacterProcessResult result = manager.processIllegalCharacters(message);
|
||||
if (result.has()) {
|
||||
try {
|
||||
NetworkReflections.field$ServerboundRenameItemPacket$name.set(packet, result.text());
|
||||
NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to replace chat", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -1725,7 +1776,7 @@ public class PacketConsumers {
|
||||
if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) {
|
||||
return;
|
||||
}
|
||||
String[] lines = (String[]) NetworkReflections.field$ServerboundSignUpdatePacket$lines.get(packet);
|
||||
String[] lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet);
|
||||
FontManager manager = CraftEngine.instance().fontManager();
|
||||
if (!manager.isDefaultFontInUse()) return;
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
@@ -1737,7 +1788,7 @@ public class PacketConsumers {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundSignUpdatePacket", e);
|
||||
}
|
||||
};
|
||||
@@ -1756,9 +1807,9 @@ public class PacketConsumers {
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
List<String> pages = (List<String>) NetworkReflections.field$ServerboundEditBookPacket$pages.get(packet);
|
||||
List<String> pages = (List<String>) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet);
|
||||
List<String> newPages = new ArrayList<>(pages.size());
|
||||
Optional<String> title = (Optional<String>) NetworkReflections.field$ServerboundEditBookPacket$title.get(packet);
|
||||
Optional<String> title = (Optional<String>) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet);
|
||||
Optional<String> newTitle;
|
||||
|
||||
if (title.isPresent()) {
|
||||
@@ -1782,13 +1833,13 @@ public class PacketConsumers {
|
||||
|
||||
if (changed) {
|
||||
Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance(
|
||||
NetworkReflections.field$ServerboundEditBookPacket$slot.get(packet),
|
||||
(int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet),
|
||||
newPages,
|
||||
newTitle
|
||||
);
|
||||
event.replacePacket(newPacket);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundEditBookPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -1815,7 +1866,7 @@ public class PacketConsumers {
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CUSTOM_PAYLOAD = (user, event, packet) -> {
|
||||
try {
|
||||
if (!VersionHelper.isOrAbove1_20_5()) return;
|
||||
Object payload = NetworkReflections.field$ServerboundCustomPayloadPacket$payload.get(packet);
|
||||
Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet);
|
||||
if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) {
|
||||
Payload discardedPayload = DiscardedPayload.from(payload);
|
||||
if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY))
|
||||
@@ -1844,7 +1895,7 @@ public class PacketConsumers {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -2234,9 +2285,9 @@ public class PacketConsumers {
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> HANDSHAKE_C2S = (user, event, packet) -> {
|
||||
try {
|
||||
if (BukkitNetworkManager.hasViaVersion()) return;
|
||||
int protocolVersion = NetworkReflections.field$ClientIntentionPacket$protocolVersion.getInt(packet);
|
||||
int protocolVersion = (int) NetworkReflections.methodHandle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet);
|
||||
user.setProtocolVersion(protocolVersion);
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientIntentionPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -2254,7 +2305,7 @@ public class PacketConsumers {
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> RESOURCE_PACK_RESPONSE = (user, event, packet) -> {
|
||||
try {
|
||||
if (user.sentResourcePack() || !Config.sendPackOnJoin() || !Config.kickOnDeclined()) return;
|
||||
Object action = NetworkReflections.field$ServerboundResourcePackPacket$action.get(packet);
|
||||
Object action = NetworkReflections.methodHandle$ServerboundResourcePackPacket$actionGetter.invokeExact(packet);
|
||||
if (action == null) return;
|
||||
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED
|
||||
|| action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD) {
|
||||
@@ -2267,7 +2318,7 @@ public class PacketConsumers {
|
||||
if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$SUCCESSFULLY_LOADED) {
|
||||
user.setSentResourcePack(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e);
|
||||
}
|
||||
};
|
||||
@@ -2276,28 +2327,17 @@ public class PacketConsumers {
|
||||
try {
|
||||
Object player = user.serverPlayer();
|
||||
if (player == null) return;
|
||||
int entityId = NetworkReflections.field$ClientboundEntityEventPacket$entityId.getInt(packet);
|
||||
int entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet);
|
||||
if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return;
|
||||
byte eventId = NetworkReflections.field$ClientboundEntityEventPacket$eventId.getByte(packet);
|
||||
byte eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet);
|
||||
if (eventId >= 24 && eventId <= 28) {
|
||||
CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityEventPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_AND_ROTATE_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
@@ -2310,4 +2350,15 @@ public class PacketConsumers {
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> MOVE_POS_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet);
|
||||
EntityPacketHandler handler = user.entityPacketHandlers().get(entityId);
|
||||
if (handler != null) {
|
||||
handler.handleMove(user, event, packet);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -52,7 +52,11 @@ public interface PacketIds {
|
||||
|
||||
int clientboundSetPlayerInventoryPacket();
|
||||
|
||||
int clientboundBlockEventPacket();
|
||||
|
||||
int serverboundContainerClickPacket();
|
||||
|
||||
int serverboundSetCreativeModeSlotPacket();
|
||||
|
||||
int serverboundInteractPacket();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler;
|
||||
|
||||
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.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.util.EntityDataUtils;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent;
|
||||
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
|
||||
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
|
||||
@@ -27,6 +29,11 @@ public class CommonItemPacketHandler implements EntityPacketHandler {
|
||||
int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem);
|
||||
if (entityDataId == EntityDataUtils.ITEM_DATA_ID) {
|
||||
Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem);
|
||||
// TODO 检查为什么会导致问题,难道是其他插件乱发entity id?
|
||||
if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) {
|
||||
CraftEngine.instance().logger().warn("Invalid item data for entity " + id);
|
||||
continue;
|
||||
}
|
||||
ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack);
|
||||
Optional<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);
|
||||
if (optional.isPresent()) {
|
||||
|
||||
@@ -11,4 +11,9 @@ public class FurnitureCollisionPacketHandler implements EntityPacketHandler {
|
||||
public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@@ -24,4 +24,9 @@ public class FurniturePacketHandler implements EntityPacketHandler {
|
||||
public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
buf.writeVarInt(event.packetID());
|
||||
buf.writeVarInt(this.entityId);
|
||||
buf.writeUUID(uuid);
|
||||
buf.writeVarInt(MEntityTypes.instance$EntityType$ITEM_DISPLAY$registryId);
|
||||
buf.writeVarInt(MEntityTypes.ITEM_DISPLAY$registryId);
|
||||
buf.writeDouble(x);
|
||||
buf.writeDouble(y);
|
||||
buf.writeDouble(z);
|
||||
|
||||
@@ -139,4 +139,14 @@ public class PacketIds1_20 implements PacketIds {
|
||||
public int serverboundSetCreativeModeSlotPacket() {
|
||||
return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clientboundBlockEventPacket() {
|
||||
return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBlockEventPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serverboundInteractPacket() {
|
||||
return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundInteractPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,11 @@ public class PacketIds1_20_5 implements PacketIds {
|
||||
return PacketIdFinder.clientboundByName("minecraft:set_player_inventory");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int clientboundBlockEventPacket() {
|
||||
return PacketIdFinder.clientboundByName("minecraft:block_event");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serverboundContainerClickPacket() {
|
||||
return PacketIdFinder.serverboundByName("minecraft:container_click");
|
||||
@@ -138,4 +143,9 @@ public class PacketIds1_20_5 implements PacketIds {
|
||||
public int serverboundSetCreativeModeSlotPacket() {
|
||||
return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int serverboundInteractPacket() {
|
||||
return PacketIdFinder.serverboundByName("minecraft:interact");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@ import com.google.gson.JsonElement;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
||||
import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
@@ -1353,10 +1356,6 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getBlockSupportShape", "b_"}, clazz$BlockState, clazz$BlockGetter, CoreReflections.clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Method method$LevelAccessor$scheduleTick = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$LevelAccessor, void.class, CoreReflections.clazz$BlockPos, clazz$Block, int.class)
|
||||
);
|
||||
|
||||
public static final Field field$BlockBehaviour$properties = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$BlockBehaviour, clazz$BlockBehaviour$Properties, 0)
|
||||
);
|
||||
@@ -3265,4 +3264,48 @@ public final class CoreReflections {
|
||||
public static final Method method$Registry$asLookup = ReflectionUtils.getMethod(
|
||||
clazz$Registry, clazz$HolderLookup$RegistryLookup, new String[]{"asLookup", "p"}
|
||||
);
|
||||
|
||||
public static final Field field$ServerEntity$broadcast = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(
|
||||
clazz$ServerEntity, Consumer.class, 0
|
||||
)
|
||||
);
|
||||
|
||||
public static final MethodHandle methodHandle$ServerEntity$broadcastSetter;
|
||||
public static final MethodHandle methodHandle$ServerEntity$updateIntervalSetter;
|
||||
public static final MethodHandle methodHandle$ServerPlayer$connectionGetter;
|
||||
|
||||
static {
|
||||
try {
|
||||
methodHandle$ServerEntity$broadcastSetter = requireNonNull(
|
||||
ReflectionUtils.unreflectSetter(field$ServerEntity$broadcast)
|
||||
.asType(MethodType.methodType(void.class, Object.class, Consumer.class))
|
||||
);
|
||||
methodHandle$ServerEntity$updateIntervalSetter = requireNonNull(
|
||||
ReflectionUtils.unreflectSetter(field$ServerEntity$updateInterval)
|
||||
.asType(MethodType.methodType(void.class, Object.class, int.class))
|
||||
);
|
||||
methodHandle$ServerPlayer$connectionGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerPlayer$connection)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ReflectionInitException("Failed to initialize reflection", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$BaseFireBlock = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.BlockFireAbstract",
|
||||
"world.level.block.BaseFireBlock"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Method method$BaseFireBlock$canBePlacedAt = requireNonNull(
|
||||
ReflectionUtils.getStaticMethod(clazz$BaseFireBlock, boolean.class, clazz$Level, clazz$BlockPos, clazz$Direction)
|
||||
);
|
||||
|
||||
public static final Field field$FireBlock$igniteOdds = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$FireBlock, Object2IntMap.class, 0)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ public final class MBlocks {
|
||||
public static final Object ICE;
|
||||
public static final Object SHORT_GRASS;
|
||||
public static final Object SHORT_GRASS$defaultState;
|
||||
public static final Object SHULKER_BOX;
|
||||
public static final Object COMPOSTER;
|
||||
|
||||
private static Object getById(String id) throws ReflectiveOperationException {
|
||||
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
|
||||
@@ -33,6 +35,8 @@ public final class MBlocks {
|
||||
ICE = getById("ice");
|
||||
SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass");
|
||||
SHORT_GRASS$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(SHORT_GRASS);
|
||||
SHULKER_BOX = getById("shulker_box");
|
||||
COMPOSTER = getById("composter");
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to init Blocks", e);
|
||||
}
|
||||
|
||||
@@ -7,50 +7,50 @@ import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
public final class MEntityTypes {
|
||||
private MEntityTypes() {}
|
||||
|
||||
public static final Object instance$EntityType$TEXT_DISPLAY;
|
||||
public static final int instance$EntityType$TEXT_DISPLAY$registryId;
|
||||
public static final Object instance$EntityType$ITEM_DISPLAY;
|
||||
public static final int instance$EntityType$ITEM_DISPLAY$registryId;
|
||||
public static final Object instance$EntityType$BLOCK_DISPLAY;
|
||||
public static final int instance$EntityType$BLOCK_DISPLAY$registryId;
|
||||
public static final Object instance$EntityType$ARMOR_STAND;
|
||||
public static final int instance$EntityType$ARMOR_STAND$registryId;
|
||||
public static final Object instance$EntityType$FALLING_BLOCK;
|
||||
public static final int instance$EntityType$FALLING_BLOCK$registryId;
|
||||
public static final Object instance$EntityType$INTERACTION;
|
||||
public static final int instance$EntityType$INTERACTION$registryId;
|
||||
public static final Object instance$EntityType$SHULKER;
|
||||
public static final int instance$EntityType$SHULKER$registryId;
|
||||
public static final Object instance$EntityType$OAK_BOAT;
|
||||
public static final int instance$EntityType$OAK_BOAT$registryId;
|
||||
public static final Object instance$EntityType$TRIDENT;
|
||||
public static final int instance$EntityType$TRIDENT$registryId;
|
||||
public static final Object instance$EntityType$SNOWBALL;
|
||||
public static final int instance$EntityType$SNOWBALL$registryId;
|
||||
public static final Object instance$EntityType$FIREBALL;
|
||||
public static final int instance$EntityType$FIREBALL$registryId;
|
||||
public static final Object instance$EntityType$EYE_OF_ENDER;
|
||||
public static final int instance$EntityType$EYE_OF_ENDER$registryId;
|
||||
public static final Object instance$EntityType$FIREWORK_ROCKET;
|
||||
public static final int instance$EntityType$FIREWORK_ROCKET$registryId;
|
||||
public static final Object instance$EntityType$ITEM;
|
||||
public static final int instance$EntityType$ITEM$registryId;
|
||||
public static final Object instance$EntityType$ITEM_FRAME;
|
||||
public static final int instance$EntityType$ITEM_FRAME$registryId;
|
||||
public static final Object instance$EntityType$GLOW_ITEM_FRAME;
|
||||
public static final int instance$EntityType$GLOW_ITEM_FRAME$registryId;
|
||||
public static final Object instance$EntityType$OMINOUS_ITEM_SPAWNER;
|
||||
public static final int instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId;
|
||||
public static final Object instance$EntityType$SMALL_FIREBALL;
|
||||
public static final int instance$EntityType$SMALL_FIREBALL$registryId;
|
||||
public static final Object instance$EntityType$EGG;
|
||||
public static final int instance$EntityType$EGG$registryId;
|
||||
public static final Object instance$EntityType$ENDER_PEARL;
|
||||
public static final int instance$EntityType$ENDER_PEARL$registryId;
|
||||
public static final Object instance$EntityType$EXPERIENCE_BOTTLE;
|
||||
public static final int instance$EntityType$EXPERIENCE_BOTTLE$registryId;
|
||||
public static final Object instance$EntityType$POTION;
|
||||
public static final int instance$EntityType$POTION$registryId;
|
||||
public static final Object TEXT_DISPLAY;
|
||||
public static final int TEXT_DISPLAY$registryId;
|
||||
public static final Object ITEM_DISPLAY;
|
||||
public static final int ITEM_DISPLAY$registryId;
|
||||
public static final Object BLOCK_DISPLAY;
|
||||
public static final int BLOCK_DISPLAY$registryId;
|
||||
public static final Object ARMOR_STAND;
|
||||
public static final int ARMOR_STAND$registryId;
|
||||
public static final Object FALLING_BLOCK;
|
||||
public static final int FALLING_BLOCK$registryId;
|
||||
public static final Object INTERACTION;
|
||||
public static final int INTERACTION$registryId;
|
||||
public static final Object SHULKER;
|
||||
public static final int SHULKER$registryId;
|
||||
public static final Object OAK_BOAT;
|
||||
public static final int OAK_BOAT$registryId;
|
||||
public static final Object TRIDENT;
|
||||
public static final int TRIDENT$registryId;
|
||||
public static final Object SNOWBALL;
|
||||
public static final int SNOWBALL$registryId;
|
||||
public static final Object FIREBALL;
|
||||
public static final int FIREBALL$registryId;
|
||||
public static final Object EYE_OF_ENDER;
|
||||
public static final int EYE_OF_ENDER$registryId;
|
||||
public static final Object FIREWORK_ROCKET;
|
||||
public static final int FIREWORK_ROCKET$registryId;
|
||||
public static final Object ITEM;
|
||||
public static final int ITEM$registryId;
|
||||
public static final Object ITEM_FRAME;
|
||||
public static final int ITEM_FRAME$registryId;
|
||||
public static final Object GLOW_ITEM_FRAME;
|
||||
public static final int GLOW_ITEM_FRAME$registryId;
|
||||
public static final Object OMINOUS_ITEM_SPAWNER;
|
||||
public static final int OMINOUS_ITEM_SPAWNER$registryId;
|
||||
public static final Object SMALL_FIREBALL;
|
||||
public static final int SMALL_FIREBALL$registryId;
|
||||
public static final Object EGG;
|
||||
public static final int EGG$registryId;
|
||||
public static final Object ENDER_PEARL;
|
||||
public static final int ENDER_PEARL$registryId;
|
||||
public static final Object EXPERIENCE_BOTTLE;
|
||||
public static final int EXPERIENCE_BOTTLE$registryId;
|
||||
public static final Object POTION;
|
||||
public static final int POTION$registryId;
|
||||
|
||||
private static Object getById(String id) throws ReflectiveOperationException {
|
||||
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
|
||||
@@ -64,50 +64,50 @@ public final class MEntityTypes {
|
||||
|
||||
static {
|
||||
try {
|
||||
instance$EntityType$TEXT_DISPLAY = getById("text_display");
|
||||
instance$EntityType$TEXT_DISPLAY$registryId = getRegistryId(instance$EntityType$TEXT_DISPLAY);
|
||||
instance$EntityType$ITEM_DISPLAY = getById("item_display");
|
||||
instance$EntityType$ITEM_DISPLAY$registryId = getRegistryId(instance$EntityType$ITEM_DISPLAY);
|
||||
instance$EntityType$BLOCK_DISPLAY = getById("block_display");
|
||||
instance$EntityType$BLOCK_DISPLAY$registryId = getRegistryId(instance$EntityType$BLOCK_DISPLAY);
|
||||
instance$EntityType$FALLING_BLOCK = getById("falling_block");
|
||||
instance$EntityType$FALLING_BLOCK$registryId = getRegistryId(instance$EntityType$FALLING_BLOCK);
|
||||
instance$EntityType$INTERACTION = getById("interaction");
|
||||
instance$EntityType$INTERACTION$registryId = getRegistryId(instance$EntityType$INTERACTION);
|
||||
instance$EntityType$SHULKER = getById("shulker");
|
||||
instance$EntityType$SHULKER$registryId = getRegistryId(instance$EntityType$SHULKER);
|
||||
instance$EntityType$ARMOR_STAND = getById("armor_stand");
|
||||
instance$EntityType$ARMOR_STAND$registryId = getRegistryId(instance$EntityType$ARMOR_STAND);
|
||||
instance$EntityType$OAK_BOAT = getById(VersionHelper.isOrAbove1_21_2() ? "oak_boat" : "boat");
|
||||
instance$EntityType$OAK_BOAT$registryId = getRegistryId(instance$EntityType$OAK_BOAT);
|
||||
instance$EntityType$TRIDENT = getById("trident");
|
||||
instance$EntityType$TRIDENT$registryId = getRegistryId(instance$EntityType$TRIDENT);
|
||||
instance$EntityType$SNOWBALL = getById("snowball");
|
||||
instance$EntityType$SNOWBALL$registryId = getRegistryId(instance$EntityType$SNOWBALL);
|
||||
instance$EntityType$FIREBALL = getById("fireball");
|
||||
instance$EntityType$FIREBALL$registryId = getRegistryId(instance$EntityType$FIREBALL);
|
||||
instance$EntityType$EYE_OF_ENDER = getById("eye_of_ender");
|
||||
instance$EntityType$EYE_OF_ENDER$registryId = getRegistryId(instance$EntityType$EYE_OF_ENDER);
|
||||
instance$EntityType$FIREWORK_ROCKET = getById("firework_rocket");
|
||||
instance$EntityType$FIREWORK_ROCKET$registryId = getRegistryId(instance$EntityType$FIREWORK_ROCKET);
|
||||
instance$EntityType$ITEM = getById("item");
|
||||
instance$EntityType$ITEM$registryId = getRegistryId(instance$EntityType$ITEM);
|
||||
instance$EntityType$ITEM_FRAME = getById("item_frame");
|
||||
instance$EntityType$ITEM_FRAME$registryId = getRegistryId(instance$EntityType$ITEM_FRAME);
|
||||
instance$EntityType$GLOW_ITEM_FRAME = getById("glow_item_frame");
|
||||
instance$EntityType$GLOW_ITEM_FRAME$registryId = getRegistryId(instance$EntityType$GLOW_ITEM_FRAME);
|
||||
instance$EntityType$SMALL_FIREBALL = getById("small_fireball");
|
||||
instance$EntityType$SMALL_FIREBALL$registryId = getRegistryId(instance$EntityType$SMALL_FIREBALL);
|
||||
instance$EntityType$EGG = getById("egg");
|
||||
instance$EntityType$EGG$registryId = getRegistryId(instance$EntityType$EGG);
|
||||
instance$EntityType$ENDER_PEARL = getById("ender_pearl");
|
||||
instance$EntityType$ENDER_PEARL$registryId = getRegistryId(instance$EntityType$ENDER_PEARL);
|
||||
instance$EntityType$EXPERIENCE_BOTTLE = getById("experience_bottle");
|
||||
instance$EntityType$EXPERIENCE_BOTTLE$registryId = getRegistryId(instance$EntityType$EXPERIENCE_BOTTLE);
|
||||
instance$EntityType$POTION = getById("potion");
|
||||
instance$EntityType$POTION$registryId = getRegistryId(instance$EntityType$POTION);
|
||||
instance$EntityType$OMINOUS_ITEM_SPAWNER = VersionHelper.isOrAbove1_20_5() ? getById("ominous_item_spawner") : null;
|
||||
instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId = getRegistryId(instance$EntityType$OMINOUS_ITEM_SPAWNER);
|
||||
TEXT_DISPLAY = getById("text_display");
|
||||
TEXT_DISPLAY$registryId = getRegistryId(TEXT_DISPLAY);
|
||||
ITEM_DISPLAY = getById("item_display");
|
||||
ITEM_DISPLAY$registryId = getRegistryId(ITEM_DISPLAY);
|
||||
BLOCK_DISPLAY = getById("block_display");
|
||||
BLOCK_DISPLAY$registryId = getRegistryId(BLOCK_DISPLAY);
|
||||
FALLING_BLOCK = getById("falling_block");
|
||||
FALLING_BLOCK$registryId = getRegistryId(FALLING_BLOCK);
|
||||
INTERACTION = getById("interaction");
|
||||
INTERACTION$registryId = getRegistryId(INTERACTION);
|
||||
SHULKER = getById("shulker");
|
||||
SHULKER$registryId = getRegistryId(SHULKER);
|
||||
ARMOR_STAND = getById("armor_stand");
|
||||
ARMOR_STAND$registryId = getRegistryId(ARMOR_STAND);
|
||||
OAK_BOAT = getById(VersionHelper.isOrAbove1_21_2() ? "oak_boat" : "boat");
|
||||
OAK_BOAT$registryId = getRegistryId(OAK_BOAT);
|
||||
TRIDENT = getById("trident");
|
||||
TRIDENT$registryId = getRegistryId(TRIDENT);
|
||||
SNOWBALL = getById("snowball");
|
||||
SNOWBALL$registryId = getRegistryId(SNOWBALL);
|
||||
FIREBALL = getById("fireball");
|
||||
FIREBALL$registryId = getRegistryId(FIREBALL);
|
||||
EYE_OF_ENDER = getById("eye_of_ender");
|
||||
EYE_OF_ENDER$registryId = getRegistryId(EYE_OF_ENDER);
|
||||
FIREWORK_ROCKET = getById("firework_rocket");
|
||||
FIREWORK_ROCKET$registryId = getRegistryId(FIREWORK_ROCKET);
|
||||
ITEM = getById("item");
|
||||
ITEM$registryId = getRegistryId(ITEM);
|
||||
ITEM_FRAME = getById("item_frame");
|
||||
ITEM_FRAME$registryId = getRegistryId(ITEM_FRAME);
|
||||
GLOW_ITEM_FRAME = getById("glow_item_frame");
|
||||
GLOW_ITEM_FRAME$registryId = getRegistryId(GLOW_ITEM_FRAME);
|
||||
SMALL_FIREBALL = getById("small_fireball");
|
||||
SMALL_FIREBALL$registryId = getRegistryId(SMALL_FIREBALL);
|
||||
EGG = getById("egg");
|
||||
EGG$registryId = getRegistryId(EGG);
|
||||
ENDER_PEARL = getById("ender_pearl");
|
||||
ENDER_PEARL$registryId = getRegistryId(ENDER_PEARL);
|
||||
EXPERIENCE_BOTTLE = getById("experience_bottle");
|
||||
EXPERIENCE_BOTTLE$registryId = getRegistryId(EXPERIENCE_BOTTLE);
|
||||
POTION = getById("potion");
|
||||
POTION$registryId = getRegistryId(POTION);
|
||||
OMINOUS_ITEM_SPAWNER = VersionHelper.isOrAbove1_20_5() ? getById("ominous_item_spawner") : null;
|
||||
OMINOUS_ITEM_SPAWNER$registryId = getRegistryId(OMINOUS_ITEM_SPAWNER);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to init EntityTypes", e);
|
||||
}
|
||||
|
||||
@@ -10,21 +10,23 @@ import java.lang.reflect.Type;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public final class MRegistries {
|
||||
public static final Object instance$Registries$BLOCK;
|
||||
public static final Object instance$Registries$ITEM;
|
||||
public static final Object instance$Registries$ATTRIBUTE;
|
||||
public static final Object instance$Registries$BIOME;
|
||||
public static final Object instance$Registries$MOB_EFFECT;
|
||||
public static final Object instance$Registries$SOUND_EVENT;
|
||||
public static final Object instance$Registries$PARTICLE_TYPE;
|
||||
public static final Object instance$Registries$ENTITY_TYPE;
|
||||
public static final Object instance$Registries$FLUID;
|
||||
public static final Object instance$Registries$RECIPE_TYPE;
|
||||
public static final Object instance$Registries$DIMENSION_TYPE;
|
||||
public static final Object instance$Registries$CONFIGURED_FEATURE;
|
||||
public static final Object instance$Registries$PLACED_FEATURE;
|
||||
public static final Object BLOCK;
|
||||
public static final Object ITEM;
|
||||
public static final Object ATTRIBUTE;
|
||||
public static final Object BIOME;
|
||||
public static final Object MOB_EFFECT;
|
||||
public static final Object SOUND_EVENT;
|
||||
public static final Object PARTICLE_TYPE;
|
||||
public static final Object ENTITY_TYPE;
|
||||
public static final Object FLUID;
|
||||
public static final Object RECIPE_TYPE;
|
||||
public static final Object DIMENSION_TYPE;
|
||||
public static final Object CONFIGURED_FEATURE;
|
||||
public static final Object PLACED_FEATURE;
|
||||
@Nullable // 1.21+
|
||||
public static final Object instance$Registries$JUKEBOX_SONG;
|
||||
public static final Object JUKEBOX_SONG;
|
||||
@Nullable // 1.21+
|
||||
public static final Object RECIPE;
|
||||
|
||||
static {
|
||||
Field[] fields = CoreReflections.clazz$Registries.getDeclaredFields();
|
||||
@@ -43,6 +45,7 @@ public final class MRegistries {
|
||||
Object registries$ConfiguredFeature = null;
|
||||
Object registries$PlacedFeature = null;
|
||||
Object registries$JukeboxSong = null;
|
||||
Object registries$Recipe = null;
|
||||
for (Field field : fields) {
|
||||
Type fieldType = field.getGenericType();
|
||||
if (fieldType instanceof ParameterizedType paramType) {
|
||||
@@ -60,6 +63,8 @@ public final class MRegistries {
|
||||
registries$RecipeType = field.get(null);
|
||||
} else if (rawType == CoreReflections.clazz$ConfiguredFeature) {
|
||||
registries$ConfiguredFeature = field.get(null);
|
||||
} else if (rawType == CoreReflections.clazz$Recipe) {
|
||||
registries$Recipe = field.get(null);
|
||||
}
|
||||
} else {
|
||||
if (type == CoreReflections.clazz$Block) {
|
||||
@@ -88,20 +93,21 @@ public final class MRegistries {
|
||||
}
|
||||
}
|
||||
}
|
||||
instance$Registries$BLOCK = requireNonNull(registries$Block);
|
||||
instance$Registries$ITEM = requireNonNull(registries$Item);
|
||||
instance$Registries$ATTRIBUTE = requireNonNull(registries$Attribute);
|
||||
instance$Registries$BIOME = requireNonNull(registries$Biome);
|
||||
instance$Registries$MOB_EFFECT = requireNonNull(registries$MobEffect);
|
||||
instance$Registries$SOUND_EVENT = requireNonNull(registries$SoundEvent);
|
||||
instance$Registries$DIMENSION_TYPE = requireNonNull(registries$DimensionType);
|
||||
instance$Registries$PARTICLE_TYPE = requireNonNull(registries$ParticleType);
|
||||
instance$Registries$ENTITY_TYPE = requireNonNull(registries$EntityType);
|
||||
instance$Registries$FLUID = requireNonNull(registries$Fluid);
|
||||
instance$Registries$RECIPE_TYPE = requireNonNull(registries$RecipeType);
|
||||
instance$Registries$CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature);
|
||||
instance$Registries$PLACED_FEATURE = requireNonNull(registries$PlacedFeature);
|
||||
instance$Registries$JUKEBOX_SONG = registries$JukeboxSong;
|
||||
BLOCK = requireNonNull(registries$Block);
|
||||
ITEM = requireNonNull(registries$Item);
|
||||
ATTRIBUTE = requireNonNull(registries$Attribute);
|
||||
BIOME = requireNonNull(registries$Biome);
|
||||
MOB_EFFECT = requireNonNull(registries$MobEffect);
|
||||
SOUND_EVENT = requireNonNull(registries$SoundEvent);
|
||||
DIMENSION_TYPE = requireNonNull(registries$DimensionType);
|
||||
PARTICLE_TYPE = requireNonNull(registries$ParticleType);
|
||||
ENTITY_TYPE = requireNonNull(registries$EntityType);
|
||||
FLUID = requireNonNull(registries$Fluid);
|
||||
RECIPE_TYPE = requireNonNull(registries$RecipeType);
|
||||
CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature);
|
||||
PLACED_FEATURE = requireNonNull(registries$PlacedFeature);
|
||||
JUKEBOX_SONG = registries$JukeboxSong;
|
||||
RECIPE = registries$Recipe;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import net.momirealms.sparrow.nbt.codec.LegacyJavaOps;
|
||||
import net.momirealms.sparrow.nbt.codec.LegacyNBTOps;
|
||||
import net.momirealms.sparrow.nbt.codec.NBTOps;
|
||||
|
||||
@@ -34,8 +35,12 @@ public class MRegistryOps {
|
||||
static {
|
||||
try {
|
||||
if (clazz$JavaOps != null) {
|
||||
// 1.20.5+
|
||||
Object javaOps = ReflectionUtils.getDeclaredField(clazz$JavaOps, clazz$JavaOps, 0).get(null);
|
||||
JAVA = (DynamicOps<Object>) CoreReflections.method$RegistryOps$create.invoke(null, javaOps, FastNMS.INSTANCE.registryAccess());
|
||||
} else if (!VersionHelper.isOrAbove1_20_5()) {
|
||||
// 1.20.1-1.20.4
|
||||
JAVA = (DynamicOps<Object>) CoreReflections.method$RegistryOps$create.invoke(null, LegacyJavaOps.INSTANCE, FastNMS.INSTANCE.registryAccess());
|
||||
} else {
|
||||
JAVA = null;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
||||
import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -968,7 +971,7 @@ public final class NetworkReflections {
|
||||
);
|
||||
|
||||
public static final Field field$ServerboundEditBookPacket$slot = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$ServerboundEditBookPacket, int.class, 0)
|
||||
ReflectionUtils.getDeclaredField(clazz$ServerboundEditBookPacket, int.class, VersionHelper.isOrAbove1_20_5() ? 0 : 4)
|
||||
);
|
||||
|
||||
public static final Field field$ServerboundEditBookPacket$pages = requireNonNull(
|
||||
@@ -1293,4 +1296,177 @@ public final class NetworkReflections {
|
||||
public static final Constructor<?> constructor$ClientboundTickingStatePacket = Optional.ofNullable(clazz$ClientboundTickingStatePacket)
|
||||
.map(it -> ReflectionUtils.getConstructor(it, float.class, boolean.class))
|
||||
.orElse(null);
|
||||
|
||||
public static final Class<?> clazz$ClientboundBlockEventPacket = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"network.protocol.game.PacketPlayOutBlockAction",
|
||||
"network.protocol.game.ClientboundBlockEventPacket"
|
||||
)
|
||||
);
|
||||
|
||||
public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameSetter;
|
||||
public static final MethodHandle methodHandle$ServerboundHelloPacket$nameGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundHelloPacket$uuidGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundInteractPacket$actionGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundSignUpdatePacket$linesGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundEditBookPacket$pagesGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundEditBookPacket$titleGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundEditBookPacket$slotGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundResourcePackPacket$actionGetter;
|
||||
public static final MethodHandle methodHandle$ClientboundEntityEventPacket$entityIdGetter;
|
||||
public static final MethodHandle methodHandle$ClientboundEntityEventPacket$eventIdGetter;
|
||||
public static final MethodHandle methodHandle$ClientIntentionPacket$protocolVersionGetter;
|
||||
public static final MethodHandle methodHandle$ClientboundRespawnPacket$dimensionGetter;
|
||||
public static final MethodHandle methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter;
|
||||
public static final MethodHandle methodHandle$CommonPlayerSpawnInfo$dimensionGetter;
|
||||
public static final MethodHandle methodHandle$ClientboundLoginPacket$dimensionGetter;
|
||||
public static final MethodHandle methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundPickItemFromBlockPacket$posGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundPickItemFromEntityPacket$idGetter;
|
||||
public static final MethodHandle methodHandle$ServerboundCustomPayloadPacket$payloadGetter;
|
||||
|
||||
static {
|
||||
try {
|
||||
methodHandle$ServerboundRenameItemPacket$nameGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundRenameItemPacket$name)
|
||||
.asType(MethodType.methodType(String.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundRenameItemPacket$nameSetter = requireNonNull(
|
||||
ReflectionUtils.unreflectSetter(field$ServerboundRenameItemPacket$name)
|
||||
.asType(MethodType.methodType(void.class, Object.class, String.class))
|
||||
);
|
||||
methodHandle$ServerboundHelloPacket$nameGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$name)
|
||||
.asType(MethodType.methodType(String.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundHelloPacket$uuidGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$uuid)
|
||||
.asType(MethodType.methodType(VersionHelper.isOrAbove1_20_2() ? UUID.class : Optional.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$itemStack)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$slotNum)
|
||||
.asType(MethodType.methodType(VersionHelper.isOrAbove1_20_5() ? short.class : int.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundInteractPacket$actionGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$action)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$hand)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$location)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundSignUpdatePacket$linesGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundSignUpdatePacket$lines)
|
||||
.asType(MethodType.methodType(String[].class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundEditBookPacket$pagesGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$pages)
|
||||
.asType(MethodType.methodType(List.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundEditBookPacket$titleGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$title)
|
||||
.asType(MethodType.methodType(Optional.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundEditBookPacket$slotGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$slot)
|
||||
.asType(MethodType.methodType(int.class, Object.class))
|
||||
);
|
||||
methodHandle$ServerboundResourcePackPacket$actionGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundResourcePackPacket$action)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
methodHandle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$entityId)
|
||||
.asType(MethodType.methodType(int.class, Object.class))
|
||||
);
|
||||
methodHandle$ClientboundEntityEventPacket$eventIdGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$eventId)
|
||||
.asType(MethodType.methodType(byte.class, Object.class))
|
||||
);
|
||||
methodHandle$ClientIntentionPacket$protocolVersionGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ClientIntentionPacket$protocolVersion)
|
||||
.asType(MethodType.methodType(int.class, Object.class))
|
||||
);
|
||||
if (field$ServerboundCustomPayloadPacket$payload != null) {
|
||||
methodHandle$ServerboundCustomPayloadPacket$payloadGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundCustomPayloadPacket$payload)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$ServerboundCustomPayloadPacket$payloadGetter = null;
|
||||
}
|
||||
if (field$ServerboundPickItemFromEntityPacket$id != null) {
|
||||
methodHandle$ServerboundPickItemFromEntityPacket$idGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromEntityPacket$id)
|
||||
.asType(MethodType.methodType(int.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$ServerboundPickItemFromEntityPacket$idGetter = null;
|
||||
}
|
||||
if (field$ServerboundPickItemFromBlockPacket$pos != null) {
|
||||
methodHandle$ServerboundPickItemFromBlockPacket$posGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromBlockPacket$pos)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$ServerboundPickItemFromBlockPacket$posGetter = null;
|
||||
}
|
||||
if (field$ClientboundLoginPacket$commonPlayerSpawnInfo != null) {
|
||||
methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$commonPlayerSpawnInfo)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = null;
|
||||
}
|
||||
if (field$ClientboundLoginPacket$dimension != null) {
|
||||
methodHandle$ClientboundLoginPacket$dimensionGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$dimension)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$ClientboundLoginPacket$dimensionGetter = null;
|
||||
}
|
||||
if (field$CommonPlayerSpawnInfo$dimension != null) {
|
||||
methodHandle$CommonPlayerSpawnInfo$dimensionGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$CommonPlayerSpawnInfo$dimension)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$CommonPlayerSpawnInfo$dimensionGetter = null;
|
||||
}
|
||||
if (field$ClientboundRespawnPacket$commonPlayerSpawnInfo != null) {
|
||||
methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$commonPlayerSpawnInfo)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = null;
|
||||
}
|
||||
if (field$ClientboundRespawnPacket$dimension != null) {
|
||||
methodHandle$ClientboundRespawnPacket$dimensionGetter = requireNonNull(
|
||||
ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$dimension)
|
||||
.asType(MethodType.methodType(Object.class, Object.class))
|
||||
);
|
||||
} else {
|
||||
methodHandle$ClientboundRespawnPacket$dimensionGetter = null;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new ReflectionInitException("Failed to initialize reflection", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,10 +30,12 @@ import net.momirealms.craftengine.core.plugin.context.CooldownData;
|
||||
import net.momirealms.craftengine.core.plugin.network.ConnectionState;
|
||||
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
|
||||
import net.momirealms.craftengine.core.plugin.network.ProtocolVersion;
|
||||
import net.momirealms.craftengine.core.sound.SoundSource;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Position;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
import org.bukkit.*;
|
||||
@@ -138,17 +140,17 @@ public class BukkitServerPlayer extends Player {
|
||||
|
||||
@Override
|
||||
public Channel nettyChannel() {
|
||||
return channel;
|
||||
return this.channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CraftEngine plugin() {
|
||||
return plugin;
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMiningBlock() {
|
||||
return destroyPos != null;
|
||||
return this.destroyPos != null;
|
||||
}
|
||||
|
||||
public void setDestroyedState(Object destroyedState) {
|
||||
@@ -221,8 +223,8 @@ public class BukkitServerPlayer extends Player {
|
||||
|
||||
@Override
|
||||
public boolean updateLastSuccessfulInteractionTick(int tick) {
|
||||
if (lastSuccessfulInteraction != tick) {
|
||||
lastSuccessfulInteraction = tick;
|
||||
if (this.lastSuccessfulInteraction != tick) {
|
||||
this.lastSuccessfulInteraction = tick;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -231,7 +233,7 @@ public class BukkitServerPlayer extends Player {
|
||||
|
||||
@Override
|
||||
public int lastSuccessfulInteractionTick() {
|
||||
return lastSuccessfulInteraction;
|
||||
return this.lastSuccessfulInteraction;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,8 +285,13 @@ public class BukkitServerPlayer extends Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Key sound, float volume, float pitch) {
|
||||
platformPlayer().playSound(platformPlayer(), sound.toString(), SoundCategory.MASTER, volume, pitch);
|
||||
public void playSound(Key sound, SoundSource source, float volume, float pitch) {
|
||||
platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Key sound, BlockPos blockPos, SoundSource source, float volume, float pitch) {
|
||||
platformPlayer().playSound(new Location(null, blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -535,8 +542,10 @@ public class BukkitServerPlayer extends Player {
|
||||
public void abortMiningBlock() {
|
||||
this.swingHandAck = false;
|
||||
this.miningProgress = 0;
|
||||
if (this.destroyPos != null) {
|
||||
this.broadcastDestroyProgress(platformPlayer(), this.destroyPos, LocationUtils.toBlockPos(this.destroyPos), -1);
|
||||
BlockPos pos = this.destroyPos;
|
||||
if (pos != null && this.isDestroyingCustomBlock) {
|
||||
// 只纠正自定义方块的
|
||||
this.broadcastDestroyProgress(platformPlayer(), pos, LocationUtils.toBlockPos(pos), -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,6 +567,8 @@ public class BukkitServerPlayer extends Player {
|
||||
int currentTick = gameTicks();
|
||||
// optimize break speed, otherwise it would be too fast
|
||||
if (currentTick - this.lastSuccessfulBreak <= 5) return;
|
||||
Object destroyedState = this.destroyedState;
|
||||
if (destroyedState == null) return;
|
||||
try {
|
||||
org.bukkit.entity.Player player = platformPlayer();
|
||||
double range = getCachedInteractionRange();
|
||||
@@ -575,7 +586,7 @@ public class BukkitServerPlayer extends Player {
|
||||
|
||||
// send hit sound if the sound is removed
|
||||
if (currentTick - this.lastHitBlockTime > 3) {
|
||||
Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(this.destroyedState);
|
||||
Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(destroyedState);
|
||||
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(blockOwner);
|
||||
Object soundEvent = CoreReflections.field$SoundType$hitSound.get(soundType);
|
||||
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
|
||||
@@ -601,8 +612,8 @@ public class BukkitServerPlayer extends Player {
|
||||
}
|
||||
}
|
||||
|
||||
float progressToAdd = getDestroyProgress(this.destroyedState, hitPos);
|
||||
int id = BlockStateUtils.blockStateToId(this.destroyedState);
|
||||
float progressToAdd = getDestroyProgress(destroyedState, hitPos);
|
||||
int id = BlockStateUtils.blockStateToId(destroyedState);
|
||||
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(id);
|
||||
// double check custom block
|
||||
if (customState != null && !customState.isEmpty()) {
|
||||
@@ -612,13 +623,13 @@ public class BukkitServerPlayer extends Player {
|
||||
// it's correct on plugin side
|
||||
if (blockSettings.isCorrectTool(item.id())) {
|
||||
// but not on serverside
|
||||
if (!FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), this.destroyedState)) {
|
||||
if (!FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) {
|
||||
// we fix the speed
|
||||
progressToAdd = progressToAdd * (10f / 3f);
|
||||
}
|
||||
} else {
|
||||
// not a correct tool on plugin side and not a correct tool on serverside
|
||||
if (!blockSettings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), this.destroyedState)) {
|
||||
if (!blockSettings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) {
|
||||
progressToAdd = progressToAdd * (10f / 3f) * blockSettings.incorrectToolSpeed();
|
||||
}
|
||||
}
|
||||
@@ -681,7 +692,7 @@ public class BukkitServerPlayer extends Player {
|
||||
double d1 = (double) hitPos.y() - otherLocation.getY();
|
||||
double d2 = (double) hitPos.z() - otherLocation.getZ();
|
||||
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
||||
this.plugin.networkManager().sendPacket(this.plugin.adapt(other), packet);
|
||||
FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.field$Player$connection$connection(FastNMS.INSTANCE.method$CraftPlayer$getHandle(other)), packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -699,16 +710,20 @@ public class BukkitServerPlayer extends Player {
|
||||
public void setIsDestroyingBlock(boolean is, boolean custom) {
|
||||
this.miningProgress = 0;
|
||||
this.isDestroyingBlock = is;
|
||||
this.isDestroyingCustomBlock = custom && is;
|
||||
if (is) {
|
||||
this.swingHandAck = true;
|
||||
this.isDestroyingCustomBlock = custom;
|
||||
} else {
|
||||
this.swingHandAck = false;
|
||||
this.destroyedState = null;
|
||||
if (this.destroyPos != null) {
|
||||
// 只纠正自定义方块的
|
||||
if (this.isDestroyingCustomBlock) {
|
||||
this.broadcastDestroyProgress(platformPlayer(), this.destroyPos, LocationUtils.toBlockPos(this.destroyPos), -1);
|
||||
}
|
||||
this.destroyPos = null;
|
||||
}
|
||||
this.isDestroyingCustomBlock = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public class BukkitSoundManager extends AbstractSoundManager {
|
||||
protected void registerSongs(Map<Key, JukeboxSong> songs) {
|
||||
if (songs.isEmpty()) return;
|
||||
try {
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.instance$Registries$JUKEBOX_SONG);;
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.JUKEBOX_SONG);;
|
||||
unfreezeRegistry(registry);
|
||||
for (Map.Entry<Key, JukeboxSong> entry : songs.entrySet()) {
|
||||
Key id = entry.getKey();
|
||||
|
||||
@@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||
import net.momirealms.craftengine.core.block.*;
|
||||
@@ -22,18 +24,26 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BlockStateUtils {
|
||||
public static final IdentityHashMap<Object, Object> CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>();
|
||||
private static int vanillaStateSize;
|
||||
private static boolean hasInit;
|
||||
public static Map<Object, Integer> IGNITE_ODDS;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void init(int size) {
|
||||
if (hasInit) {
|
||||
throw new IllegalStateException("BlockStateUtils has already been initialized");
|
||||
}
|
||||
vanillaStateSize = size;
|
||||
try {
|
||||
IGNITE_ODDS = (Map<Object, Integer>) CoreReflections.field$FireBlock$igniteOdds.get(MBlocks.FIRE);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to initialize instance$FireBlock$igniteOdds", e);
|
||||
}
|
||||
hasInit = true;
|
||||
}
|
||||
|
||||
@@ -248,4 +258,9 @@ public class BlockStateUtils {
|
||||
public static int vanillaStateSize() {
|
||||
return vanillaStateSize;
|
||||
}
|
||||
|
||||
public static boolean isBurnable(Object state) {
|
||||
Object blockOwner = getBlockOwner(state);
|
||||
return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class BlockTags {
|
||||
Object value = CACHE.get(key);
|
||||
if (value == null) {
|
||||
try {
|
||||
value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, KeyUtils.toResourceLocation(key));
|
||||
value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.BLOCK, KeyUtils.toResourceLocation(key));
|
||||
CACHE.put(key, value);
|
||||
return value;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -2,11 +2,8 @@ package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.core.util.ReflectionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitReflectionUtils {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.core.util.DamageSource;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
|
||||
public class DamageCauseUtils {
|
||||
|
||||
private DamageCauseUtils() {}
|
||||
|
||||
public static EntityDamageEvent.DamageCause toBukkit(DamageSource cause) {
|
||||
return switch (cause) {
|
||||
case BLOCK_EXPLOSION -> EntityDamageEvent.DamageCause.BLOCK_EXPLOSION;
|
||||
case CAMPFIRE -> EntityDamageEvent.DamageCause.CAMPFIRE;
|
||||
case CONTACT -> EntityDamageEvent.DamageCause.CONTACT;
|
||||
case CRAMMING -> EntityDamageEvent.DamageCause.CRAMMING;
|
||||
case CUSTOM -> EntityDamageEvent.DamageCause.CUSTOM;
|
||||
case DROWNING -> EntityDamageEvent.DamageCause.DROWNING;
|
||||
case DRYOUT -> EntityDamageEvent.DamageCause.DRYOUT;
|
||||
case ENTITY_ATTACK -> EntityDamageEvent.DamageCause.ENTITY_ATTACK;
|
||||
case ENTITY_EXPLOSION -> EntityDamageEvent.DamageCause.ENTITY_EXPLOSION;
|
||||
case ENTITY_SWEEP_ATTACK -> EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK;
|
||||
case FALL -> EntityDamageEvent.DamageCause.FALL;
|
||||
case FALLING_BLOCK -> EntityDamageEvent.DamageCause.FALLING_BLOCK;
|
||||
case FIRE -> EntityDamageEvent.DamageCause.FIRE;
|
||||
case FIRE_TICK -> EntityDamageEvent.DamageCause.FIRE_TICK;
|
||||
case FLY_INTO_WALL -> EntityDamageEvent.DamageCause.FLY_INTO_WALL;
|
||||
case FREEZE -> EntityDamageEvent.DamageCause.FREEZE;
|
||||
case HOT_FLOOR -> EntityDamageEvent.DamageCause.HOT_FLOOR;
|
||||
case KILL -> EntityDamageEvent.DamageCause.KILL;
|
||||
case LAVA -> EntityDamageEvent.DamageCause.LAVA;
|
||||
case LIGHTNING -> EntityDamageEvent.DamageCause.LIGHTNING;
|
||||
case MAGIC -> EntityDamageEvent.DamageCause.MAGIC;
|
||||
case MELTING -> EntityDamageEvent.DamageCause.MELTING;
|
||||
case POISON -> EntityDamageEvent.DamageCause.POISON;
|
||||
case PROJECTILE -> EntityDamageEvent.DamageCause.PROJECTILE;
|
||||
case SONIC_BOOM -> EntityDamageEvent.DamageCause.SONIC_BOOM;
|
||||
case STARVATION -> EntityDamageEvent.DamageCause.STARVATION;
|
||||
case SUFFOCATION -> EntityDamageEvent.DamageCause.SUFFOCATION;
|
||||
case SUICIDE -> EntityDamageEvent.DamageCause.SUICIDE;
|
||||
case THORNS -> EntityDamageEvent.DamageCause.THORNS;
|
||||
case VOID -> EntityDamageEvent.DamageCause.VOID;
|
||||
case WITHER -> EntityDamageEvent.DamageCause.WITHER;
|
||||
case WORLD_BORDER -> EntityDamageEvent.DamageCause.WORLD_BORDER;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public static DamageSource fromBukkit(EntityDamageEvent.DamageCause cause) {
|
||||
return switch (cause) {
|
||||
case BLOCK_EXPLOSION -> DamageSource.BLOCK_EXPLOSION;
|
||||
case CAMPFIRE -> DamageSource.CAMPFIRE;
|
||||
case CONTACT -> DamageSource.CONTACT;
|
||||
case CRAMMING -> DamageSource.CRAMMING;
|
||||
case CUSTOM -> DamageSource.CUSTOM;
|
||||
case DROWNING -> DamageSource.DROWNING;
|
||||
case DRYOUT -> DamageSource.DRYOUT;
|
||||
case ENTITY_ATTACK -> DamageSource.ENTITY_ATTACK;
|
||||
case ENTITY_EXPLOSION -> DamageSource.ENTITY_EXPLOSION;
|
||||
case ENTITY_SWEEP_ATTACK -> DamageSource.ENTITY_SWEEP_ATTACK;
|
||||
case FALL -> DamageSource.FALL;
|
||||
case FALLING_BLOCK -> DamageSource.FALLING_BLOCK;
|
||||
case FIRE -> DamageSource.FIRE;
|
||||
case FIRE_TICK -> DamageSource.FIRE_TICK;
|
||||
case FLY_INTO_WALL -> DamageSource.FLY_INTO_WALL;
|
||||
case FREEZE -> DamageSource.FREEZE;
|
||||
case HOT_FLOOR -> DamageSource.HOT_FLOOR;
|
||||
case KILL -> DamageSource.KILL;
|
||||
case LAVA -> DamageSource.LAVA;
|
||||
case LIGHTNING -> DamageSource.LIGHTNING;
|
||||
case MAGIC -> DamageSource.MAGIC;
|
||||
case MELTING -> DamageSource.MELTING;
|
||||
case POISON -> DamageSource.POISON;
|
||||
case PROJECTILE -> DamageSource.PROJECTILE;
|
||||
case SONIC_BOOM -> DamageSource.SONIC_BOOM;
|
||||
case STARVATION -> DamageSource.STARVATION;
|
||||
case SUFFOCATION -> DamageSource.SUFFOCATION;
|
||||
case SUICIDE -> DamageSource.SUICIDE;
|
||||
case THORNS -> DamageSource.THORNS;
|
||||
case VOID -> DamageSource.VOID;
|
||||
case WITHER -> DamageSource.WITHER;
|
||||
case WORLD_BORDER -> DamageSource.WORLD_BORDER;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public class FeatureUtils {
|
||||
|
||||
public static Object createFeatureKey(Key id) {
|
||||
try {
|
||||
return CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
return CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ public class InteractUtils {
|
||||
keyReference, item.getItem()
|
||||
))) != null).isPresent();
|
||||
});
|
||||
registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true);
|
||||
registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true);
|
||||
registerInteraction(BlockKeys.DISPENSER, (player, item, blockState, result) -> true);
|
||||
registerInteraction(BlockKeys.DROPPER, (player, item, blockState, result) -> true);
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ItemTags {
|
||||
Object value = CACHE.get(key);
|
||||
if (value == null) {
|
||||
try {
|
||||
value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.instance$Registries$ITEM, KeyUtils.toResourceLocation(key));
|
||||
value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.ITEM, KeyUtils.toResourceLocation(key));
|
||||
CACHE.put(key, value);
|
||||
return value;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
|
||||
public class NoteBlockChainUpdateUtils {
|
||||
|
||||
private NoteBlockChainUpdateUtils() {}
|
||||
|
||||
// TODO 都在一个区块内,应该优化到区块内的方块getter
|
||||
public static void noteBlockChainUpdate(Object level, Object chunkSource, Object direction, Object blockPos, int times) {
|
||||
if (times >= Config.maxChainUpdate()) return;
|
||||
if (times-- < 0) return;
|
||||
Object relativePos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, direction);
|
||||
Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos);
|
||||
if (BlockStateUtils.isClientSideNoteBlock(state)) {
|
||||
FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, relativePos);
|
||||
noteBlockChainUpdate(level, chunkSource, direction, relativePos, times+1);
|
||||
noteBlockChainUpdate(level, chunkSource, direction, relativePos, times);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class RegistryUtils {
|
||||
|
||||
public static int currentBiomeRegistrySize() {
|
||||
try {
|
||||
Object idMap = CoreReflections.method$Registry$asHolderIdMap.invoke(CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.instance$Registries$BIOME));
|
||||
Object idMap = CoreReflections.method$Registry$asHolderIdMap.invoke(CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.BIOME));
|
||||
return (int) CoreReflections.method$IdMap$size.invoke(idMap);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
package net.momirealms.craftengine.bukkit.world;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.util.EntityUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.ParticleUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.SoundUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.context.Context;
|
||||
import net.momirealms.craftengine.core.sound.SoundSource;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockInWorld;
|
||||
import net.momirealms.craftengine.core.world.Position;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.WorldHeight;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import net.momirealms.craftengine.core.world.particle.ParticleData;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
@@ -124,4 +118,9 @@ public class BukkitWorld implements World {
|
||||
Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.handle(), flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void levelEvent(int id, BlockPos pos, int data) {
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(serverWorld(), id, LocationUtils.toBlockPos(pos), data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,20 @@ debug_clear_cooldown:
|
||||
- /craftengine debug clear-cooldown
|
||||
- /ce debug clear-cooldown
|
||||
|
||||
debug_entity_id_to_uuid:
|
||||
enable: true
|
||||
permission: ce.command.debug.entity_id_to_uuid
|
||||
usage:
|
||||
- /craftengine debug entity-id-to-uuid
|
||||
- /ce debug entity-id-to-uuid
|
||||
|
||||
debug_migrate_templates:
|
||||
enable: true
|
||||
permission: ce.command.debug.migrate_templates
|
||||
usage:
|
||||
- /craftengine debug migrate-templates
|
||||
- /ce debug migrate-templates
|
||||
|
||||
debug_test:
|
||||
enable: true
|
||||
permission: ce.command.debug.test
|
||||
|
||||
@@ -49,12 +49,14 @@ resource-pack:
|
||||
bypass-textures:
|
||||
# - minecraft:block/farmland
|
||||
- "@legacy_unicode"
|
||||
- "@vanilla_font_textures"
|
||||
- "@vanilla_item_textures"
|
||||
- "@vanilla_block_textures"
|
||||
bypass-models: []
|
||||
- "@vanilla_textures"
|
||||
bypass-models:
|
||||
- "@vanilla_models"
|
||||
bypass-sounds: []
|
||||
bypass-equipments: []
|
||||
# Validate if there are any errors in the resource pack, such as missing textures or models
|
||||
validate:
|
||||
enable: true
|
||||
supported-version:
|
||||
min: "1.20"
|
||||
max: LATEST
|
||||
@@ -336,7 +338,7 @@ gui:
|
||||
|
||||
performance:
|
||||
# Maximum chain update depth when fixing client visuals
|
||||
max-block-chain-update-limit: 64
|
||||
max-note-block-chain-update-limit: 48
|
||||
# Prevent lag or oversized packet when processing emoji-heavy content
|
||||
max-emojis-per-parse: 16
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -12,7 +12,7 @@ minecraft:jungle_sapling[stage=1]: minecraft:jungle_sapling[stage=0]
|
||||
minecraft:dark_oak_sapling[stage=1]: minecraft:dark_oak_sapling[stage=0]
|
||||
minecraft:acacia_sapling[stage=1]: minecraft:acacia_sapling[stage=0]
|
||||
minecraft:cherry_sapling[stage=1]: minecraft:cherry_sapling[stage=0]
|
||||
#minecraft:pale_oak_leaves[stage=1]: minecraft:pale_oak_leaves[stage=0] # 1.21.4+
|
||||
#minecraft:pale_oak_sapling[stage=1]: minecraft:pale_oak_sapling[stage=0] # 1.21.4+
|
||||
########################################################################################################################################################################################################################
|
||||
# Ideal block for lower half slabs
|
||||
# Sculk Sensor
|
||||
|
||||
@@ -167,7 +167,7 @@ items#misc:
|
||||
template: "default:loot_table/self"
|
||||
settings:
|
||||
template:
|
||||
- default:sound/sand
|
||||
- default:sound/stone
|
||||
- default:pickaxe_power/level_1
|
||||
- default:settings/solid_1x1x1
|
||||
overrides:
|
||||
|
||||
@@ -2,7 +2,7 @@ templates:
|
||||
default:emoji/basic:
|
||||
content: "<hover:show_text:'<i18n:emoji.tip>'><!shadow><white><arg:emoji></white></!shadow></hover>"
|
||||
default:emoji/addition_info:
|
||||
content: "<hover:show_text:'<i18n:emoji.tip>'><!shadow><white><arg:emoji></white></!shadow>{text}</hover>"
|
||||
content: "<hover:show_text:'<i18n:emoji.tip>'><!shadow><white><arg:emoji></white></!shadow>${text}</hover>"
|
||||
|
||||
emoji:
|
||||
default:emoji_location:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
items:
|
||||
# client-bound-data requires CraftEngine mod to apply
|
||||
minecraft:string:
|
||||
client-bound-data:
|
||||
components:
|
||||
|
||||
@@ -229,16 +229,16 @@ items#topaz_gears:
|
||||
|
||||
templates:
|
||||
default:armor/topaz:
|
||||
material: "chainmail_{part}"
|
||||
material: "chainmail_${part}"
|
||||
custom-model-data: 1000
|
||||
data:
|
||||
item-name: "<!i><#FF8C00><i18n:item.topaz_{part}>"
|
||||
item-name: "<!i><#FF8C00><i18n:item.topaz_${part}>"
|
||||
tooltip-style: minecraft:topaz
|
||||
settings:
|
||||
tags:
|
||||
- "default:topaz_tools"
|
||||
equippable:
|
||||
slot: "{slot}"
|
||||
slot: "${slot}"
|
||||
asset-id: topaz
|
||||
humanoid: "minecraft:topaz"
|
||||
humanoid-leggings: "minecraft:topaz"
|
||||
@@ -247,111 +247,111 @@ templates:
|
||||
property: minecraft:trim_material
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}"
|
||||
path: "minecraft:item/custom/topaz_${part}"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
cases:
|
||||
- when: minecraft:quartz
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_quartz_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_quartz_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_quartz"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_quartz"
|
||||
- when: minecraft:iron
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_iron_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_iron_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_iron"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_iron"
|
||||
- when: minecraft:netherite
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_netherite_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_netherite_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_netherite"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_netherite"
|
||||
- when: minecraft:redstone
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_redstone_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_redstone_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_redstone"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_redstone"
|
||||
- when: minecraft:copper
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_copper_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_copper_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_copper"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_copper"
|
||||
- when: minecraft:gold
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_gold_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_gold_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_gold"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_gold"
|
||||
- when: minecraft:emerald
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_emerald_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_emerald_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_emerald"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_emerald"
|
||||
- when: minecraft:diamond
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_diamond_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_diamond_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_diamond"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_diamond"
|
||||
- when: minecraft:lapis
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_lapis_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_lapis_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_lapis"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_lapis"
|
||||
- when: minecraft:amethyst
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_amethyst_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_amethyst_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_amethyst"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_amethyst"
|
||||
- when: minecraft:resin
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "minecraft:item/custom/topaz_{part}_resin_trim"
|
||||
path: "minecraft:item/custom/topaz_${part}_resin_trim"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "minecraft:item/custom/topaz_{part}"
|
||||
"layer1": "minecraft:trims/items/{part}_trim_resin"
|
||||
"layer0": "minecraft:item/custom/topaz_${part}"
|
||||
"layer1": "minecraft:trims/items/${part}_trim_resin"
|
||||
|
||||
recipes#11:
|
||||
default:topaz_shovel:
|
||||
|
||||
@@ -7,32 +7,32 @@ templates#models#block:
|
||||
# model: model_path
|
||||
# texture: texture_path
|
||||
default:model/cube_all:
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:block/cube_all"
|
||||
textures:
|
||||
"all": "{texture}"
|
||||
"all": "${texture}"
|
||||
# template: default:model/simplified_cube_all
|
||||
# arguments:
|
||||
# path: [model/texture]_path
|
||||
default:model/simplified_cube_all:
|
||||
path: "{path}"
|
||||
path: "${path}"
|
||||
generation:
|
||||
parent: "minecraft:block/cube_all"
|
||||
textures:
|
||||
"all": "{path}"
|
||||
"all": "${path}"
|
||||
# template: default:model/cube_column
|
||||
# arguments:
|
||||
# model: model_path
|
||||
# end_texture: end_texture_path
|
||||
# side_texture: side_texture_path
|
||||
default:model/cube_column:
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:block/cube_column"
|
||||
textures:
|
||||
"end": "{end_texture}"
|
||||
"side": "{side_texture}"
|
||||
"end": "${end_texture}"
|
||||
"side": "${side_texture}"
|
||||
# template: default:model/cube
|
||||
# arguments:
|
||||
# model: model_path
|
||||
@@ -44,7 +44,7 @@ templates#models#block:
|
||||
# south_texture: south_texture_path
|
||||
# west_texture: west_texture_path
|
||||
default:model/cube:
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:block/cube_column"
|
||||
textures:
|
||||
@@ -64,21 +64,21 @@ templates#models#2d:
|
||||
# texture: texture_path
|
||||
default:model/generated:
|
||||
type: "minecraft:model"
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "{texture}"
|
||||
"layer0": "${texture}"
|
||||
# template: default:model/simplified_generated
|
||||
# arguments:
|
||||
# path: [model/texture]_path
|
||||
default:model/simplified_generated:
|
||||
type: "minecraft:model"
|
||||
path: "{path}"
|
||||
path: "${path}"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "{path}"
|
||||
"layer0": "${path}"
|
||||
# template: default:model/2_layer_generated
|
||||
# arguments:
|
||||
# model: model_path
|
||||
@@ -86,33 +86,33 @@ templates#models#2d:
|
||||
# layer1: texture_path
|
||||
default:model/2_layer_generated:
|
||||
type: "minecraft:model"
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "{layer0}"
|
||||
"layer1": "{layer1}"
|
||||
"layer0": "${layer0}"
|
||||
"layer1": "${layer1}"
|
||||
# template: default:model/handheld
|
||||
# arguments:
|
||||
# model: model_path
|
||||
# texture: texture_path
|
||||
default:model/handheld:
|
||||
type: "minecraft:model"
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:item/handheld"
|
||||
textures:
|
||||
"layer0": "{texture}"
|
||||
"layer0": "${texture}"
|
||||
# template: default:model/simplified_handheld
|
||||
# arguments:
|
||||
# path: [model/texture]_path
|
||||
default:model/simplified_handheld:
|
||||
type: "minecraft:model"
|
||||
path: "{path}"
|
||||
path: "${path}"
|
||||
generation:
|
||||
parent: "minecraft:item/handheld"
|
||||
textures:
|
||||
"layer0": "{path}"
|
||||
"layer0": "${path}"
|
||||
# template: default:model/elytra
|
||||
# arguments:
|
||||
# model: model_path
|
||||
@@ -123,17 +123,17 @@ templates#models#2d:
|
||||
type: "minecraft:condition"
|
||||
property: minecraft:broken
|
||||
on-false:
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "{texture}"
|
||||
"layer0": "${texture}"
|
||||
on-true:
|
||||
path: "{broken_model}"
|
||||
path: "${broken_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "{broken_texture}"
|
||||
"layer0": "${broken_texture}"
|
||||
# template: default:model/simplified_elytra
|
||||
# arguments:
|
||||
# path: [model/texture]_path
|
||||
@@ -141,10 +141,10 @@ templates#models#2d:
|
||||
default:model/simplified_elytra:
|
||||
template: default:model/elytra
|
||||
arguments:
|
||||
model: "{path}"
|
||||
texture: "{path}"
|
||||
broken_model: "{broken_path}"
|
||||
broken_texture: "{broken_path}"
|
||||
model: "${path}"
|
||||
texture: "${path}"
|
||||
broken_model: "${broken_path}"
|
||||
broken_texture: "${broken_path}"
|
||||
|
||||
# shield
|
||||
templates#models#shield:
|
||||
@@ -157,10 +157,10 @@ templates#models#shield:
|
||||
property: "minecraft:using_item"
|
||||
on-false:
|
||||
type: minecraft:model
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
on-true:
|
||||
type: minecraft:model
|
||||
path: "{block_model}"
|
||||
path: "${block_model}"
|
||||
|
||||
# fishing rods
|
||||
templates#models#fishing_rod:
|
||||
@@ -173,10 +173,10 @@ templates#models#fishing_rod:
|
||||
property: "minecraft:fishing_rod/cast"
|
||||
on-false:
|
||||
type: "minecraft:model"
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
on-true:
|
||||
type: "minecraft:model"
|
||||
path: "{cast_model}"
|
||||
path: "${cast_model}"
|
||||
# template: default:model/fishing_rod_2d
|
||||
# arguments:
|
||||
# model: rod_model_path
|
||||
@@ -188,18 +188,18 @@ templates#models#fishing_rod:
|
||||
property: "minecraft:fishing_rod/cast"
|
||||
on-false:
|
||||
type: "minecraft:model"
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:item/fishing_rod"
|
||||
textures:
|
||||
"layer0": "{texture}"
|
||||
"layer0": "${texture}"
|
||||
on-true:
|
||||
type: "minecraft:model"
|
||||
path: "{cast_model}"
|
||||
path: "${cast_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/fishing_rod"
|
||||
textures:
|
||||
"layer0": "{cast_texture}"
|
||||
"layer0": "${cast_texture}"
|
||||
# template: default:model/simplified_fishing_rod_2d
|
||||
# arguments:
|
||||
# path: rod_[model/texture]_path
|
||||
@@ -207,10 +207,10 @@ templates#models#fishing_rod:
|
||||
default:model/simplified_fishing_rod_2d:
|
||||
template: default:model/fishing_rod_2d
|
||||
arguments:
|
||||
texture: "{path}"
|
||||
model: "{path}"
|
||||
cast_texture: "{cast_path}"
|
||||
cast_model: "{cast_path}"
|
||||
texture: "${path}"
|
||||
model: "${path}"
|
||||
cast_texture: "${cast_path}"
|
||||
cast_model: "${cast_path}"
|
||||
|
||||
# bows
|
||||
templates#models#bow:
|
||||
@@ -225,7 +225,7 @@ templates#models#bow:
|
||||
property: "minecraft:using_item"
|
||||
on-false:
|
||||
type: "minecraft:model"
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
on-true:
|
||||
type: "minecraft:range_dispatch"
|
||||
property: "minecraft:use_duration"
|
||||
@@ -233,15 +233,15 @@ templates#models#bow:
|
||||
entries:
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_1_model}"
|
||||
path: "${pulling_1_model}"
|
||||
threshold: 0.65
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_2_model}"
|
||||
path: "${pulling_2_model}"
|
||||
threshold: 0.9
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: "{pulling_0_model}"
|
||||
path: "${pulling_0_model}"
|
||||
# template: default:model/bow_2d
|
||||
# arguments:
|
||||
# model: bow_model_path
|
||||
@@ -257,11 +257,11 @@ templates#models#bow:
|
||||
property: "minecraft:using_item"
|
||||
on-false:
|
||||
type: "minecraft:model"
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:item/bow"
|
||||
textures:
|
||||
"layer0": "{texture}"
|
||||
"layer0": "${texture}"
|
||||
on-true:
|
||||
type: "minecraft:range_dispatch"
|
||||
property: "minecraft:use_duration"
|
||||
@@ -269,27 +269,27 @@ templates#models#bow:
|
||||
entries:
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_1_model}"
|
||||
path: "${pulling_1_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/bow_pulling_1"
|
||||
textures:
|
||||
"layer0": "{pulling_1_texture}"
|
||||
"layer0": "${pulling_1_texture}"
|
||||
threshold: 0.65
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_2_model}"
|
||||
path: "${pulling_2_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/bow_pulling_2"
|
||||
textures:
|
||||
"layer0": "{pulling_2_texture}"
|
||||
"layer0": "${pulling_2_texture}"
|
||||
threshold: 0.9
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: "{pulling_0_model}"
|
||||
path: "${pulling_0_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/bow_pulling_0"
|
||||
textures:
|
||||
"layer0": "{pulling_0_texture}"
|
||||
"layer0": "${pulling_0_texture}"
|
||||
# template: default:model/simplified_bow_2d
|
||||
# arguments:
|
||||
# path: bow_[model/texture]_path
|
||||
@@ -299,14 +299,14 @@ templates#models#bow:
|
||||
default:model/simplified_bow_2d:
|
||||
template: default:model/bow_2d
|
||||
arguments:
|
||||
model: "{path}"
|
||||
pulling_0_model: "{pulling_0_path}"
|
||||
pulling_1_model: "{pulling_1_path}"
|
||||
pulling_2_model: "{pulling_2_path}"
|
||||
texture: "{path}"
|
||||
pulling_0_texture: "{pulling_0_path}"
|
||||
pulling_1_texture: "{pulling_1_path}"
|
||||
pulling_2_texture: "{pulling_2_path}"
|
||||
model: "${path}"
|
||||
pulling_0_model: "${pulling_0_path}"
|
||||
pulling_1_model: "${pulling_1_path}"
|
||||
pulling_2_model: "${pulling_2_path}"
|
||||
texture: "${path}"
|
||||
pulling_0_texture: "${pulling_0_path}"
|
||||
pulling_1_texture: "${pulling_1_path}"
|
||||
pulling_2_texture: "${pulling_2_path}"
|
||||
|
||||
# crossbows
|
||||
templates#models#crossbow:
|
||||
@@ -328,29 +328,29 @@ templates#models#crossbow:
|
||||
- when: arrow
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "{arrow_model}"
|
||||
path: "${arrow_model}"
|
||||
- when: rocket
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "{firework_model}"
|
||||
path: "${firework_model}"
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
on-true:
|
||||
type: "minecraft:range_dispatch"
|
||||
property: "minecraft:crossbow/pull"
|
||||
entries:
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_1_model}"
|
||||
path: "${pulling_1_model}"
|
||||
threshold: 0.58
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_2_model}"
|
||||
path: "${pulling_2_model}"
|
||||
threshold: 1.0
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: "{pulling_0_model}"
|
||||
path: "${pulling_0_model}"
|
||||
# template: default:model/crossbow_2d
|
||||
# arguments:
|
||||
# model: crossbow_model_path
|
||||
@@ -375,53 +375,53 @@ templates#models#crossbow:
|
||||
- when: arrow
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "{arrow_model}"
|
||||
path: "${arrow_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/crossbow_arrow"
|
||||
textures:
|
||||
"layer0": "{arrow_texture}"
|
||||
"layer0": "${arrow_texture}"
|
||||
- when: rocket
|
||||
model:
|
||||
type: minecraft:model
|
||||
path: "{firework_model}"
|
||||
path: "${firework_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/crossbow_firework"
|
||||
textures:
|
||||
"layer0": "{firework_texture}"
|
||||
"layer0": "${firework_texture}"
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: "{model}"
|
||||
path: "${model}"
|
||||
generation:
|
||||
parent: "minecraft:item/crossbow"
|
||||
textures:
|
||||
"layer0": "{texture}"
|
||||
"layer0": "${texture}"
|
||||
on-true:
|
||||
type: "minecraft:range_dispatch"
|
||||
property: "minecraft:crossbow/pull"
|
||||
entries:
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_1_model}"
|
||||
path: "${pulling_1_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/crossbow_pulling_1"
|
||||
textures:
|
||||
"layer0": "{pulling_1_texture}"
|
||||
"layer0": "${pulling_1_texture}"
|
||||
threshold: 0.58
|
||||
- model:
|
||||
type: minecraft:model
|
||||
path: "{pulling_2_model}"
|
||||
path: "${pulling_2_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/crossbow_pulling_2"
|
||||
textures:
|
||||
"layer0": "{pulling_2_texture}"
|
||||
"layer0": "${pulling_2_texture}"
|
||||
threshold: 1.0
|
||||
fallback:
|
||||
type: minecraft:model
|
||||
path: "{pulling_0_model}"
|
||||
path: "${pulling_0_model}"
|
||||
generation:
|
||||
parent: "minecraft:item/crossbow_pulling_0"
|
||||
textures:
|
||||
"layer0": "{pulling_0_texture}"
|
||||
"layer0": "${pulling_0_texture}"
|
||||
# template: default:model/simplified_crossbow_2d
|
||||
# arguments:
|
||||
# path: crossbow_[model/texture]_path
|
||||
@@ -433,28 +433,28 @@ templates#models#crossbow:
|
||||
default:model/simplified_crossbow_2d:
|
||||
template: default:model/crossbow_2d
|
||||
arguments:
|
||||
model: "{path}"
|
||||
texture: "{path}"
|
||||
arrow_model: "{arrow_path}"
|
||||
arrow_texture: "{arrow_path}"
|
||||
firework_model: "{firework_path}"
|
||||
firework_texture: "{firework_path}"
|
||||
pulling_0_model: "{pulling_0_path}"
|
||||
pulling_0_texture: "{pulling_0_path}"
|
||||
pulling_1_model: "{pulling_1_path}"
|
||||
pulling_1_texture: "{pulling_1_path}"
|
||||
pulling_2_model: "{pulling_2_path}"
|
||||
pulling_2_texture: "{pulling_2_path}"
|
||||
model: "${path}"
|
||||
texture: "${path}"
|
||||
arrow_model: "${arrow_path}"
|
||||
arrow_texture: "${arrow_path}"
|
||||
firework_model: "${firework_path}"
|
||||
firework_texture: "${firework_path}"
|
||||
pulling_0_model: "${pulling_0_path}"
|
||||
pulling_0_texture: "${pulling_0_path}"
|
||||
pulling_1_model: "${pulling_1_path}"
|
||||
pulling_1_texture: "${pulling_1_path}"
|
||||
pulling_2_model: "${pulling_2_path}"
|
||||
pulling_2_texture: "${pulling_2_path}"
|
||||
|
||||
# sounds
|
||||
templates#settings#sounds:
|
||||
default:sound/block_template:
|
||||
sounds:
|
||||
break: "minecraft:block.{block_type}.break"
|
||||
step: "minecraft:block.{block_type}.step"
|
||||
place: "minecraft:block.{block_type}.place"
|
||||
hit: "minecraft:block.{block_type}.hit"
|
||||
fall: "minecraft:block.{block_type}.fall"
|
||||
break: "minecraft:block.${block_type}.break"
|
||||
step: "minecraft:block.${block_type}.step"
|
||||
place: "minecraft:block.${block_type}.place"
|
||||
hit: "minecraft:block.${block_type}.hit"
|
||||
fall: "minecraft:block.${block_type}.fall"
|
||||
default:sound/crop:
|
||||
sounds:
|
||||
break: "minecraft:block.crop.break"
|
||||
@@ -614,7 +614,7 @@ templates#settings#break_level:
|
||||
# block settings
|
||||
templates#settings#blocks:
|
||||
default:settings/middle_click_pick_itself:
|
||||
item: "{__NAMESPACE__}:{__ID__}"
|
||||
item: "${__NAMESPACE__}:${__ID__}"
|
||||
default:settings/solid_1x1x1:
|
||||
is-suffocating: true
|
||||
replaceable: false
|
||||
@@ -696,7 +696,7 @@ templates#settings#blocks:
|
||||
default:settings/ore:
|
||||
template:
|
||||
- "default:sound/stone"
|
||||
- "default:pickaxe_power/level_{break_power}"
|
||||
- "default:pickaxe_power/level_${break_power}"
|
||||
overrides:
|
||||
hardness: 3.0
|
||||
resistance: 3.0
|
||||
@@ -712,7 +712,7 @@ templates#settings#blocks:
|
||||
default:settings/deepslate_ore:
|
||||
template:
|
||||
- "default:sound/deepslate"
|
||||
- "default:pickaxe_power/level_{break_power}"
|
||||
- "default:pickaxe_power/level_${break_power}"
|
||||
overrides:
|
||||
hardness: 4.5
|
||||
resistance: 3.0
|
||||
@@ -735,45 +735,45 @@ templates#block_states:
|
||||
default: y
|
||||
appearances:
|
||||
axisY:
|
||||
state: "{base_block}:{vanilla_id}"
|
||||
state: "${base_block}:${vanilla_id}"
|
||||
model:
|
||||
path: "{model_vertical_path}"
|
||||
path: "${model_vertical_path}"
|
||||
generation:
|
||||
parent: "minecraft:block/cube_column"
|
||||
textures:
|
||||
"end": "{texture_top_path}"
|
||||
"side": "{texture_side_path}"
|
||||
"end": "${texture_top_path}"
|
||||
"side": "${texture_side_path}"
|
||||
axisX:
|
||||
state: "{base_block}:{vanilla_id}"
|
||||
state: "${base_block}:${vanilla_id}"
|
||||
model:
|
||||
x: 90
|
||||
y: 90
|
||||
path: "{model_horizontal_path}"
|
||||
path: "${model_horizontal_path}"
|
||||
generation:
|
||||
parent: "minecraft:block/cube_column_horizontal"
|
||||
textures:
|
||||
"end": "{texture_top_path}"
|
||||
"side": "{texture_side_path}"
|
||||
"end": "${texture_top_path}"
|
||||
"side": "${texture_side_path}"
|
||||
axisZ:
|
||||
state: "{base_block}:{vanilla_id}"
|
||||
state: "${base_block}:${vanilla_id}"
|
||||
model:
|
||||
x: 90
|
||||
path: "{model_horizontal_path}"
|
||||
path: "${model_horizontal_path}"
|
||||
generation:
|
||||
parent: "minecraft:block/cube_column_horizontal"
|
||||
textures:
|
||||
"end": "{texture_top_path}"
|
||||
"side": "{texture_side_path}"
|
||||
"end": "${texture_top_path}"
|
||||
"side": "${texture_side_path}"
|
||||
variants:
|
||||
axis=x:
|
||||
appearance: axisX
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
axis=y:
|
||||
appearance: axisY
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
axis=z:
|
||||
appearance: axisZ
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
default:block_state/leaves:
|
||||
properties:
|
||||
waterlogged:
|
||||
@@ -788,107 +788,107 @@ templates#block_states:
|
||||
range: 1~7
|
||||
appearances:
|
||||
default:
|
||||
state: "{default_state}"
|
||||
state: "${default_state}"
|
||||
model:
|
||||
path: "{model_path}"
|
||||
path: "${model_path}"
|
||||
generation:
|
||||
parent: "minecraft:block/leaves"
|
||||
textures:
|
||||
"all": "{texture_path}"
|
||||
"all": "${texture_path}"
|
||||
waterlogged:
|
||||
state: "{waterlogged_state}"
|
||||
state: "${waterlogged_state}"
|
||||
model:
|
||||
path: "{model_path}"
|
||||
path: "${model_path}"
|
||||
variants:
|
||||
distance=1,persistent=false,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=2,persistent=false,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=3,persistent=false,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=4,persistent=false,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=5,persistent=false,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=6,persistent=false,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=7,persistent=false,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
is-randomly-ticking: true
|
||||
distance=1,persistent=true,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=2,persistent=true,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=3,persistent=true,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=4,persistent=true,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=5,persistent=true,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=6,persistent=true,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=7,persistent=true,waterlogged=false:
|
||||
appearance: "default"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
distance=1,persistent=false,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=2,persistent=false,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=3,persistent=false,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=4,persistent=false,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=5,persistent=false,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=6,persistent=false,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=7,persistent=false,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
@@ -896,49 +896,49 @@ templates#block_states:
|
||||
fluid-state: water
|
||||
distance=1,persistent=true,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=2,persistent=true,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=3,persistent=true,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=4,persistent=true,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=5,persistent=true,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=6,persistent=true,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
fluid-state: water
|
||||
distance=7,persistent=true,waterlogged=true:
|
||||
appearance: "waterlogged"
|
||||
id: "{internal_id}"
|
||||
id: "${internal_id}"
|
||||
settings:
|
||||
resistance: 1200.0
|
||||
burnable: false
|
||||
@@ -951,9 +951,9 @@ templates#recipes:
|
||||
category: building
|
||||
group: planks
|
||||
ingredients:
|
||||
A: "#default:{wood_type}_logs"
|
||||
A: "#default:${wood_type}_logs"
|
||||
result:
|
||||
id: "default:{wood_type}_planks"
|
||||
id: "default:${wood_type}_planks"
|
||||
count: 4
|
||||
default:recipe/log_2_wood:
|
||||
type: shaped
|
||||
@@ -963,29 +963,29 @@ templates#recipes:
|
||||
- "AA"
|
||||
- "AA"
|
||||
ingredients:
|
||||
A: "default:{wood_type}_log"
|
||||
A: "default:${wood_type}_log"
|
||||
result:
|
||||
id: "default:{wood_type}_wood"
|
||||
id: "default:${wood_type}_wood"
|
||||
count: 3
|
||||
default:recipe/smelting_ore:
|
||||
type: smelting
|
||||
experience: "{exp}"
|
||||
experience: "${exp}"
|
||||
category: misc
|
||||
group: topaz
|
||||
time: 200
|
||||
ingredient: "{ingredient}"
|
||||
ingredient: "${ingredient}"
|
||||
result:
|
||||
id: "{result}"
|
||||
id: "${result}"
|
||||
count: 1
|
||||
default:recipe/blasting_ore:
|
||||
type: blasting
|
||||
experience: "{exp}"
|
||||
experience: "${exp}"
|
||||
category: misc
|
||||
group: topaz
|
||||
time: 100
|
||||
ingredient: "{ingredient}"
|
||||
ingredient: "${ingredient}"
|
||||
result:
|
||||
id: "{result}"
|
||||
id: "${result}"
|
||||
count: 1
|
||||
|
||||
# loot tables
|
||||
@@ -1001,7 +1001,7 @@ templates#loot_tables:
|
||||
- type: survives_explosion
|
||||
entries:
|
||||
- type: item
|
||||
item: "{__NAMESPACE__}:{__ID__}"
|
||||
item: "${__NAMESPACE__}:${__ID__}"
|
||||
|
||||
# drop one item
|
||||
|
||||
@@ -1015,7 +1015,7 @@ templates#loot_tables:
|
||||
- type: survives_explosion
|
||||
entries:
|
||||
- type: item
|
||||
item: "{item}"
|
||||
item: "${item}"
|
||||
|
||||
# drop the original furniture item or a fallback item
|
||||
|
||||
@@ -1027,7 +1027,7 @@ templates#loot_tables:
|
||||
- rolls: 1
|
||||
entries:
|
||||
- type: furniture_item
|
||||
item: "{item}"
|
||||
item: "${item}"
|
||||
|
||||
# drop with silk touch
|
||||
|
||||
@@ -1042,7 +1042,7 @@ templates#loot_tables:
|
||||
predicate: minecraft:silk_touch>=1
|
||||
entries:
|
||||
- type: item
|
||||
item: "{item}"
|
||||
item: "${item}"
|
||||
|
||||
# crop drops
|
||||
|
||||
@@ -1058,21 +1058,21 @@ templates#loot_tables:
|
||||
- type: alternatives
|
||||
children:
|
||||
- type: item
|
||||
item: "{crop_item}"
|
||||
item: "${crop_item}"
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: "{ripe_age}"
|
||||
age: "${ripe_age}"
|
||||
- type: item
|
||||
item: "{crop_seed}"
|
||||
item: "${crop_seed}"
|
||||
- rolls: 1
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: "{ripe_age}"
|
||||
age: "${ripe_age}"
|
||||
entries:
|
||||
- type: item
|
||||
item: "{crop_seed}"
|
||||
item: "${crop_seed}"
|
||||
functions:
|
||||
- type: apply_bonus
|
||||
enchantment: minecraft:fortune
|
||||
@@ -1090,15 +1090,15 @@ templates#loot_tables:
|
||||
- rolls: 1
|
||||
entries:
|
||||
- type: item
|
||||
item: "{crop_item}"
|
||||
item: "${crop_item}"
|
||||
- rolls: 1
|
||||
conditions:
|
||||
- type: match_block_property
|
||||
properties:
|
||||
age: "{ripe_age}"
|
||||
age: "${ripe_age}"
|
||||
entries:
|
||||
- type: item
|
||||
item: "{crop_item}"
|
||||
item: "${crop_item}"
|
||||
functions:
|
||||
- type: apply_bonus
|
||||
enchantment: minecraft:fortune
|
||||
@@ -1122,12 +1122,12 @@ templates#loot_tables:
|
||||
- type: alternatives
|
||||
children:
|
||||
- type: item
|
||||
item: "{ore_block}"
|
||||
item: "${ore_block}"
|
||||
conditions:
|
||||
- type: enchantment
|
||||
predicate: minecraft:silk_touch>=1
|
||||
- type: item
|
||||
item: "{ore_drop}"
|
||||
item: "${ore_drop}"
|
||||
functions:
|
||||
- type: apply_bonus
|
||||
enchantment: minecraft:fortune
|
||||
@@ -1137,8 +1137,8 @@ templates#loot_tables:
|
||||
- type: drop_exp
|
||||
count:
|
||||
type: uniform
|
||||
min: "{min_exp}"
|
||||
max: "{max_exp}"
|
||||
min: "${min_exp:-2}"
|
||||
max: "${max_exp:-4}"
|
||||
|
||||
# template: default:loot_table/ore_no_exp
|
||||
# arguments:
|
||||
@@ -1151,12 +1151,12 @@ templates#loot_tables:
|
||||
- type: alternatives
|
||||
children:
|
||||
- type: item
|
||||
item: "{ore_block}"
|
||||
item: "${ore_block}"
|
||||
conditions:
|
||||
- type: enchantment
|
||||
predicate: minecraft:silk_touch>=1
|
||||
- type: item
|
||||
item: "{ore_drop}"
|
||||
item: "${ore_drop}"
|
||||
functions:
|
||||
- type: apply_bonus
|
||||
enchantment: minecraft:fortune
|
||||
@@ -1177,7 +1177,7 @@ templates#loot_tables:
|
||||
- type: alternatives
|
||||
children:
|
||||
- type: item
|
||||
item: "{leaves}"
|
||||
item: "${leaves}"
|
||||
conditions:
|
||||
- type: any_of
|
||||
terms:
|
||||
@@ -1186,7 +1186,7 @@ templates#loot_tables:
|
||||
- type: enchantment
|
||||
predicate: minecraft:silk_touch>=1
|
||||
- type: item
|
||||
item: "{sapling}"
|
||||
item: "${sapling}"
|
||||
conditions:
|
||||
- type: survives_explosion
|
||||
- type: table_bonus
|
||||
|
||||
@@ -69,21 +69,21 @@ images:
|
||||
templates:
|
||||
internal:icon/2d:
|
||||
material: arrow
|
||||
custom-model-data: "{model_data}"
|
||||
custom-model-data: "${model_data}"
|
||||
data:
|
||||
item-name: "{name}"
|
||||
lore: "{lore}"
|
||||
item-name: "${name}"
|
||||
lore: "${lore}"
|
||||
model:
|
||||
template: "internal:model/simplified_generated"
|
||||
arguments:
|
||||
path: "minecraft:item/custom/gui/{texture}"
|
||||
path: "minecraft:item/custom/gui/${texture}"
|
||||
internal:model/simplified_generated:
|
||||
type: "minecraft:model"
|
||||
path: "{path}"
|
||||
path: "${path}"
|
||||
generation:
|
||||
parent: "minecraft:item/generated"
|
||||
textures:
|
||||
"layer0": "{path}"
|
||||
"layer0": "${path}"
|
||||
|
||||
items:
|
||||
internal:next_page_0:
|
||||
|
||||
@@ -64,6 +64,7 @@ command.upload.on_progress: "<white>Started uploading progress. Check the consol
|
||||
command.send_resource_pack.success.single: "<white>Sent resource pack to <arg:0>.</white>"
|
||||
command.send_resource_pack.success.multiple: "<white>Send resource packs to <arg:0> players.</white>"
|
||||
warning.config.pack.duplicated_files: "</red>Duplicated files Found. Please resolve them through config.yml 'resource-pack.duplicated-files-handler' section.</red>"
|
||||
warning.config.yaml.duplicated_key: "<red>Issue found in file <arg:0> - Found duplicated key '<arg:1>' at line <arg:2>, this might cause unexpected results.</red>"
|
||||
warning.config.type.int: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to integer type for option '<arg:3>'.</yellow>"
|
||||
warning.config.type.float: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to float type for option '<arg:3>'.</yellow>"
|
||||
warning.config.type.double: "<yellow>Issue found in file <arg:0> - Failed to load '<arg:1>': Cannot cast '<arg:2>' to double type for option '<arg:3>'.</yellow>"
|
||||
@@ -113,7 +114,6 @@ warning.config.image.missing_char: "<yellow>Issue found in file <arg:0> - The im
|
||||
warning.config.image.codepoint_conflict: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is using a character '<arg:3>(<arg:4>)' in font <arg:2> that has been used by another image '<arg:5>'.</yellow>"
|
||||
warning.config.image.invalid_codepoint_grid: "<yellow>Issue found in file <arg:0> - Image '<arg:1>' has an invalid 'chars' codepoint grid.</yellow>"
|
||||
warning.config.image.invalid_char: "<yellow>Issue found in file <arg:0> - Image '<arg:1>' has a char parameter containing combining characters, which may result in image splitting.</yellow>"
|
||||
warning.config.image.file_not_found: "<yellow>Issue found in file <arg:0> - PNG file '<arg:2>' not found for image '<arg:1>'.</yellow>"
|
||||
warning.config.image.invalid_hex_value: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is using a unicode character '<arg:2>' that is not a valid hexadecimal (radix 16) value.</yellow>"
|
||||
warning.config.recipe.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated recipe '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
warning.config.recipe.missing_type: "<yellow>Issue found in file <arg:0> - The recipe '<arg:1>' is missing the required 'type' argument.</yellow>"
|
||||
@@ -133,8 +133,10 @@ warning.config.recipe.smithing_transform.post_processor.keep_component.missing_c
|
||||
warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "<yellow>Issue found in file <arg:0> - The smithing transform recipe '<arg:1>' is missing the required argument 'tags' for post-processors 'keep_tags'.</yellow>"
|
||||
warning.config.i18n.unknown_locale: "<yellow>Issue found in file <arg:0> - Unknown locale '<arg:1>'.</yellow>"
|
||||
warning.config.template.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated template '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
warning.config.template.invalid: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid template '<arg:2>'.</yellow>"
|
||||
warning.config.template.argument.self_increase_int.invalid_range: "<yellow>Issue found in file <arg:0> - The template '<arg:1>' is using a 'from' '<arg:2>' larger than 'to' '<arg:3>' in 'self_increase_int' argument.</yellow>"
|
||||
warning.config.template.argument.list.invalid_type: "<yellow>Issue found in file <arg:0> - The template '<arg:1>' is using a 'list' argument which expects a 'List' as argument while the input argument is a(n) '<arg:2>'.</yellow>"
|
||||
warning.config.template.argument.default_value.invalid_syntax: "<yellow>Issue found in file <arg:0> - The template '<arg:1>' is using an invalid default value '<arg:2>' for argument '<arg:3>'.</yellow>"
|
||||
warning.config.vanilla_loot.missing_type: "<yellow>Issue found in file <arg:0> - The vanilla loot '<arg:1>' is missing the required 'type' argument.</yellow>"
|
||||
warning.config.vanilla_loot.invalid_type: "<yellow>Issue found in file <arg:0> - The vanilla loot '<arg:1>' is using an invalid type '<arg:2>'. Allowed types: [<arg:3>].</yellow>"
|
||||
warning.config.vanilla_loot.block.invalid_target: "<yellow>Issue found in file <arg:0> - Invalid block target '<arg:2>' in vanilla loot '<arg:1>'.</yellow>"
|
||||
@@ -151,11 +153,13 @@ warning.config.furniture.hitbox.invalid_type: "<yellow>Issue found in file <arg:
|
||||
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Issue found in file <arg:0> - The furniture '<arg:1>' is using a custom hitbox with invalid entity type '<arg:2>'.</yellow>"
|
||||
warning.config.item.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated item '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
warning.config.item.settings.unknown: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown setting type '<arg:2>'.</yellow>"
|
||||
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an unknown damage source '<arg:2>'. Allowed sources: [<arg:3>].</yellow>"
|
||||
warning.config.item.missing_material: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'material' argument.</yellow>"
|
||||
warning.config.item.invalid_material: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid material type '<arg:2>'.</yellow>"
|
||||
warning.config.item.invalid_custom_model_data: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a negative custom model data '<arg:2>' which is invalid.</yellow>"
|
||||
warning.config.item.bad_custom_model_data: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a custom model data '<arg:2>' that is too large. It's recommended to use a value lower than 16,777,216.</yellow>"
|
||||
warning.config.item.custom_model_data_conflict: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a custom model data '<arg:2>' that has been occupied by item '<arg:3>'.</yellow>"
|
||||
warning.config.item.invalid_component: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using a non-existing component type '<arg:2>'.</yellow>"
|
||||
warning.config.item.missing_model_id: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'custom-model-data' or 'item-model' argument.</yellow>"
|
||||
warning.config.item.missing_model: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'model' section for 1.21.4+ resource pack support.</yellow>"
|
||||
warning.config.item.behavior.missing_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'type' argument for its item behavior.</yellow>"
|
||||
@@ -350,3 +354,8 @@ warning.config.selector.invalid_target: "<yellow>Issue found in file <arg:0> - T
|
||||
warning.config.resource_pack.item_model.conflict.vanilla: "<yellow>Failed to generate item model for '<arg:0>' because this item model has been occupied by a vanilla item.</yellow>"
|
||||
warning.config.resource_pack.item_model.already_exist: "<yellow>Failed to generate item model for '<arg:0>' because the file '<arg:1>' already exists.</yellow>"
|
||||
warning.config.resource_pack.model.generation.already_exist: "<yellow>Failed to generate model because the model file '<arg:0>' already exists.</yellow>"
|
||||
warning.config.resource_pack.generation.missing_font_texture: "<yellow>Font '<arg:0>' is missing required texture: '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.missing_model_texture: "<yellow>Model '<arg:0>' is missing texture '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.missing_item_model: "<yellow>Item '<arg:0>' is missing model file: '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.missing_block_model: "<yellow>Block '<arg:0>' is missing model file: '<arg:1>'</yellow>"
|
||||
warning.config.resource_pack.generation.missing_parent_model: "<yellow>Model '<arg:0>' cannot find parent model: '<arg:1>'</yellow>"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user