mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-23 17:09:19 +00:00
Merge remote-tracking branch 'upstream/dev' into dev
# Conflicts: # gradle.properties
This commit is contained in:
@@ -46,7 +46,6 @@ dependencies {
|
||||
compileOnly("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}")
|
||||
// Adventure
|
||||
compileOnly("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}") {
|
||||
exclude("com.google.code.gson", "gson")
|
||||
|
||||
@@ -6,7 +6,7 @@ import ch.njol.skript.lang.Expression;
|
||||
import ch.njol.skript.lang.SkriptParser;
|
||||
import ch.njol.util.Kleenean;
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.Furniture;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.Event;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -23,9 +23,9 @@ public class EffRemoveFurniture extends Effect {
|
||||
protected void execute(Event e) {
|
||||
for (Entity entity : entities.getArray(e)) {
|
||||
if (CraftEngineFurniture.isFurniture(entity)) {
|
||||
LoadedFurniture loadedFurniture = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity);
|
||||
if (loadedFurniture != null) {
|
||||
loadedFurniture.destroy();
|
||||
Furniture bukkitFurniture = CraftEngineFurniture.getLoadedFurnitureByBaseEntity(entity);
|
||||
if (bukkitFurniture != null) {
|
||||
bukkitFurniture.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ dependencies {
|
||||
implementation(project(":bukkit:compatibility"))
|
||||
implementation(project(":bukkit:compatibility:legacy"))
|
||||
|
||||
implementation("net.kyori:adventure-platform-bukkit:${rootProject.properties["adventure_platform_version"]}")
|
||||
implementation("com.saicone.rtag:rtag-item:${rootProject.properties["rtag_version"]}")
|
||||
implementation("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}")
|
||||
implementation("net.momirealms:antigrieflib:${rootProject.properties["anti_grief_version"]}")
|
||||
|
||||
@@ -23,10 +23,9 @@ commons-io=${commons_io_version}
|
||||
commons-imaging=${commons_imaging_version}
|
||||
byte-buddy=${byte_buddy_version}
|
||||
snake-yaml=${snake_yaml_version}
|
||||
adventure-text-minimessage=${adventure_bundle_version}
|
||||
adventure-text-serializer-gson=${adventure_bundle_version}
|
||||
adventure-text-serializer-json=${adventure_bundle_version}
|
||||
adventure-text-serializer-json-legacy-impl=${adventure_bundle_version}
|
||||
examination-api=1.3.0
|
||||
option=1.1.0
|
||||
adventure-api=${adventure_bundle_version}
|
||||
netty-codec-http=${netty_version}
|
||||
ahocorasick=${ahocorasick_version}
|
||||
lz4=${lz4_version}
|
||||
|
||||
@@ -64,14 +64,12 @@ items#misc:
|
||||
events:
|
||||
- on: right_click
|
||||
functions:
|
||||
- type: run
|
||||
functions:
|
||||
- type: open_window
|
||||
gui-type: anvil
|
||||
- type: cancel_event
|
||||
conditions:
|
||||
- type: expression
|
||||
expression: "!<arg:player.is_sneaking>"
|
||||
- type: open_window
|
||||
gui-type: anvil
|
||||
- type: cancel_event
|
||||
conditions:
|
||||
- type: expression
|
||||
expression: "!<arg:player.is_sneaking>"
|
||||
settings:
|
||||
template:
|
||||
- default:pickaxe_power/level_4
|
||||
|
||||
@@ -94,6 +94,9 @@ warning.config.condition.permission.missing_permission: "<yellow>Issue found in
|
||||
warning.config.condition.equals.missing_value1: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'value1' argument for 'equals' condition.</yellow>"
|
||||
warning.config.condition.equals.missing_value2: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'value2' argument for 'equals' condition.</yellow>"
|
||||
warning.config.condition.expression.missing_expression: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'expression' argument for 'expression' condition.</yellow>"
|
||||
warning.config.condition.is_null.missing_argument: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'argument' argument for 'is_null' condition.</yellow>"
|
||||
warning.config.condition.hand.missing_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'hand' argument for 'hand' condition.</yellow>"
|
||||
warning.config.condition.hand.invalid_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid 'hand' argument '<arg:2>' for 'hand' condition. Allowed hand types: [<arg:3>]</yellow>"
|
||||
warning.config.structure.not_section: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is expected to be a config section while it's actually a(n) '<arg:2>'.</yellow>"
|
||||
warning.config.image.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated image '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
warning.config.image.missing_height: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'height' argument.</yellow>"
|
||||
@@ -317,6 +320,10 @@ warning.config.function.message.missing_message: "<yellow>Issue found in file <a
|
||||
warning.config.function.open_window.missing_gui_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'gui-type' argument for 'open_window' function.</yellow>"
|
||||
warning.config.function.open_window.invalid_gui_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid gui type <arg:2> for 'open_window' function. Allowed types: [<arg:3>].</yellow>"
|
||||
warning.config.function.run.missing_functions: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'functions' argument for 'run' function.</yellow>"
|
||||
warning.config.function.place_block.missing_block_state: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'block-state' argument for 'place_block' function.</yellow>"
|
||||
warning.config.function.set_food.missing_food: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'food' argument for 'set_food' function.</yellow>"
|
||||
warning.config.function.set_saturation.missing_saturation: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'saturation' argument for 'set_saturation' function.</yellow>"
|
||||
warning.config.function.play_sound.missing_sound: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'sound' argument for 'play_sound' function.</yellow>"
|
||||
warning.config.selector.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for selector.</yellow>"
|
||||
warning.config.selector.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector type '<arg:2>'.</yellow>"
|
||||
warning.config.selector.invalid_target: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector target '<arg:2>'.</yellow>"
|
||||
|
||||
@@ -94,7 +94,10 @@ warning.config.condition.permission.missing_permission: "<yellow>在文件 <arg:
|
||||
warning.config.condition.equals.missing_value1: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'equals' 条件必需的 'value1' 参数</yellow>"
|
||||
warning.config.condition.equals.missing_value2: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'equals' 条件必需的 'value2' 参数</yellow>"
|
||||
warning.config.condition.expression.missing_expression: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'expression' 条件必需的 'expression' 参数</yellow>"
|
||||
warning.config.condition.is_null.missing_argument: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'is_null' 条件的必需的 'argument' 参数.</yellow>"
|
||||
warning.config.structure.not_section: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 应为配置段落 但实际类型为 '<arg:2>'</yellow>"
|
||||
warning.config.condition.hand.missing_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'hand' argument for 'hand' condition.</yellow>"
|
||||
warning.config.condition.hand.invalid_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid 'hand' argument '<arg:2>' for 'hand' condition. Allowed hand types: [<arg:3>]</yellow>"
|
||||
warning.config.image.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的图片配置 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
|
||||
warning.config.image.missing_height: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 缺少必需的 'height' 参数</yellow>"
|
||||
warning.config.image.height_ascent_conflict: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 违反位图规则: 'height' 参数 '<arg:2>' 必须不小于 'ascent' 参数 '<arg:3>'</yellow>"
|
||||
@@ -317,6 +320,10 @@ warning.config.function.message.missing_message: "<yellow>在文件 <arg:0> 中
|
||||
warning.config.function.open_window.missing_gui_type: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'open_window' 函数必需的 'gui-type' 参数</yellow>"
|
||||
warning.config.function.open_window.invalid_gui_type: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 为 'open_window' 函数使用了无效的 GUI 类型 <arg:2>. 允许的类型: [<arg:3>]。</yellow>"
|
||||
warning.config.function.run.missing_functions: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'run' 函数必需的 'functions' 参数</yellow>"
|
||||
warning.config.function.place_block.missing_block_state: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'place_block' 函数必需的 'block-state' 参数.</yellow>"
|
||||
warning.config.function.set_food.missing_food: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'food' argument for 'set_food' function.</yellow>"
|
||||
warning.config.function.set_saturation.missing_saturation: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'saturation' argument for 'set_saturation' function.</yellow>"
|
||||
warning.config.function.play_sound.missing_sound: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'sound' argument for 'play_sound' function.</yellow>"
|
||||
warning.config.selector.missing_type: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少选择器必需的 'type' 参数</yellow>"
|
||||
warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 使用了无效的选择器类型 '<arg:2>'</yellow>"
|
||||
warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>"
|
||||
|
||||
@@ -3,8 +3,11 @@ package net.momirealms.craftengine.bukkit.api;
|
||||
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
@@ -29,4 +32,8 @@ public final class BukkitAdaptors {
|
||||
public static BukkitBlockInWorld adapt(final Block block) {
|
||||
return new BukkitBlockInWorld(block);
|
||||
}
|
||||
|
||||
public static Location toLocation(WorldPosition position) {
|
||||
return LocationUtils.toLocation(position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package net.momirealms.craftengine.bukkit.api;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
|
||||
import net.momirealms.craftengine.bukkit.nms.CollisionEntity;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.entity.furniture.AnchorType;
|
||||
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.Furniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
@@ -48,7 +49,7 @@ public final class CraftEngineFurniture {
|
||||
* @return the loaded furniture
|
||||
*/
|
||||
@Nullable
|
||||
public static LoadedFurniture place(Location location, Key furnitureId) {
|
||||
public static Furniture place(Location location, Key furnitureId) {
|
||||
CustomFurniture furniture = byId(furnitureId);
|
||||
if (furniture == null) return null;
|
||||
return place(location, furnitureId, furniture.getAnyPlacement());
|
||||
@@ -63,7 +64,7 @@ public final class CraftEngineFurniture {
|
||||
* @return the loaded furniture
|
||||
*/
|
||||
@Nullable
|
||||
public static LoadedFurniture place(Location location, Key furnitureId, AnchorType anchorType) {
|
||||
public static Furniture place(Location location, Key furnitureId, AnchorType anchorType) {
|
||||
CustomFurniture furniture = byId(furnitureId);
|
||||
if (furniture == null) return null;
|
||||
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true);
|
||||
@@ -78,7 +79,7 @@ public final class CraftEngineFurniture {
|
||||
* @return the loaded furniture
|
||||
*/
|
||||
@NotNull
|
||||
public static LoadedFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType) {
|
||||
public static Furniture place(Location location, CustomFurniture furniture, AnchorType anchorType) {
|
||||
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), true);
|
||||
}
|
||||
|
||||
@@ -92,7 +93,7 @@ public final class CraftEngineFurniture {
|
||||
* @return the loaded furniture
|
||||
*/
|
||||
@Nullable
|
||||
public static LoadedFurniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) {
|
||||
public static Furniture place(Location location, Key furnitureId, AnchorType anchorType, boolean playSound) {
|
||||
CustomFurniture furniture = byId(furnitureId);
|
||||
if (furniture == null) return null;
|
||||
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound);
|
||||
@@ -108,7 +109,7 @@ public final class CraftEngineFurniture {
|
||||
* @return the loaded furniture
|
||||
*/
|
||||
@NotNull
|
||||
public static LoadedFurniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) {
|
||||
public static Furniture place(Location location, CustomFurniture furniture, AnchorType anchorType, boolean playSound) {
|
||||
return BukkitFurnitureManager.instance().place(location, furniture, FurnitureExtraData.builder().anchorType(anchorType).build(), playSound);
|
||||
}
|
||||
|
||||
@@ -152,7 +153,7 @@ public final class CraftEngineFurniture {
|
||||
* @return the loaded furniture
|
||||
*/
|
||||
@Nullable
|
||||
public static LoadedFurniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) {
|
||||
public static Furniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) {
|
||||
return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntity.getEntityId());
|
||||
}
|
||||
|
||||
@@ -163,7 +164,7 @@ public final class CraftEngineFurniture {
|
||||
* @return the loaded furniture
|
||||
*/
|
||||
@Nullable
|
||||
public static LoadedFurniture getLoadedFurnitureBySeat(@NotNull Entity seat) {
|
||||
public static Furniture getLoadedFurnitureBySeat(@NotNull Entity seat) {
|
||||
Integer baseEntityId = seat.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
if (baseEntityId == null) return null;
|
||||
return BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(baseEntityId);
|
||||
@@ -172,107 +173,108 @@ public final class CraftEngineFurniture {
|
||||
/**
|
||||
* Removes furniture
|
||||
*
|
||||
* @param furniture furniture base entity
|
||||
* @param entity furniture base entity
|
||||
* @return success or not
|
||||
*/
|
||||
public static boolean remove(@NotNull Entity furniture) {
|
||||
if (!isFurniture(furniture)) return false;
|
||||
LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId());
|
||||
if (loadedFurniture == null) return false;
|
||||
loadedFurniture.destroy();
|
||||
public static boolean remove(@NotNull Entity entity) {
|
||||
if (!isFurniture(entity)) return false;
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId());
|
||||
if (furniture == null) return false;
|
||||
furniture.destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes furniture, with more options
|
||||
*
|
||||
* @param furniture furniture base entity
|
||||
* @param entity furniture base entity
|
||||
* @param dropLoot whether to drop loots
|
||||
* @param playSound whether to play break sound
|
||||
* @return success or not
|
||||
*/
|
||||
public static boolean remove(@NotNull Entity furniture,
|
||||
public static boolean remove(@NotNull Entity entity,
|
||||
boolean dropLoot,
|
||||
boolean playSound) {
|
||||
if (!isFurniture(furniture)) return false;
|
||||
LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId());
|
||||
if (loadedFurniture == null) return false;
|
||||
remove(loadedFurniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound);
|
||||
if (!isFurniture(entity)) return false;
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId());
|
||||
if (furniture == null) return false;
|
||||
remove(furniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes furniture, with more options
|
||||
*
|
||||
* @param furniture furniture base entity
|
||||
* @param entity furniture base entity
|
||||
* @param player the player who removes the furniture
|
||||
* @param dropLoot whether to drop loots
|
||||
* @param playSound whether to play break sound
|
||||
* @return success or not
|
||||
*/
|
||||
public static boolean remove(@NotNull Entity furniture,
|
||||
public static boolean remove(@NotNull Entity entity,
|
||||
@Nullable Player player,
|
||||
boolean dropLoot,
|
||||
boolean playSound) {
|
||||
if (!isFurniture(furniture)) return false;
|
||||
LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(furniture.getEntityId());
|
||||
if (loadedFurniture == null) return false;
|
||||
remove(loadedFurniture, player, dropLoot, playSound);
|
||||
if (!isFurniture(entity)) return false;
|
||||
Furniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entity.getEntityId());
|
||||
if (furniture == null) return false;
|
||||
remove(furniture, player, dropLoot, playSound);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes furniture by providing furniture instance
|
||||
*
|
||||
* @param loadedFurniture loaded furniture
|
||||
* @param furniture loaded furniture
|
||||
* @param dropLoot whether to drop loots
|
||||
* @param playSound whether to play break sound
|
||||
*/
|
||||
public static void remove(@NotNull LoadedFurniture loadedFurniture,
|
||||
public static void remove(@NotNull Furniture furniture,
|
||||
boolean dropLoot,
|
||||
boolean playSound) {
|
||||
remove(loadedFurniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound);
|
||||
remove(furniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes furniture by providing furniture instance
|
||||
*
|
||||
* @param loadedFurniture loaded furniture
|
||||
* @param furniture loaded furniture
|
||||
* @param player the player who removes the furniture
|
||||
* @param dropLoot whether to drop loots
|
||||
* @param playSound whether to play break sound
|
||||
*/
|
||||
|
||||
public static void remove(@NotNull LoadedFurniture loadedFurniture,
|
||||
public static void remove(@NotNull Furniture furniture,
|
||||
@Nullable Player player,
|
||||
boolean dropLoot,
|
||||
boolean playSound) {
|
||||
remove(loadedFurniture, player == null ? null : BukkitCraftEngine.instance().adapt(player), dropLoot, playSound);
|
||||
remove(furniture, player == null ? null : BukkitCraftEngine.instance().adapt(player), dropLoot, playSound);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes furniture by providing furniture instance
|
||||
*
|
||||
* @param loadedFurniture loaded furniture
|
||||
* @param furniture loaded furniture
|
||||
* @param player the player who removes the furniture
|
||||
* @param dropLoot whether to drop loots
|
||||
* @param playSound whether to play break sound
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void remove(@NotNull LoadedFurniture loadedFurniture,
|
||||
public static void remove(@NotNull Furniture furniture,
|
||||
@Nullable net.momirealms.craftengine.core.entity.player.Player player,
|
||||
boolean dropLoot,
|
||||
boolean playSound) {
|
||||
Location location = loadedFurniture.dropLocation();
|
||||
loadedFurniture.destroy();
|
||||
LootTable<ItemStack> lootTable = (LootTable<ItemStack>) loadedFurniture.config().lootTable();
|
||||
if (!furniture.isValid()) return;
|
||||
Location location = ((BukkitFurniture) furniture).dropLocation();
|
||||
furniture.destroy();
|
||||
LootTable<ItemStack> lootTable = (LootTable<ItemStack>) furniture.config().lootTable();
|
||||
World world = new BukkitWorld(location.getWorld());
|
||||
WorldPosition position = new WorldPosition(world, location.getX(), location.getY(), location.getZ());
|
||||
if (dropLoot && lootTable != null) {
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position)
|
||||
.withParameter(DirectContextParameters.FURNITURE, loadedFurniture)
|
||||
.withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, loadedFurniture.extraData().item().orElse(null));
|
||||
.withParameter(DirectContextParameters.FURNITURE, furniture)
|
||||
.withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, furniture.extraData().item().orElse(null));
|
||||
if (player != null) {
|
||||
builder.withParameter(DirectContextParameters.PLAYER, player);
|
||||
}
|
||||
@@ -282,7 +284,7 @@ public final class CraftEngineFurniture {
|
||||
}
|
||||
}
|
||||
if (playSound) {
|
||||
world.playBlockSound(position, loadedFurniture.config().settings().sounds().breakSound());
|
||||
world.playBlockSound(position, furniture.config().settings().sounds().breakSound());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.api.event;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.Furniture;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
@@ -11,10 +12,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class FurnitureBreakEvent extends PlayerEvent implements Cancellable {
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
private boolean cancelled;
|
||||
private final LoadedFurniture furniture;
|
||||
private final BukkitFurniture furniture;
|
||||
|
||||
public FurnitureBreakEvent(@NotNull Player player,
|
||||
@NotNull LoadedFurniture furniture) {
|
||||
@NotNull BukkitFurniture furniture) {
|
||||
super(player);
|
||||
this.furniture = furniture;
|
||||
}
|
||||
@@ -25,7 +26,7 @@ public class FurnitureBreakEvent extends PlayerEvent implements Cancellable {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LoadedFurniture furniture() {
|
||||
public Furniture furniture() {
|
||||
return this.furniture;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.api.event;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.Furniture;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -12,12 +13,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class FurnitureInteractEvent extends PlayerEvent implements Cancellable {
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
private boolean cancelled;
|
||||
private final LoadedFurniture furniture;
|
||||
private final BukkitFurniture furniture;
|
||||
private final InteractionHand hand;
|
||||
private final Location interactionPoint;
|
||||
|
||||
public FurnitureInteractEvent(@NotNull Player player,
|
||||
@NotNull LoadedFurniture furniture,
|
||||
@NotNull BukkitFurniture furniture,
|
||||
@NotNull InteractionHand hand,
|
||||
@NotNull Location interactionPoint) {
|
||||
super(player);
|
||||
@@ -42,7 +43,7 @@ public class FurnitureInteractEvent extends PlayerEvent implements Cancellable {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LoadedFurniture furniture() {
|
||||
public Furniture furniture() {
|
||||
return this.furniture;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.api.event;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.Furniture;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -12,12 +13,12 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class FurniturePlaceEvent extends PlayerEvent implements Cancellable {
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
private final Location location;
|
||||
private final LoadedFurniture furniture;
|
||||
private final BukkitFurniture furniture;
|
||||
private final InteractionHand hand;
|
||||
private boolean cancelled;
|
||||
|
||||
public FurniturePlaceEvent(@NotNull Player player,
|
||||
@NotNull LoadedFurniture furniture,
|
||||
@NotNull BukkitFurniture furniture,
|
||||
@NotNull Location location,
|
||||
@NotNull InteractionHand hand) {
|
||||
super(player);
|
||||
@@ -32,7 +33,7 @@ public class FurniturePlaceEvent extends PlayerEvent implements Cancellable {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LoadedFurniture furniture() {
|
||||
public Furniture furniture() {
|
||||
return this.furniture;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ import net.momirealms.craftengine.core.loot.LootTable;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
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.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.util.Cancellable;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
|
||||
@@ -3,12 +3,10 @@ package net.momirealms.craftengine.bukkit.block;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
@@ -28,12 +26,8 @@ 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.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.plugin.event.EventFunctions;
|
||||
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||
@@ -45,10 +39,9 @@ import org.bukkit.Registry;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Path;
|
||||
@@ -58,50 +51,34 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
private static BukkitBlockManager instance;
|
||||
private final BukkitCraftEngine plugin;
|
||||
private final BlockParser blockParser;
|
||||
|
||||
// A temporary map used to detect whether the same block state corresponds to multiple models.
|
||||
private final Map<Integer, Key> tempRegistryIdConflictMap = new Int2ObjectOpenHashMap<>();
|
||||
// A temporary map that converts the custom block registered on the server to the vanilla block ID.
|
||||
private final Map<Integer, Integer> tempBlockAppearanceConvertor = new Int2IntOpenHashMap();
|
||||
// A temporary map that stores the model path of a certain vanilla block state
|
||||
private final Map<Integer, JsonElement> tempVanillaBlockStateModels = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// The total amount of blocks registered
|
||||
private int customBlockCount;
|
||||
protected final ImmutableBlockState[] stateId2ImmutableBlockStates;
|
||||
// Minecraft objects
|
||||
// Cached new blocks $ holders
|
||||
private ImmutableMap<Key, Integer> internalId2StateId;
|
||||
private ImmutableMap<Integer, Object> stateId2BlockHolder;
|
||||
private Map<Key, Integer> internalId2StateId;
|
||||
private Map<Integer, Object> stateId2BlockHolder;
|
||||
// This map is used to change the block states that are not necessarily needed into a certain block state
|
||||
private ImmutableMap<Integer, Integer> blockAppearanceMapper;
|
||||
private Map<Integer, Integer> blockAppearanceMapper;
|
||||
// Used to automatically arrange block states for strings such as minecraft:note_block:0
|
||||
private ImmutableMap<Key, List<Integer>> blockAppearanceArranger;
|
||||
private ImmutableMap<Key, List<Integer>> realBlockArranger;
|
||||
private Map<Key, List<Integer>> blockAppearanceArranger;
|
||||
private Map<Key, List<Integer>> realBlockArranger;
|
||||
// Record the amount of real blocks by block type
|
||||
private LinkedHashMap<Key, Integer> registeredRealBlockSlots;
|
||||
private Map<Key, Integer> registeredRealBlockSlots;
|
||||
// A set of blocks that sounds have been removed
|
||||
private ImmutableSet<Object> affectedSoundBlocks;
|
||||
private ImmutableMap<Key, Key> soundMapper;
|
||||
private Set<Object> affectedSoundBlocks;
|
||||
private Map<Key, Key> soundMapper;
|
||||
// A list to record the order of registration
|
||||
private List<Key> blockRegisterOrder = new ObjectArrayList<>();
|
||||
|
||||
// a reverted mapper
|
||||
private final Map<Integer, List<Integer>> appearanceToRealState = new Int2ObjectOpenHashMap<>();
|
||||
// Used to store override information of json files
|
||||
private final Map<Key, Map<String, JsonElement>> blockStateOverrides = new HashMap<>();
|
||||
// for mod, real block id -> state models
|
||||
private final Map<Key, JsonElement> modBlockStates = new HashMap<>();
|
||||
// Event listeners
|
||||
private final BlockEventListener blockEventListener;
|
||||
private final FallingBlockRemoveListener fallingBlockRemoveListener;
|
||||
|
||||
private Map<Integer, List<String>> clientBoundTags = Map.of();
|
||||
private Map<Integer, List<String>> previousTags = Map.of();
|
||||
// cached tag packet
|
||||
protected Object cachedUpdateTagsPacket;
|
||||
|
||||
public BukkitBlockManager(BukkitCraftEngine plugin) {
|
||||
super(plugin);
|
||||
instance = this;
|
||||
this.plugin = plugin;
|
||||
this.blockParser = new BlockParser();
|
||||
this.initVanillaRegistry();
|
||||
@@ -120,42 +97,33 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
if (enableNoteBlocks) {
|
||||
this.recordVanillaNoteBlocks();
|
||||
}
|
||||
if (VersionHelper.isOrAbove1_20_3()) {
|
||||
this.fallingBlockRemoveListener = new FallingBlockRemoveListener();
|
||||
} else this.fallingBlockRemoveListener = null;
|
||||
this.stateId2ImmutableBlockStates = new ImmutableBlockState[customBlockCount];
|
||||
this.fallingBlockRemoveListener = VersionHelper.isOrAbove1_20_3() ? new FallingBlockRemoveListener() : null;
|
||||
this.stateId2ImmutableBlockStates = new ImmutableBlockState[this.customBlockCount];
|
||||
Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.INSTANCE.defaultState());
|
||||
instance = this;
|
||||
this.resetPacketConsumers();
|
||||
}
|
||||
|
||||
public List<Key> blockRegisterOrder() {
|
||||
return Collections.unmodifiableList(this.blockRegisterOrder);
|
||||
}
|
||||
|
||||
public static BukkitBlockManager instance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public List<Key> blockRegisterOrder() {
|
||||
return Collections.unmodifiableList(this.blockRegisterOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delayedInit() {
|
||||
Bukkit.getPluginManager().registerEvents(this.blockEventListener, plugin.bootstrap());
|
||||
Bukkit.getPluginManager().registerEvents(this.blockEventListener, this.plugin.bootstrap());
|
||||
if (this.fallingBlockRemoveListener != null) {
|
||||
Bukkit.getPluginManager().registerEvents(this.fallingBlockRemoveListener, plugin.bootstrap());
|
||||
Bukkit.getPluginManager().registerEvents(this.fallingBlockRemoveListener, this.plugin.bootstrap());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
super.unload();
|
||||
this.clearCache();
|
||||
this.appearanceToRealState.clear();
|
||||
this.blockStateOverrides.clear();
|
||||
this.modBlockStates.clear();
|
||||
if (EmptyBlock.STATE != null)
|
||||
Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.STATE);
|
||||
this.previousTags = this.clientBoundTags;
|
||||
this.clientBoundTags = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,15 +140,14 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
@Override
|
||||
public void delayedLoad() {
|
||||
initSuggestions();
|
||||
resetPacketConsumers();
|
||||
clearCache();
|
||||
resendTags();
|
||||
this.resetPacketConsumers();
|
||||
super.delayedLoad();
|
||||
}
|
||||
|
||||
private void resendTags() {
|
||||
@Override
|
||||
protected void resendTags() {
|
||||
// if there's no change
|
||||
if (this.clientBoundTags.equals(this.previousTags)) return;
|
||||
if (this.clientBoundTags.equals(this.previousClientBoundTags)) return;
|
||||
List<TagUtils.TagEntry> list = new ArrayList<>();
|
||||
for (Map.Entry<Integer, List<String>> entry : this.clientBoundTags.entrySet()) {
|
||||
list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue()));
|
||||
@@ -197,10 +164,19 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCache() {
|
||||
this.tempRegistryIdConflictMap.clear();
|
||||
this.tempBlockAppearanceConvertor.clear();
|
||||
this.tempVanillaBlockStateModels.clear();
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockStateWrapper createPackedBlockState(String blockState) {
|
||||
ImmutableBlockState state = BlockStateParser.deserialize(blockState);
|
||||
if (state != null) {
|
||||
return state.customBlockState();
|
||||
}
|
||||
try {
|
||||
BlockData blockData = Bukkit.createBlockData(blockState);
|
||||
return BlockStateUtils.toPackedBlockState(blockData);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -209,11 +185,13 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ImmutableBlockState getImmutableBlockStateUnsafe(int stateId) {
|
||||
return this.stateId2ImmutableBlockStates[stateId - BlockStateUtils.vanillaStateSize()];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ImmutableBlockState getImmutableBlockState(int stateId) {
|
||||
if (!BlockStateUtils.isVanillaBlock(stateId)) {
|
||||
return this.stateId2ImmutableBlockStates[stateId - BlockStateUtils.vanillaStateSize()];
|
||||
@@ -221,41 +199,53 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, JsonElement> modBlockStates() {
|
||||
return Collections.unmodifiableMap(this.modBlockStates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigParser parser() {
|
||||
return this.blockParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, Map<String, JsonElement>> blockOverrides() {
|
||||
return Collections.unmodifiableMap(this.blockStateOverrides);
|
||||
public void addBlock(Key id, CustomBlock customBlock) {
|
||||
// bind appearance and real state
|
||||
for (ImmutableBlockState state : customBlock.variantProvider().states()) {
|
||||
ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()];
|
||||
if (previous != null && !previous.isEmpty()) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.bind_failed", state.toString(), previous.toString());
|
||||
}
|
||||
this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state;
|
||||
this.tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId());
|
||||
this.appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new IntArrayList()).add(state.customBlockState().registryId());
|
||||
}
|
||||
super.addBlock(id, customBlock);
|
||||
}
|
||||
|
||||
public ImmutableMap<Key, List<Integer>> blockAppearanceArranger() {
|
||||
@Override
|
||||
public Key getBlockOwnerId(BlockStateWrapper state) {
|
||||
return BlockStateUtils.getBlockOwnerIdFromState(state.handle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableAppearances(Key blockType) {
|
||||
return Optional.ofNullable(this.registeredRealBlockSlots.get(blockType)).orElse(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<Key, List<Integer>> blockAppearanceArranger() {
|
||||
return this.blockAppearanceArranger;
|
||||
}
|
||||
|
||||
public ImmutableMap<Key, List<Integer>> realBlockArranger() {
|
||||
@NotNull
|
||||
public Map<Key, List<Integer>> realBlockArranger() {
|
||||
return this.realBlockArranger;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Integer> appearanceToRealStates(int appearanceStateId) {
|
||||
return this.appearanceToRealState.get(appearanceStateId);
|
||||
}
|
||||
|
||||
private void initMirrorRegistry() {
|
||||
int size = RegistryUtils.currentBlockRegistrySize();
|
||||
PackedBlockState[] states = new PackedBlockState[size];
|
||||
BlockStateWrapper[] states = new BlockStateWrapper[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
states[i] = new PackedBlockState(BlockStateUtils.idToBlockState(i), i);
|
||||
states[i] = BlockStateWrapper.create(BlockStateUtils.idToBlockState(i), i, BlockStateUtils.isVanillaBlock(i));
|
||||
}
|
||||
BlockRegistryMirror.init(states, new PackedBlockState(Reflections.instance$Blocks$STONE$defaultState, BlockStateUtils.blockStateToId(Reflections.instance$Blocks$STONE$defaultState)));
|
||||
BlockRegistryMirror.init(states, BlockStateWrapper.vanilla(Reflections.instance$Blocks$STONE$defaultState, BlockStateUtils.blockStateToId(Reflections.instance$Blocks$STONE$defaultState)));
|
||||
}
|
||||
|
||||
private void registerEmptyBlock() {
|
||||
@@ -276,25 +266,25 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
private void initVanillaRegistry() {
|
||||
int vanillaStateCount;
|
||||
if (plugin.hasMod()) {
|
||||
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();
|
||||
plugin.logger().severe("Fatal error", e);
|
||||
this.plugin.logger().severe("Fatal error", e);
|
||||
}
|
||||
} else {
|
||||
vanillaStateCount = RegistryUtils.currentBlockRegistrySize();
|
||||
}
|
||||
plugin.logger().info("Vanilla block count: " + vanillaStateCount);
|
||||
this.plugin.logger().info("Vanilla block count: " + vanillaStateCount);
|
||||
BlockStateUtils.init(vanillaStateCount);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerBlocks() {
|
||||
plugin.logger().info("Registering blocks. Please wait...");
|
||||
this.plugin.logger().info("Registering blocks. Please wait...");
|
||||
try {
|
||||
ImmutableMap.Builder<Key, Integer> builder1 = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<Integer, Object> builder2 = ImmutableMap.builder();
|
||||
@@ -367,7 +357,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
parseVanillaBlock(pack, path, id, section);
|
||||
} else {
|
||||
// check duplicated config
|
||||
if (byId.containsKey(id)) {
|
||||
if (BukkitBlockManager.this.byId.containsKey(id)) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.duplicate");
|
||||
}
|
||||
parseCustomBlock(pack, path, id, section);
|
||||
@@ -376,128 +366,73 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
private void parseCustomBlock(Pack pack, Path path, Key id, Map<String, Object> section) {
|
||||
// read block settings
|
||||
BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false));
|
||||
|
||||
// read loot table
|
||||
LootTable<ItemStack> lootTable = LootTable.fromMap(MiscUtils.castToMap(section.getOrDefault("loot", Map.of()), false));
|
||||
|
||||
BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.get("settings"), true));
|
||||
// read states
|
||||
Map<String, Property<?>> properties;
|
||||
Map<String, Integer> appearances;
|
||||
Map<String, VariantState> variants;
|
||||
Object stateObj = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state");
|
||||
Map<String, Object> stateSection = MiscUtils.castToMap(stateObj, true);
|
||||
|
||||
Map<String, Object> stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true);
|
||||
boolean singleState = !stateSection.containsKey("properties");
|
||||
// single state
|
||||
if (!stateSection.containsKey("properties")) {
|
||||
if (singleState) {
|
||||
properties = Map.of();
|
||||
int internalId = ResourceConfigUtils.getAsInt(stateSection.getOrDefault("id", -1), "id");
|
||||
if (internalId < 0) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.missing_real_id");
|
||||
}
|
||||
|
||||
Pair<Key, Integer> pair = parseAppearanceSection(id, stateSection);
|
||||
if (pair == null) return;
|
||||
|
||||
appearances = Map.of("default", pair.right());
|
||||
String internalBlock = pair.left().value() + "_" + internalId;
|
||||
Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, internalBlock);
|
||||
int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id");
|
||||
VanillaBlockState vanillaBlock = getVanillaBlock(id, stateSection);
|
||||
appearances = Map.of("", vanillaBlock.registryId());
|
||||
Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, vanillaBlock.type().value() + "_" + internalId);
|
||||
int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1);
|
||||
if (internalBlockRegistryId == -1) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id",
|
||||
internalBlock,
|
||||
String.valueOf(registeredRealBlockSlots.get(pair.left()) - 1));
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(vanillaBlock.type()) - 1));
|
||||
}
|
||||
variants = Map.of("", new VariantState("default", settings, internalBlockRegistryId));
|
||||
variants = Map.of("", new VariantState("", settings, internalBlockRegistryId));
|
||||
} else {
|
||||
// properties
|
||||
Map<String, Object> propertySection = MiscUtils.castToMap(stateSection.get("properties"), true);
|
||||
if (propertySection == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.missing_properties");
|
||||
}
|
||||
properties = parseProperties(propertySection);
|
||||
properties = getProperties(MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), true));
|
||||
// appearance
|
||||
Map<String, Object> appearancesSection = MiscUtils.castToMap(stateSection.get("appearances"), true);
|
||||
if (appearancesSection == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.missing_appearances");
|
||||
}
|
||||
appearances = new HashMap<>();
|
||||
Map<String, Key> tempTypeMap = new HashMap<>();
|
||||
for (Map.Entry<String, Object> appearanceEntry : appearancesSection.entrySet()) {
|
||||
if (appearanceEntry.getValue() instanceof Map<?, ?> appearanceSection) {
|
||||
Pair<Key, Integer> pair = parseAppearanceSection(id, MiscUtils.castToMap(appearanceSection, false));
|
||||
if (pair == null) return;
|
||||
appearances.put(appearanceEntry.getKey(), pair.right());
|
||||
tempTypeMap.put(appearanceEntry.getKey(), pair.left());
|
||||
Map<String, Key> appearance2BlockType = new HashMap<>();
|
||||
for (Map.Entry<String, Object> appearanceEntry : MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), false).entrySet()) {
|
||||
if (appearanceEntry.getValue() instanceof Map<?, ?>) {
|
||||
VanillaBlockState vanillaBlock = getVanillaBlock(id, MiscUtils.castToMap(appearanceEntry.getValue(), false));
|
||||
appearances.put(appearanceEntry.getKey(), vanillaBlock.registryId());
|
||||
appearance2BlockType.put(appearanceEntry.getKey(), vanillaBlock.type());
|
||||
}
|
||||
}
|
||||
// variants
|
||||
Map<String, Object> variantsSection = MiscUtils.castToMap(stateSection.get("variants"), true);
|
||||
if (variantsSection == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.missing_variants");
|
||||
}
|
||||
variants = new HashMap<>();
|
||||
for (Map.Entry<String, Object> variantEntry : variantsSection.entrySet()) {
|
||||
if (variantEntry.getValue() instanceof Map<?, ?> variantSection0) {
|
||||
Map<String, Object> variantSection = MiscUtils.castToMap(variantSection0, false);
|
||||
String variantName = variantEntry.getKey();
|
||||
String appearance = (String) variantSection.get("appearance");
|
||||
if (appearance == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.variant.missing_appearance", variantName);
|
||||
}
|
||||
for (Map.Entry<String, Object> variantEntry : MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), false).entrySet()) {
|
||||
if (variantEntry.getValue() instanceof Map<?, ?>) {
|
||||
Map<String, Object> variantSection = MiscUtils.castToMap(variantEntry.getValue(), false);
|
||||
String variantNBT = variantEntry.getKey();
|
||||
String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance");
|
||||
if (!appearances.containsKey(appearance)) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantName, appearance);
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance);
|
||||
}
|
||||
int internalId = ResourceConfigUtils.getAsInt(variantSection.getOrDefault("id", -1), "id");
|
||||
Key baseBlock = tempTypeMap.get(appearance);
|
||||
int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id");
|
||||
Key baseBlock = appearance2BlockType.get(appearance);
|
||||
Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, baseBlock.value() + "_" + internalId);
|
||||
int internalBlockRegistryId = Optional.ofNullable(internalId2StateId.get(internalBlockId)).orElse(-1);
|
||||
if (internalBlockRegistryId == -1) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id",
|
||||
internalBlockId.toString(),
|
||||
String.valueOf(registeredRealBlockSlots.getOrDefault(baseBlock, 1) - 1));
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(baseBlock) - 1));
|
||||
}
|
||||
Map<String, Object> anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true);
|
||||
variants.put(variantName, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId));
|
||||
variants.put(variantNBT, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object eventsObj = ResourceConfigUtils.get(section, "events", "event");
|
||||
EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events = EventFunctions.parseEvents(eventsObj);
|
||||
|
||||
Map<String, Object> behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false);
|
||||
CustomBlock block = BukkitCustomBlock.builder(id)
|
||||
.appearances(appearances)
|
||||
.variantMapper(variants)
|
||||
.lootTable(lootTable)
|
||||
.properties(properties)
|
||||
.settings(settings)
|
||||
.behavior(behaviors)
|
||||
.events(events)
|
||||
.lootTable(LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), true)))
|
||||
.behavior(MiscUtils.castToMap(section.get("behavior"), true))
|
||||
.events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")))
|
||||
.build();
|
||||
|
||||
// bind appearance and real state
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
ImmutableBlockState previous = stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()];
|
||||
if (previous != null && !previous.isEmpty()) {
|
||||
TranslationManager.instance().log("warning.config.block.state.bind_failed", path.toString(), id.toString(), state.toString(), previous.toString());
|
||||
continue;
|
||||
}
|
||||
stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state;
|
||||
tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId());
|
||||
appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new IntArrayList()).add(state.customBlockState().registryId());
|
||||
}
|
||||
|
||||
BukkitBlockManager.this.byId.put(id, block);
|
||||
|
||||
// generate mod assets
|
||||
if (Config.generateModAssets()) {
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
Key realBlockId = BlockStateUtils.getBlockOwnerIdFromState(state.customBlockState());
|
||||
modBlockStates.put(realBlockId, tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId()));
|
||||
}
|
||||
}
|
||||
addBlock(id, block);
|
||||
}
|
||||
|
||||
private void parseVanillaBlock(Pack pack, Path path, Key id, Map<String, Object> section) {
|
||||
@@ -518,7 +453,8 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Property<?>> parseProperties(Map<String, Object> propertiesSection) {
|
||||
@NotNull
|
||||
private Map<String, Property<?>> getProperties(Map<String, Object> propertiesSection) {
|
||||
Map<String, Property<?>> properties = new HashMap<>();
|
||||
for (Map.Entry<String, Object> entry : propertiesSection.entrySet()) {
|
||||
Property<?> property = Properties.fromMap(entry.getKey(), MiscUtils.castToMap(entry.getValue(), false));
|
||||
@@ -527,69 +463,40 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<Key, Integer> parseAppearanceSection(Key id, Map<String, Object> section) {
|
||||
@NotNull
|
||||
private VanillaBlockState getVanillaBlock(Key id, Map<String, Object> section) {
|
||||
// require state non null
|
||||
Object vanillaStateString = section.get("state");
|
||||
if (vanillaStateString == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.missing_state");
|
||||
}
|
||||
|
||||
String vanillaBlockStateTag = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("state"), "warning.config.block.state.missing_state");
|
||||
// get its registry id
|
||||
int vanillaStateRegistryId = parseVanillaStateRegistryId(vanillaStateString.toString());
|
||||
|
||||
// check conflict
|
||||
Key ifAny = this.tempRegistryIdConflictMap.get(vanillaStateRegistryId);
|
||||
int vanillaBlockStateRegistryId = getVanillaBlockStateRegistryId(vanillaBlockStateTag);
|
||||
// check if another block has occupied the appearance
|
||||
// TODO blocks share the same look
|
||||
Key ifAny = this.tempRegistryIdConflictMap.get(vanillaBlockStateRegistryId);
|
||||
if (ifAny != null && !ifAny.equals(id)) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.conflict", BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(vanillaStateRegistryId)).getAsString(), ifAny.toString());
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.conflict", BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(vanillaBlockStateRegistryId)).getAsString(), ifAny.toString());
|
||||
}
|
||||
|
||||
// require models not to be null
|
||||
Object models = section.get("models");
|
||||
if (models == null) {
|
||||
models = section.get("model");
|
||||
}
|
||||
if (models == null) {
|
||||
Object models = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "models", "model"), "warning.config.block.state.missing_model");
|
||||
List<JsonObject> variants = ResourceConfigUtils.parseConfigAsList(models, this::getVariantModel);
|
||||
if (variants.isEmpty()) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.missing_model");
|
||||
}
|
||||
|
||||
List<JsonObject> variants = new ArrayList<>();
|
||||
if (models instanceof Map<?, ?> singleModelSection) {
|
||||
loadVariantModel(variants, MiscUtils.castToMap(singleModelSection, false));
|
||||
} else if (models instanceof List<?> modelList) {
|
||||
for (Object model : modelList) {
|
||||
if (model instanceof Map<?,?> singleModelMap) {
|
||||
loadVariantModel(variants, MiscUtils.castToMap(singleModelMap, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (variants.isEmpty()) return null;
|
||||
|
||||
this.tempRegistryIdConflictMap.put(vanillaStateRegistryId, id);
|
||||
String blockState = BlockStateUtils.idToBlockState(vanillaStateRegistryId).toString();
|
||||
Key block = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}')));
|
||||
String propertyData = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']'));
|
||||
Map<String, JsonElement> paths = this.blockStateOverrides.computeIfAbsent(block, k -> new HashMap<>());
|
||||
if (variants.size() == 1) {
|
||||
paths.put(propertyData, variants.get(0));
|
||||
this.tempVanillaBlockStateModels.put(vanillaStateRegistryId, variants.get(0));
|
||||
} else {
|
||||
JsonArray array = new JsonArray();
|
||||
for (JsonObject object : variants) {
|
||||
array.add(object);
|
||||
}
|
||||
paths.put(propertyData, array);
|
||||
this.tempVanillaBlockStateModels.put(vanillaStateRegistryId, array);
|
||||
}
|
||||
return Pair.of(block, vanillaStateRegistryId);
|
||||
// TODO blocks share the same look
|
||||
this.tempRegistryIdConflictMap.put(vanillaBlockStateRegistryId, id);
|
||||
// gets the full block state
|
||||
String blockState = BlockStateUtils.idToBlockState(vanillaBlockStateRegistryId).toString();
|
||||
Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}')));
|
||||
String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']'));
|
||||
// for generating assets
|
||||
JsonElement combinedVariant = GsonHelper.combine(variants);
|
||||
this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()).put(propertyNBT, combinedVariant);
|
||||
this.tempVanillaBlockStateModels.put(vanillaBlockStateRegistryId, combinedVariant);
|
||||
return new VanillaBlockState(blockId, propertyNBT, vanillaBlockStateRegistryId);
|
||||
}
|
||||
|
||||
private void loadVariantModel(List<JsonObject> variants, Map<String, Object> singleModelMap) {
|
||||
private JsonObject getVariantModel(Map<String, Object> singleModelMap) {
|
||||
JsonObject json = new JsonObject();
|
||||
String modelPath = (String) singleModelMap.get("path");
|
||||
if (modelPath == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.model.missing_path");
|
||||
}
|
||||
String modelPath = ResourceConfigUtils.requireNonEmptyStringOrThrow(singleModelMap.get("path"), "warning.config.block.state.model.missing_path");
|
||||
if (!ResourceLocation.isValid(modelPath)) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.model.invalid_path", modelPath);
|
||||
}
|
||||
@@ -602,10 +509,10 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
if (generationMap != null) {
|
||||
prepareModelGeneration(ModelGeneration.of(Key.of(modelPath), generationMap));
|
||||
}
|
||||
variants.add(json);
|
||||
return json;
|
||||
}
|
||||
|
||||
private int parseVanillaStateRegistryId(String blockState) {
|
||||
private int getVanillaBlockStateRegistryId(String blockState) {
|
||||
String[] split = blockState.split(":", 3);
|
||||
if (split.length >= 4) {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState);
|
||||
|
||||
@@ -10,8 +10,8 @@ import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||
@@ -26,18 +26,21 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class BukkitCustomBlock extends CustomBlock {
|
||||
public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
|
||||
protected BukkitCustomBlock(
|
||||
Key id,
|
||||
Holder.Reference<CustomBlock> holder,
|
||||
Map<String, Property<?>> properties,
|
||||
Map<String, Integer> appearances,
|
||||
Map<String, VariantState> variantMapper,
|
||||
BlockSettings settings,
|
||||
@NotNull EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events,
|
||||
@NotNull Key id,
|
||||
@NotNull Holder.Reference<CustomBlock> holder,
|
||||
@NotNull Map<String, Property<?>> properties,
|
||||
@NotNull Map<String, Integer> appearances,
|
||||
@NotNull Map<String, VariantState> variantMapper,
|
||||
@NotNull BlockSettings settings,
|
||||
@NotNull Map<EventTrigger, List<Function<PlayerOptionalContext>>> events,
|
||||
@Nullable Map<String, Object> behavior,
|
||||
@Nullable LootTable<?> lootTable
|
||||
) {
|
||||
@@ -147,17 +150,67 @@ public class BukkitCustomBlock extends CustomBlock {
|
||||
}
|
||||
|
||||
public static Builder builder(Key id) {
|
||||
return new Builder(id);
|
||||
return new BuilderImpl(id);
|
||||
}
|
||||
|
||||
public static class Builder extends CustomBlock.Builder {
|
||||
public static class BuilderImpl implements Builder {
|
||||
protected final Key id;
|
||||
protected Map<String, Property<?>> properties;
|
||||
protected Map<String, Integer> appearances;
|
||||
protected Map<String, VariantState> variantMapper;
|
||||
protected BlockSettings settings;
|
||||
protected Map<String, Object> behavior;
|
||||
protected LootTable<?> lootTable;
|
||||
protected Map<EventTrigger, List<Function<PlayerOptionalContext>>> events;
|
||||
|
||||
protected Builder(Key id) {
|
||||
super(id);
|
||||
public BuilderImpl(Key id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomBlock build() {
|
||||
public Builder events(Map<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||
this.events = events;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder appearances(Map<String, Integer> appearances) {
|
||||
this.appearances = appearances;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder behavior(Map<String, Object> behavior) {
|
||||
this.behavior = behavior;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder lootTable(LootTable<?> lootTable) {
|
||||
this.lootTable = lootTable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder properties(Map<String, Property<?>> properties) {
|
||||
this.properties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder settings(BlockSettings settings) {
|
||||
this.settings = settings;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder variantMapper(Map<String, VariantState> variantMapper) {
|
||||
this.variantMapper = variantMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CustomBlock build() {
|
||||
// create or get block holder
|
||||
Holder.Reference<CustomBlock> holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() ->
|
||||
((WritableRegistry<CustomBlock>) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id)));
|
||||
|
||||
@@ -42,12 +42,12 @@ public class BukkitEntity extends AbstractEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXRot() {
|
||||
public float xRot() {
|
||||
return literalObject().getYaw();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getYRot() {
|
||||
public float yRot() {
|
||||
return literalObject().getPitch();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package net.momirealms.craftengine.bukkit.entity.furniture;
|
||||
|
||||
import net.momirealms.craftengine.core.entity.furniture.AbstractCustomFurniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.AnchorType;
|
||||
import net.momirealms.craftengine.core.entity.furniture.CustomFurniture;
|
||||
import net.momirealms.craftengine.core.entity.furniture.FurnitureSettings;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BukkitCustomFurniture extends AbstractCustomFurniture {
|
||||
|
||||
protected BukkitCustomFurniture(@NotNull Key id,
|
||||
@NotNull FurnitureSettings settings,
|
||||
@NotNull Map<AnchorType, Placement> placements,
|
||||
@NotNull Map<EventTrigger, List<Function<PlayerOptionalContext>>> events,
|
||||
@Nullable LootTable<?> lootTable) {
|
||||
super(id, settings, placements, events, lootTable);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new BuilderImpl();
|
||||
}
|
||||
|
||||
public static class BuilderImpl implements Builder {
|
||||
private Key id;
|
||||
private Map<AnchorType, Placement> placements;
|
||||
private FurnitureSettings settings;
|
||||
private Map<EventTrigger, List<Function<PlayerOptionalContext>>> events;
|
||||
private LootTable<?> lootTable;
|
||||
|
||||
@Override
|
||||
public CustomFurniture build() {
|
||||
return new BukkitCustomFurniture(id, settings, placements, events, lootTable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder id(Key id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder placement(Map<AnchorType, Placement> placements) {
|
||||
this.placements = placements;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder settings(FurnitureSettings settings) {
|
||||
this.settings = settings;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder lootTable(LootTable<?> lootTable) {
|
||||
this.lootTable = lootTable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder events(Map<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||
this.events = events;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
package net.momirealms.craftengine.bukkit.entity.furniture;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import net.momirealms.craftengine.bukkit.entity.BukkitEntity;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.util.EntityUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LegacyAttributeUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.ArrayUtils;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.QuaternionUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||
import org.bukkit.Location;
|
||||
@@ -29,7 +29,7 @@ import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
|
||||
public class LoadedFurniture implements Furniture {
|
||||
public class BukkitFurniture implements Furniture {
|
||||
private final Key id;
|
||||
private final CustomFurniture furniture;
|
||||
private final AnchorType anchorType;
|
||||
@@ -44,8 +44,8 @@ public class LoadedFurniture implements Furniture {
|
||||
// cache
|
||||
private final List<Integer> fakeEntityIds;
|
||||
private final List<Integer> entityIds;
|
||||
private final Map<Integer, HitBox> hitBoxes = new HashMap<>();
|
||||
private final Map<Integer, AABB> aabb = new HashMap<>();
|
||||
private final Map<Integer, HitBox> hitBoxes = new Int2ObjectArrayMap<>();
|
||||
private final Map<Integer, AABB> aabb = new Int2ObjectArrayMap<>();
|
||||
private final boolean minimized;
|
||||
private final boolean hasExternalModel;
|
||||
// seats
|
||||
@@ -55,7 +55,7 @@ public class LoadedFurniture implements Furniture {
|
||||
private Object cachedSpawnPacket;
|
||||
private Object cachedMinimizedSpawnPacket;
|
||||
|
||||
public LoadedFurniture(Entity baseEntity,
|
||||
public BukkitFurniture(Entity baseEntity,
|
||||
CustomFurniture furniture,
|
||||
FurnitureExtraData extraData) {
|
||||
this.id = furniture.id();
|
||||
@@ -66,8 +66,8 @@ public class LoadedFurniture implements Furniture {
|
||||
this.baseEntity = new WeakReference<>(baseEntity);
|
||||
this.furniture = furniture;
|
||||
this.minimized = furniture.settings().minimized();
|
||||
List<Integer> fakeEntityIds = new ArrayList<>();
|
||||
List<Integer> mainEntityIds = new ArrayList<>();
|
||||
List<Integer> fakeEntityIds = new IntArrayList();
|
||||
List<Integer> mainEntityIds = new IntArrayList();
|
||||
mainEntityIds.add(this.baseEntityId);
|
||||
|
||||
CustomFurniture.Placement placement = furniture.getPlacement(anchorType);
|
||||
@@ -84,19 +84,11 @@ public class LoadedFurniture implements Furniture {
|
||||
this.hasExternalModel = false;
|
||||
}
|
||||
|
||||
float yaw = this.location.getYaw();
|
||||
Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - yaw), 0).conjugate();
|
||||
|
||||
double x = location.getX();
|
||||
double y = location.getY();
|
||||
double z = location.getZ();
|
||||
|
||||
Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate();
|
||||
List<Object> packets = new ArrayList<>();
|
||||
List<Object> minimizedPackets = new ArrayList<>();
|
||||
List<Collider> colliders = new ArrayList<>();
|
||||
|
||||
World world = world();
|
||||
WorldPosition position = new WorldPosition(world, x, y, z, yaw, 0);
|
||||
WorldPosition position = position();
|
||||
Integer dyedColor = this.extraData.dyedColor().orElse(null);
|
||||
for (FurnitureElement element : placement.elements()) {
|
||||
int entityId = Reflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||
@@ -154,13 +146,8 @@ public class LoadedFurniture implements Furniture {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d position() {
|
||||
return new Vec3d(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public World world() {
|
||||
return new BukkitWorld(this.location.getWorld());
|
||||
public WorldPosition position() {
|
||||
return LocationUtils.toWorldPosition(this.location);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -170,7 +157,7 @@ public class LoadedFurniture implements Furniture {
|
||||
|
||||
@NotNull
|
||||
public Entity baseEntity() {
|
||||
Entity entity = baseEntity.get();
|
||||
Entity entity = this.baseEntity.get();
|
||||
if (entity == null) {
|
||||
throw new RuntimeException("Base entity not found. It might be unloaded.");
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||
import net.momirealms.craftengine.core.entity.Billboard;
|
||||
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
|
||||
import net.momirealms.craftengine.core.entity.furniture.AbstractFurnitureElement;
|
||||
import net.momirealms.craftengine.core.entity.furniture.FurnitureElement;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
@@ -30,10 +31,10 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement {
|
||||
ItemDisplayContext transform,
|
||||
Vector3f scale,
|
||||
Vector3f translation,
|
||||
Vector3f offset,
|
||||
Vector3f position,
|
||||
Quaternionf rotation,
|
||||
boolean applyDyedColor) {
|
||||
super(item, billboard, transform, scale, translation, offset, rotation, applyDyedColor);
|
||||
super(item, billboard, transform, scale, translation, position, rotation, applyDyedColor);
|
||||
this.commonValues = new ArrayList<>();
|
||||
ItemDisplayEntityData.Scale.addEntityDataIfNotDefaultValue(scale(), this.commonValues);
|
||||
ItemDisplayEntityData.RotationLeft.addEntityDataIfNotDefaultValue(rotation(), this.commonValues);
|
||||
@@ -67,4 +68,72 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement {
|
||||
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(item.getLiteralObject(), cachedValues);
|
||||
return cachedValues;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new BuilderImpl();
|
||||
}
|
||||
|
||||
public static class BuilderImpl implements Builder {
|
||||
private boolean applyDyedColor;
|
||||
private Key item;
|
||||
private Billboard billboard;
|
||||
private ItemDisplayContext transform;
|
||||
private Vector3f scale;
|
||||
private Vector3f translation;
|
||||
private Vector3f position;
|
||||
private Quaternionf rotation;
|
||||
|
||||
@Override
|
||||
public Builder applyDyedColor(boolean applyDyedColor) {
|
||||
this.applyDyedColor = applyDyedColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder item(Key item) {
|
||||
this.item = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder billboard(Billboard billboard) {
|
||||
this.billboard = billboard;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder transform(ItemDisplayContext transform) {
|
||||
this.transform = transform;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder scale(Vector3f scale) {
|
||||
this.scale = scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder translation(Vector3f translation) {
|
||||
this.translation = translation;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder position(Vector3f position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder rotation(Quaternionf rotation) {
|
||||
this.rotation = rotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FurnitureElement build() {
|
||||
return new BukkitFurnitureElement(item, billboard, transform, scale, translation, position, rotation, applyDyedColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,58 +6,45 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.handler.FurniturePacketHandler;
|
||||
import net.momirealms.craftengine.bukkit.util.EntityUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.Reflections;
|
||||
import net.momirealms.craftengine.core.entity.Billboard;
|
||||
import net.momirealms.craftengine.core.entity.ItemDisplayContext;
|
||||
import net.momirealms.craftengine.core.entity.furniture.*;
|
||||
import net.momirealms.craftengine.core.loot.LootTable;
|
||||
import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.plugin.event.EventFunctions;
|
||||
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.WorldPosition;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
public static final NamespacedKey FURNITURE_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_id"));
|
||||
// DEPRECATED
|
||||
// public static final NamespacedKey FURNITURE_ANCHOR_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:anchor_type"));
|
||||
public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:furniture_extra_data"));
|
||||
public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_to_base_entity"));
|
||||
public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = Objects.requireNonNull(NamespacedKey.fromString("craftengine:seat_vector"));
|
||||
public static final NamespacedKey FURNITURE_COLLISION = Objects.requireNonNull(NamespacedKey.fromString("craftengine:collision"));
|
||||
public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY);
|
||||
public static final NamespacedKey FURNITURE_EXTRA_DATA_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_EXTRA_DATA_KEY);
|
||||
public static final NamespacedKey FURNITURE_SEAT_BASE_ENTITY_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY);
|
||||
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 = Reflections.instance$EntityType$INTERACTION;
|
||||
public static ColliderType COLLISION_ENTITY_TYPE = ColliderType.INTERACTION;
|
||||
private static BukkitFurnitureManager instance;
|
||||
private final BukkitCraftEngine plugin;
|
||||
private final FurnitureParser furnitureParser;
|
||||
private final Map<Integer, LoadedFurniture> furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f);
|
||||
private final Map<Integer, LoadedFurniture> furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f);
|
||||
private final Map<Integer, BukkitFurniture> furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f);
|
||||
private final Map<Integer, BukkitFurniture> furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f);
|
||||
// Event listeners
|
||||
private final Listener dismountListener;
|
||||
private final FurnitureEventListener furnitureEventListener;
|
||||
@@ -67,9 +54,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
}
|
||||
|
||||
public BukkitFurnitureManager(BukkitCraftEngine plugin) {
|
||||
super(plugin);
|
||||
instance = this;
|
||||
this.plugin = plugin;
|
||||
this.furnitureParser = new FurnitureParser();
|
||||
this.furnitureEventListener = new FurnitureEventListener(this);
|
||||
this.dismountListener = VersionHelper.isOrAbove1_20_3() ? new DismountListener1_20_3(this) : new DismountListener1_20(this::handleDismount);
|
||||
}
|
||||
@@ -79,7 +66,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
return this.place(LocationUtils.toLocation(position), furniture, extraData, playSound);
|
||||
}
|
||||
|
||||
public LoadedFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) {
|
||||
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());
|
||||
@@ -101,128 +88,6 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigParser parser() {
|
||||
return this.furnitureParser;
|
||||
}
|
||||
|
||||
public class FurnitureParser implements ConfigParser {
|
||||
public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" };
|
||||
|
||||
@Override
|
||||
public String[] sectionId() {
|
||||
return CONFIG_SECTION_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int loadingSequence() {
|
||||
return LoadingSequence.FURNITURE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) {
|
||||
if (byId.containsKey(id)) {
|
||||
throw new LocalizedResourceConfigException("warning.config.furniture.duplicate", path, id);
|
||||
}
|
||||
|
||||
Map<String, Object> lootMap = MiscUtils.castToMap(section.get("loot"), true);
|
||||
Map<String, Object> settingsMap = MiscUtils.castToMap(section.get("settings"), true);
|
||||
Map<String, Object> placementMap = MiscUtils.castToMap(section.get("placement"), true);
|
||||
if (placementMap == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.furniture.missing_placement", path, id);
|
||||
}
|
||||
|
||||
EnumMap<AnchorType, CustomFurniture.Placement> placements = new EnumMap<>(AnchorType.class);
|
||||
|
||||
for (Map.Entry<String, Object> entry : placementMap.entrySet()) {
|
||||
// anchor type
|
||||
AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH));
|
||||
Map<String, Object> placementArguments = MiscUtils.castToMap(entry.getValue(), true);
|
||||
|
||||
Optional<Vector3f> optionalLootSpawnOffset = Optional.ofNullable(placementArguments.get("loot-spawn-offset")).map(it -> MiscUtils.getAsVector3f(it, "loot-spawn-offset"));
|
||||
|
||||
// furniture display elements
|
||||
List<FurnitureElement> elements = new ArrayList<>();
|
||||
List<Map<String, Object>> elementConfigs = (List<Map<String, Object>>) placementArguments.getOrDefault("elements", List.of());
|
||||
for (Map<String, Object> element : elementConfigs) {
|
||||
String key = (String) element.get("item");
|
||||
if (key == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.furniture.element.missing_item", path, id);
|
||||
}
|
||||
ItemDisplayContext transform = ItemDisplayContext.valueOf(element.getOrDefault("transform", "NONE").toString().toUpperCase(Locale.ENGLISH));
|
||||
Billboard billboard = Billboard.valueOf(element.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH));
|
||||
FurnitureElement furnitureElement = new BukkitFurnitureElement(Key.of(key), billboard, transform,
|
||||
MiscUtils.getAsVector3f(element.getOrDefault("scale", "1"), "scale"),
|
||||
MiscUtils.getAsVector3f(element.getOrDefault("translation", "0"), "translation"),
|
||||
MiscUtils.getAsVector3f(element.getOrDefault("position", "0"), "position"),
|
||||
MiscUtils.getAsQuaternionf(element.getOrDefault("rotation", "0"), "rotation"),
|
||||
(boolean) element.getOrDefault("apply-dyed-color", true)
|
||||
);
|
||||
elements.add(furnitureElement);
|
||||
}
|
||||
|
||||
// external model providers
|
||||
Optional<ExternalModel> externalModel;
|
||||
if (placementArguments.containsKey("model-engine")) {
|
||||
externalModel = Optional.of(plugin.compatibilityManager().createModelEngineModel(placementArguments.get("model-engine").toString()));
|
||||
} else if (placementArguments.containsKey("better-model")) {
|
||||
externalModel = Optional.of(plugin.compatibilityManager().createBetterModelModel(placementArguments.get("better-model").toString()));
|
||||
} else {
|
||||
externalModel = Optional.empty();
|
||||
}
|
||||
|
||||
// add hitboxes
|
||||
List<Map<String, Object>> hitboxConfigs = (List<Map<String, Object>>) placementArguments.getOrDefault("hitboxes", List.of());
|
||||
List<HitBox> hitboxes = new ArrayList<>();
|
||||
for (Map<String, Object> config : hitboxConfigs) {
|
||||
HitBox hitBox = HitBoxTypes.fromMap(config);
|
||||
hitboxes.add(hitBox);
|
||||
}
|
||||
if (hitboxes.isEmpty() && externalModel.isEmpty()) {
|
||||
hitboxes.add(InteractionHitBox.DEFAULT);
|
||||
}
|
||||
|
||||
// rules
|
||||
Map<String, Object> ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true);
|
||||
if (ruleSection != null) {
|
||||
RotationRule rotationRule = Optional.ofNullable((String) ruleSection.get("rotation"))
|
||||
.map(it -> RotationRule.valueOf(it.toUpperCase(Locale.ENGLISH)))
|
||||
.orElse(RotationRule.ANY);
|
||||
AlignmentRule alignmentRule = Optional.ofNullable((String) ruleSection.get("alignment"))
|
||||
.map(it -> AlignmentRule.valueOf(it.toUpperCase(Locale.ENGLISH)))
|
||||
.orElse(AlignmentRule.CENTER);
|
||||
placements.put(anchorType, new CustomFurniture.Placement(
|
||||
elements.toArray(new FurnitureElement[0]),
|
||||
hitboxes.toArray(new HitBox[0]),
|
||||
rotationRule,
|
||||
alignmentRule,
|
||||
externalModel,
|
||||
optionalLootSpawnOffset
|
||||
));
|
||||
} else {
|
||||
placements.put(anchorType, new CustomFurniture.Placement(
|
||||
elements.toArray(new FurnitureElement[0]),
|
||||
hitboxes.toArray(new HitBox[0]),
|
||||
RotationRule.ANY,
|
||||
AlignmentRule.CENTER,
|
||||
externalModel,
|
||||
optionalLootSpawnOffset
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// get furniture settings
|
||||
FurnitureSettings settings = FurnitureSettings.fromMap(settingsMap);
|
||||
|
||||
// get loot table
|
||||
LootTable<ItemStack> lootTable = lootMap == null ? null : LootTable.fromMap(lootMap);
|
||||
EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"));
|
||||
CustomFurniture furniture = new CustomFurniture(id, settings, placements, events, lootTable);
|
||||
byId.put(id, furniture);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delayedInit() {
|
||||
COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class;
|
||||
@@ -264,19 +129,29 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LoadedFurniture loadedFurnitureByRealEntityId(int entityId) {
|
||||
public BukkitFurniture loadedFurnitureByRealEntityId(int entityId) {
|
||||
return this.furnitureByRealEntityId.get(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public LoadedFurniture loadedFurnitureByEntityId(int entityId) {
|
||||
public BukkitFurniture loadedFurnitureByEntityId(int entityId) {
|
||||
return this.furnitureByEntityId.get(entityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CustomFurniture.Builder furnitureBuilder() {
|
||||
return BukkitCustomFurniture.builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FurnitureElement.Builder furnitureElementBuilder() {
|
||||
return BukkitFurnitureElement.builder();
|
||||
}
|
||||
|
||||
protected void handleBaseEntityUnload(Entity entity) {
|
||||
int id = entity.getEntityId();
|
||||
LoadedFurniture furniture = this.furnitureByRealEntityId.remove(id);
|
||||
BukkitFurniture furniture = this.furnitureByRealEntityId.remove(id);
|
||||
if (furniture != null) {
|
||||
Location location = entity.getLocation();
|
||||
boolean isPreventing = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
@@ -305,7 +180,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
if (optionalFurniture.isEmpty()) return;
|
||||
|
||||
CustomFurniture customFurniture = optionalFurniture.get();
|
||||
LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
|
||||
BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
|
||||
if (previous != null) return;
|
||||
|
||||
Location location = display.getLocation();
|
||||
@@ -313,7 +188,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
boolean preventChange = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
if (above1_20_1) {
|
||||
if (!preventChange) {
|
||||
LoadedFurniture furniture = addNewFurniture(display, customFurniture);
|
||||
BukkitFurniture furniture = addNewFurniture(display, customFurniture);
|
||||
furniture.initializeColliders();
|
||||
for (Player player : display.getTrackedPlayers()) {
|
||||
this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds()));
|
||||
@@ -321,7 +196,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LoadedFurniture furniture = addNewFurniture(display, customFurniture);
|
||||
BukkitFurniture furniture = addNewFurniture(display, customFurniture);
|
||||
for (Player player : display.getTrackedPlayers()) {
|
||||
this.plugin.adapt(player).entityPacketHandlers().computeIfAbsent(furniture.baseEntityId(), k -> new FurniturePacketHandler(furniture.fakeEntityIds()));
|
||||
this.plugin.networkManager().sendPacket(player, furniture.spawnPacket(player));
|
||||
@@ -383,9 +258,9 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
Optional<CustomFurniture> optionalFurniture = furnitureById(key);
|
||||
if (optionalFurniture.isPresent()) {
|
||||
CustomFurniture customFurniture = optionalFurniture.get();
|
||||
LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
|
||||
BukkitFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId());
|
||||
if (previous != null) return;
|
||||
LoadedFurniture furniture = addNewFurniture(display, customFurniture);
|
||||
BukkitFurniture furniture = addNewFurniture(display, customFurniture);
|
||||
furniture.initializeColliders(); // safely do it here
|
||||
}
|
||||
}
|
||||
@@ -412,23 +287,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
return FurnitureExtraData.fromBytes(extraData);
|
||||
}
|
||||
|
||||
// private AnchorType getAnchorType(Entity baseEntity, CustomFurniture furniture) {
|
||||
// String anchorType = baseEntity.getPersistentDataContainer().get(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING);
|
||||
// if (anchorType != null) {
|
||||
// try {
|
||||
// AnchorType unverified = AnchorType.valueOf(anchorType);
|
||||
// if (furniture.isAllowedPlacement(unverified)) {
|
||||
// return unverified;
|
||||
// }
|
||||
// } catch (IllegalArgumentException ignored) {
|
||||
// }
|
||||
// }
|
||||
// AnchorType anchorTypeEnum = furniture.getAnyPlacement();
|
||||
// baseEntity.getPersistentDataContainer().set(FURNITURE_ANCHOR_KEY, PersistentDataType.STRING, anchorTypeEnum.name());
|
||||
// return anchorTypeEnum;
|
||||
// }
|
||||
|
||||
private synchronized LoadedFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture) {
|
||||
private synchronized BukkitFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture) {
|
||||
FurnitureExtraData extraData;
|
||||
try {
|
||||
extraData = getFurnitureExtraData(display);
|
||||
@@ -436,16 +295,21 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
extraData = FurnitureExtraData.builder().build();
|
||||
plugin.logger().warn("Furniture extra data could not be loaded", e);
|
||||
}
|
||||
LoadedFurniture loadedFurniture = new LoadedFurniture(display, furniture, extraData);
|
||||
this.furnitureByRealEntityId.put(loadedFurniture.baseEntityId(), loadedFurniture);
|
||||
for (int entityId : loadedFurniture.entityIds()) {
|
||||
this.furnitureByEntityId.put(entityId, loadedFurniture);
|
||||
BukkitFurniture bukkitFurniture = new BukkitFurniture(display, furniture, extraData);
|
||||
this.furnitureByRealEntityId.put(bukkitFurniture.baseEntityId(), bukkitFurniture);
|
||||
for (int entityId : bukkitFurniture.entityIds()) {
|
||||
this.furnitureByEntityId.put(entityId, bukkitFurniture);
|
||||
}
|
||||
for (Collider collisionEntity : loadedFurniture.collisionEntities()) {
|
||||
for (Collider collisionEntity : bukkitFurniture.collisionEntities()) {
|
||||
int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity.handle());
|
||||
this.furnitureByRealEntityId.put(collisionEntityId, loadedFurniture);
|
||||
this.furnitureByRealEntityId.put(collisionEntityId, bukkitFurniture);
|
||||
}
|
||||
return loadedFurniture;
|
||||
return bukkitFurniture;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HitBox defaultHitBox() {
|
||||
return InteractionHitBox.DEFAULT;
|
||||
}
|
||||
|
||||
protected void handleDismount(Player player, Entity entity) {
|
||||
@@ -458,7 +322,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
if (baseFurniture == null) return;
|
||||
vehicle.remove();
|
||||
LoadedFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture);
|
||||
BukkitFurniture furniture = loadedFurnitureByRealEntityId(baseFurniture);
|
||||
if (furniture == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.event.world.EntitiesLoadEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -6,14 +6,17 @@ import net.momirealms.craftengine.core.item.*;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.function.Function;
|
||||
import net.momirealms.craftengine.core.plugin.event.EventTrigger;
|
||||
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.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
private final Material material;
|
||||
@@ -22,7 +25,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
List<ItemBehavior> behaviors,
|
||||
List<ItemDataModifier<ItemStack>> modifiers, List<ItemDataModifier<ItemStack>> clientBoundModifiers,
|
||||
ItemSettings settings,
|
||||
EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||
Map<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||
super(id, materialKey, behaviors, modifiers, clientBoundModifiers, settings, events);
|
||||
this.material = material;
|
||||
}
|
||||
@@ -56,7 +59,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
private Holder<Key> id;
|
||||
private Key materialKey;
|
||||
private final Material material;
|
||||
private final EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events = new EnumMap<>(EventTrigger.class);
|
||||
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);
|
||||
@@ -122,7 +125,7 @@ public class BukkitCustomItem extends AbstractCustomItem<ItemStack> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<ItemStack> events(EnumMap<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||
public Builder<ItemStack> events(Map<EventTrigger, List<Function<PlayerOptionalContext>>> events) {
|
||||
this.events.putAll(events);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -98,6 +98,6 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
|
||||
|
||||
@Override
|
||||
public void count(int amount) {
|
||||
this.item.setAmount(amount);
|
||||
this.item.setAmount(Math.max(amount, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
|
||||
@Override
|
||||
public ItemStack load() {
|
||||
ItemStack itemStack = this.rtagItem.load();
|
||||
itemStack.setAmount(this.count);
|
||||
itemStack.setAmount(Math.max(this.count, 0));
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
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.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.Cancellable;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
|
||||
@@ -2,8 +2,8 @@ package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptPlaceEvent;
|
||||
import net.momirealms.craftengine.bukkit.api.event.FurniturePlaceEvent;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
@@ -23,8 +23,8 @@ import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
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.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
@@ -105,7 +105,7 @@ public class FurnitureItemBehavior extends ItemBehavior {
|
||||
finalPlacePosition = new Vec3d(xz.left(), xz.right(), clickedPosition.z());
|
||||
}
|
||||
} else {
|
||||
furnitureYaw = placement.rotationRule().apply(180 + player.getXRot());
|
||||
furnitureYaw = placement.rotationRule().apply(180 + player.xRot());
|
||||
Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.z()));
|
||||
finalPlacePosition = new Vec3d(xz.left(), clickedPosition.y(), xz.right());
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class FurnitureItemBehavior extends ItemBehavior {
|
||||
|
||||
Item<?> item = context.getItem();
|
||||
|
||||
LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().place(
|
||||
BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place(
|
||||
furnitureLocation.clone(), customFurniture,
|
||||
FurnitureExtraData.builder()
|
||||
.item(item.copyWithCount(1))
|
||||
@@ -142,15 +142,15 @@ public class FurnitureItemBehavior extends ItemBehavior {
|
||||
.dyedColor(item.dyedColor().orElse(null))
|
||||
.build(), false);
|
||||
|
||||
FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, loadedFurniture, furnitureLocation, context.getHand());
|
||||
FurniturePlaceEvent placeEvent = new FurniturePlaceEvent(bukkitPlayer, bukkitFurniture, furnitureLocation, context.getHand());
|
||||
if (EventUtils.fireAndCheckCancel(placeEvent)) {
|
||||
loadedFurniture.destroy();
|
||||
bukkitFurniture.destroy();
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
Cancellable dummy = Cancellable.dummy();
|
||||
PlayerOptionalContext functionContext = PlayerOptionalContext.of(player, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FURNITURE, loadedFurniture)
|
||||
.withParameter(DirectContextParameters.FURNITURE, bukkitFurniture)
|
||||
.withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(furnitureLocation))
|
||||
.withParameter(DirectContextParameters.EVENT, dummy)
|
||||
.withParameter(DirectContextParameters.HAND, context.getHand())
|
||||
|
||||
@@ -25,8 +25,8 @@ import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -16,8 +16,8 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
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.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.util.Cancellable;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.world.BlockHitResult;
|
||||
@@ -121,7 +121,14 @@ public class ItemEventListener implements Listener {
|
||||
|
||||
// interact block with items
|
||||
if (hasItem && action == Action.RIGHT_CLICK_BLOCK) {
|
||||
Location interactionPoint = Objects.requireNonNull(event.getInteractionPoint(), "interaction point should not be null");
|
||||
Location interactionPoint = event.getInteractionPoint();
|
||||
// some plugins would trigger this event without interaction point
|
||||
if (interactionPoint == null) {
|
||||
if (hasCustomItem) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Direction direction = DirectionUtils.toDirection(event.getBlockFace());
|
||||
BlockPos pos = LocationUtils.toBlockPos(block.getLocation());
|
||||
Vec3d vec3d = new Vec3d(interactionPoint.getX(), interactionPoint.getY(), interactionPoint.getZ());
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.command;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.ComponentUtils;
|
||||
@@ -18,11 +17,9 @@ import org.bukkit.entity.Player;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitSenderFactory extends SenderFactory<BukkitCraftEngine, CommandSender> {
|
||||
private final BukkitAudiences audiences;
|
||||
|
||||
public BukkitSenderFactory(BukkitCraftEngine plugin) {
|
||||
super(plugin);
|
||||
this.audiences = BukkitAudiences.create(plugin.bootstrap());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,20 +38,18 @@ public class BukkitSenderFactory extends SenderFactory<BukkitCraftEngine, Comman
|
||||
return Sender.CONSOLE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Audience audience(CommandSender sender) {
|
||||
return this.audiences.sender(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
// we can safely send async for players and the console - otherwise, send it sync
|
||||
if (sender instanceof Player player) {
|
||||
FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player), FastNMS.INSTANCE.constructor$ClientboundSystemChatPacket(ComponentUtils.adventureToMinecraft(message), false));
|
||||
} else if (sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
|
||||
audience(sender).sendMessage(message);
|
||||
} else if (sender instanceof ConsoleCommandSender commandSender) {
|
||||
commandSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message));
|
||||
} else if (sender instanceof RemoteConsoleCommandSender commandSender) {
|
||||
commandSender.sendMessage(LegacyComponentSerializer.legacySection().serialize(message));
|
||||
} else {
|
||||
plugin().scheduler().executeSync(() -> audience(sender).sendMessage(message));
|
||||
String legacy = LegacyComponentSerializer.legacySection().serialize(message);
|
||||
plugin().scheduler().sync().run(() -> sender.sendMessage(legacy));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +88,5 @@ public class BukkitSenderFactory extends SenderFactory<BukkitCraftEngine, Comman
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
this.audiences.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature<Comma
|
||||
for (int appearance : appearances) {
|
||||
Component text = Component.text("|");
|
||||
List<Integer> reals = blockManager.appearanceToRealStates(appearance);
|
||||
if (reals == null) {
|
||||
if (reals == null || reals.isEmpty()) {
|
||||
Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.GREEN);
|
||||
hover = hover.append(Component.newline()).append(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.GREEN));
|
||||
text = text.color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover));
|
||||
|
||||
@@ -3,16 +3,17 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.item.ComponentTypes;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.bukkit.util.MaterialUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.PlayerUtils;
|
||||
import net.momirealms.craftengine.core.item.*;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import net.momirealms.craftengine.core.plugin.command.FlagKeys;
|
||||
import net.momirealms.craftengine.core.plugin.locale.MessageConstants;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -26,7 +27,6 @@ import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.context.CommandInput;
|
||||
import org.incendo.cloud.parser.flag.CommandFlag;
|
||||
import org.incendo.cloud.parser.standard.StringParser;
|
||||
import org.incendo.cloud.suggestion.Suggestion;
|
||||
import org.incendo.cloud.suggestion.SuggestionProvider;
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture;
|
||||
import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent;
|
||||
import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager;
|
||||
import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture;
|
||||
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
@@ -35,11 +35,14 @@ import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
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.plugin.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.network.*;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import net.momirealms.craftengine.core.world.BlockHitResult;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.EntityHitResult;
|
||||
import net.momirealms.craftengine.core.world.WorldEvents;
|
||||
import net.momirealms.craftengine.core.world.chunk.Palette;
|
||||
import net.momirealms.craftengine.core.world.chunk.PalettedContainer;
|
||||
import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData;
|
||||
@@ -47,7 +50,6 @@ import net.momirealms.craftengine.core.world.chunk.packet.MCSection;
|
||||
import net.momirealms.craftengine.core.world.collision.AABB;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -1489,7 +1491,7 @@ public class PacketConsumers {
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> PICK_ITEM_FROM_ENTITY = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = (int) Reflections.field$ServerboundPickItemFromEntityPacket$id.get(packet);
|
||||
LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
|
||||
if (furniture == null) return;
|
||||
Player player = (Player) user.platformPlayer();
|
||||
if (player == null) return;
|
||||
@@ -1518,7 +1520,7 @@ public class PacketConsumers {
|
||||
}
|
||||
};
|
||||
|
||||
private static void handlePickItemFromEntityOnMainThread(Player player, LoadedFurniture furniture) throws Exception {
|
||||
private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Exception {
|
||||
Key itemId = furniture.config().settings().itemId();
|
||||
if (itemId == null) return;
|
||||
pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity()));
|
||||
@@ -1596,7 +1598,7 @@ public class PacketConsumers {
|
||||
int entityId = FastNMS.INSTANCE.field$ClientboundAddEntityPacket$entityId(packet);
|
||||
if (entityType == Reflections.instance$EntityType$ITEM_DISPLAY) {
|
||||
// Furniture
|
||||
LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId);
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId);
|
||||
if (furniture != null) {
|
||||
Player player = (Player) user.platformPlayer();
|
||||
List<Integer> fakeEntityIds = furniture.fakeEntityIds();
|
||||
@@ -1631,7 +1633,7 @@ public class PacketConsumers {
|
||||
}
|
||||
} else if (entityType == BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE) {
|
||||
// Cancel collider entity packet
|
||||
LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId);
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(entityId);
|
||||
if (furniture != null) {
|
||||
event.setCancelled(true);
|
||||
user.entityPacketHandlers().put(entityId, FurnitureCollisionPacketHandler.INSTANCE);
|
||||
@@ -1709,7 +1711,7 @@ public class PacketConsumers {
|
||||
} else {
|
||||
entityId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet);
|
||||
}
|
||||
LoadedFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
|
||||
BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId);
|
||||
if (furniture == null) return;
|
||||
Object action = Reflections.field$ServerboundInteractPacket$action.get(packet);
|
||||
Object actionType = Reflections.method$ServerboundInteractPacket$Action$getType.invoke(action);
|
||||
@@ -1733,7 +1735,7 @@ public class PacketConsumers {
|
||||
// execute functions
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FURNITURE, furniture)
|
||||
.withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position()))
|
||||
.withParameter(DirectContextParameters.POSITION, furniture.position())
|
||||
);
|
||||
furniture.config().execute(context, EventTrigger.LEFT_CLICK);
|
||||
furniture.config().execute(context, EventTrigger.BREAK);
|
||||
@@ -1763,7 +1765,7 @@ public class PacketConsumers {
|
||||
// execute functions
|
||||
PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.FURNITURE, furniture)
|
||||
.withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position()))
|
||||
.withParameter(DirectContextParameters.POSITION, furniture.position())
|
||||
);
|
||||
furniture.config().execute(context, EventTrigger.RIGHT_CLICK);
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import net.momirealms.craftengine.bukkit.plugin.gui.CraftEngineInventoryHolder;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.BlockSettings;
|
||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.PackedBlockState;
|
||||
import net.momirealms.craftengine.core.entity.player.GameMode;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
@@ -433,7 +433,7 @@ public class BukkitServerPlayer extends Player {
|
||||
// instant break
|
||||
boolean custom = immutableBlockState != null;
|
||||
if (custom && getDestroyProgress(state, pos) >= 1f) {
|
||||
PackedBlockState vanillaBlockState = immutableBlockState.vanillaBlockState();
|
||||
BlockStateWrapper vanillaBlockState = immutableBlockState.vanillaBlockState();
|
||||
// if it's not an instant break on client side, we should resend level event
|
||||
if (vanillaBlockState != null && getDestroyProgress(vanillaBlockState.handle(), pos) < 1f) {
|
||||
Object levelEventPacket = FastNMS.INSTANCE.constructor$ClientboundLevelEventPacket(
|
||||
@@ -641,6 +641,11 @@ public class BukkitServerPlayer extends Player {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void breakBlock(int x, int y, int z) {
|
||||
platformPlayer().breakBlock(new Location(platformPlayer().getWorld(), x, y, z).getBlock());
|
||||
}
|
||||
|
||||
private void broadcastDestroyProgress(org.bukkit.entity.Player player, BlockPos hitPos, Object blockPos, int stage) {
|
||||
Object packet = FastNMS.INSTANCE.constructor$ClientboundBlockDestructionPacket(Integer.MAX_VALUE - entityID(), blockPos, stage);
|
||||
for (org.bukkit.entity.Player other : player.getWorld().getPlayers()) {
|
||||
@@ -698,12 +703,12 @@ public class BukkitServerPlayer extends Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getYRot() {
|
||||
public float yRot() {
|
||||
return platformPlayer().getPitch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXRot() {
|
||||
public float xRot() {
|
||||
return platformPlayer().getYaw();
|
||||
}
|
||||
|
||||
@@ -878,4 +883,24 @@ public class BukkitServerPlayer extends Player {
|
||||
public boolean isFlying() {
|
||||
return platformPlayer().isFlying();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int foodLevel() {
|
||||
return platformPlayer().getFoodLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFoodLevel(int foodLevel) {
|
||||
this.platformPlayer().setFoodLevel(Math.min(Math.max(0, foodLevel), 20));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float saturation() {
|
||||
return platformPlayer().getSaturation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSaturation(float saturation) {
|
||||
this.platformPlayer().setSaturation(saturation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ public class BlockStateUtils {
|
||||
hasInit = true;
|
||||
}
|
||||
|
||||
public static BlockStateWrapper toPackedBlockState(BlockData blockData) {
|
||||
Object state = blockDataToBlockState(blockData);
|
||||
int id = blockStateToId(state);
|
||||
return BlockStateWrapper.create(state, id, isVanillaBlock(id));
|
||||
}
|
||||
|
||||
public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item<ItemStack> itemInHand) {
|
||||
BlockSettings settings = state.settings();
|
||||
if (settings.requireCorrectTool()) {
|
||||
@@ -101,10 +107,10 @@ public class BlockStateUtils {
|
||||
}
|
||||
|
||||
public static Key getBlockOwnerId(Block block) {
|
||||
return getBlockOwnerId(block.getBlockData());
|
||||
return getBlockOwnerIdFromData(block.getBlockData());
|
||||
}
|
||||
|
||||
public static Key getBlockOwnerId(BlockData block) {
|
||||
public static Key getBlockOwnerIdFromData(BlockData block) {
|
||||
Object blockState = blockDataToBlockState(block);
|
||||
return getBlockOwnerIdFromState(blockState);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ public class ComponentUtils {
|
||||
return jsonElementToMinecraft(AdventureHelper.componentToJsonElement(component));
|
||||
}
|
||||
|
||||
public static Object adventureToPaperAdventure(Component component) {
|
||||
return jsonElementToPaperAdventure(AdventureHelper.componentToJsonElement(component));
|
||||
}
|
||||
|
||||
public static Object jsonElementToMinecraft(JsonElement json) {
|
||||
return FastNMS.INSTANCE.method$Component$Serializer$fromJson(json);
|
||||
}
|
||||
|
||||
@@ -274,7 +274,7 @@ public class InteractUtils {
|
||||
}
|
||||
|
||||
public static boolean isInteractable(Player player, BlockData state, BlockHitResult hit, Item<ItemStack> item) {
|
||||
Key blockType = BlockStateUtils.getBlockOwnerId(state);
|
||||
Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state);
|
||||
if (INTERACTIONS.containsKey(blockType)) {
|
||||
return INTERACTIONS.get(blockType).apply(player, item, state, hit);
|
||||
} else {
|
||||
|
||||
@@ -4,8 +4,8 @@ import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.core.block.BlockSounds;
|
||||
import net.momirealms.craftengine.core.sound.SoundSource;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.SoundCategory;
|
||||
|
||||
public class SoundUtils {
|
||||
|
||||
@@ -21,4 +23,19 @@ public class SoundUtils {
|
||||
public static Object getOrRegisterSoundEvent(Key key) throws ReflectiveOperationException {
|
||||
return Reflections.method$SoundEvent$createVariableRangeEvent.invoke(null, KeyUtils.toResourceLocation(key));
|
||||
}
|
||||
|
||||
public static SoundCategory toBukkit(SoundSource source) {
|
||||
return switch (source) {
|
||||
case BLOCK -> SoundCategory.BLOCKS;
|
||||
case MUSIC -> SoundCategory.MUSIC;
|
||||
case VOICE -> SoundCategory.VOICE;
|
||||
case MASTER -> SoundCategory.MASTER;
|
||||
case PLAYER -> SoundCategory.PLAYERS;
|
||||
case RECORD -> SoundCategory.RECORDS;
|
||||
case AMBIENT -> SoundCategory.AMBIENT;
|
||||
case HOSTILE -> SoundCategory.HOSTILE;
|
||||
case NEUTRAL -> SoundCategory.NEUTRAL;
|
||||
case WEATHER -> SoundCategory.WEATHER;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ 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.SoundUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockStateWrapper;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
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;
|
||||
@@ -86,6 +89,11 @@ public class BukkitWorld implements World {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playSound(Position location, Key sound, float volume, float pitch, SoundSource source) {
|
||||
platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playBlockSound(Position location, Key sound, float volume, float pitch) {
|
||||
platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch);
|
||||
@@ -95,4 +103,11 @@ public class BukkitWorld implements World {
|
||||
public long time() {
|
||||
return platformWorld().getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockAt(int x, int y, int z, BlockStateWrapper blockState, int flags) {
|
||||
Object worldServer = serverWorld();
|
||||
Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.handle(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user