Fix compilation errors
This commit is contained in:
parent
21a40835b5
commit
d86f5b87f1
29 changed files with 9 additions and 6622 deletions
|
@ -2,6 +2,7 @@ package dev.zontreck.libzontreck.blocks;
|
|||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
@ -45,7 +46,8 @@ public abstract class RedstoneBlock extends RotatableBlock
|
|||
|
||||
private boolean redstoneIsActivated(LevelReader level, BlockPos pos)
|
||||
{
|
||||
if(level.hasNeighborSignal(pos))
|
||||
ServerLevel srv = (ServerLevel)level;
|
||||
if(srv.hasNeighborSignal(pos))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
|
|
@ -1,590 +0,0 @@
|
|||
/*
|
||||
* @file Auxiliaries.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* General commonly used functionality.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ComponentUtils;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.shapes.BooleanOp;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import org.slf4j.Logger;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
public class Auxiliaries {
|
||||
private static String modid;
|
||||
private static Logger logger;
|
||||
private static Supplier<CompoundTag> server_config_supplier = CompoundTag::new;
|
||||
|
||||
public static void init(String modid, Logger logger, Supplier<CompoundTag> server_config_supplier) {
|
||||
Auxiliaries.modid = modid;
|
||||
Auxiliaries.logger = logger;
|
||||
Auxiliaries.server_config_supplier = server_config_supplier;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Mod specific exports
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static String modid() {
|
||||
return modid;
|
||||
}
|
||||
|
||||
public static Logger logger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Sidedness, system/environment, tagging interfaces
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public interface IExperimentalFeature {
|
||||
}
|
||||
|
||||
public static boolean isModLoaded(final String registry_name) {
|
||||
return ModList.get().isLoaded(registry_name);
|
||||
}
|
||||
|
||||
public static boolean isDevelopmentMode() {
|
||||
return SharedConstants.IS_RUNNING_IN_IDE;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean isShiftDown() {
|
||||
return (InputConstants.isKeyDown(SidedProxy.mc().getWindow().getWindow(), GLFW.GLFW_KEY_LEFT_SHIFT) ||
|
||||
InputConstants.isKeyDown(SidedProxy.mc().getWindow().getWindow(), GLFW.GLFW_KEY_RIGHT_SHIFT));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean isCtrlDown() {
|
||||
return (InputConstants.isKeyDown(SidedProxy.mc().getWindow().getWindow(), GLFW.GLFW_KEY_LEFT_CONTROL) ||
|
||||
InputConstants.isKeyDown(SidedProxy.mc().getWindow().getWindow(), GLFW.GLFW_KEY_RIGHT_CONTROL));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Logging
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static void logInfo(final String msg) {
|
||||
logger.info(msg);
|
||||
}
|
||||
|
||||
public static void logWarn(final String msg) {
|
||||
logger.warn(msg);
|
||||
}
|
||||
|
||||
public static void logError(final String msg) {
|
||||
logger.error(msg);
|
||||
}
|
||||
|
||||
public static void logDebug(final String msg) { /*logger.debug(msg);*/ }
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Localization, text formatting
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Text localization wrapper, implicitly prepends `MODID` to the
|
||||
* translation keys. Forces formatting argument, nullable if no special formatting shall be applied..
|
||||
*/
|
||||
public static MutableComponent localizable(String modtrkey, Object... args) {
|
||||
return Component.translatable((modtrkey.startsWith("block.") || (modtrkey.startsWith("item."))) ? (modtrkey) : (modid + "." + modtrkey), args);
|
||||
}
|
||||
|
||||
public static MutableComponent localizable(String modtrkey, @Nullable ChatFormatting color, Object... args) {
|
||||
final MutableComponent tr = Component.translatable(modid + "." + modtrkey, args);
|
||||
if (color != null) tr.getStyle().applyFormat(color);
|
||||
return tr;
|
||||
}
|
||||
|
||||
public static Component localizable(String modtrkey) {
|
||||
return localizable(modtrkey, new Object[]{});
|
||||
}
|
||||
|
||||
public static Component localizable_block_key(String blocksubkey) {
|
||||
return Component.translatable("block." + modid + "." + blocksubkey);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static String localize(String translationKey, Object... args) {
|
||||
Component tr = Component.translatable(translationKey, args);
|
||||
tr.getStyle().applyFormat(ChatFormatting.RESET);
|
||||
final String ft = tr.getString();
|
||||
if (ft.contains("${")) {
|
||||
// Non-recursive, non-argument lang file entry cross referencing.
|
||||
Pattern pt = Pattern.compile("\\$\\{([^}]+)\\}");
|
||||
Matcher mt = pt.matcher(ft);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (mt.find()) {
|
||||
String m = mt.group(1);
|
||||
if (m.contains("?")) {
|
||||
String[] kv = m.split("\\?", 2);
|
||||
String key = kv[0].trim();
|
||||
boolean not = key.startsWith("!");
|
||||
if (not) key = key.replaceFirst("!", "");
|
||||
m = kv[1].trim();
|
||||
if (!server_config_supplier.get().contains(key)) {
|
||||
m = "";
|
||||
} else {
|
||||
boolean r = server_config_supplier.get().getBoolean(key);
|
||||
if (not) r = !r;
|
||||
if (!r) m = "";
|
||||
}
|
||||
}
|
||||
mt.appendReplacement(sb, Matcher.quoteReplacement((Component.translatable(m)).getString().trim()));
|
||||
}
|
||||
mt.appendTail(sb);
|
||||
return sb.toString();
|
||||
} else {
|
||||
return ft;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a given key is translated for the current language.
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean hasTranslation(String key) {
|
||||
return net.minecraft.client.resources.language.I18n.exists(key);
|
||||
}
|
||||
|
||||
public static MutableComponent join(Collection<? extends Component> components, String separator) {
|
||||
return ComponentUtils.formatList(components, Component.literal(separator), Function.identity());
|
||||
}
|
||||
|
||||
public static MutableComponent join(Component... components) {
|
||||
final MutableComponent tc = Component.empty();
|
||||
for (Component c : components) {
|
||||
tc.append(c);
|
||||
}
|
||||
return tc;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(Component component) {
|
||||
return component.getSiblings().isEmpty() && component.getString().isEmpty();
|
||||
}
|
||||
|
||||
public static final class Tooltip {
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean extendedTipCondition() {
|
||||
return isShiftDown();
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean helpCondition() {
|
||||
return isShiftDown() && isCtrlDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an extended tooltip or help tooltip depending on the key states of CTRL and SHIFT.
|
||||
* Returns true if the localisable help/tip was added, false if not (either not CTL/SHIFT or
|
||||
* no translation found).
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean addInformation(@Nullable String advancedTooltipTranslationKey, @Nullable String helpTranslationKey, List<Component> tooltip, TooltipFlag flag, boolean addAdvancedTooltipHints) {
|
||||
// Note: intentionally not using keybinding here, this must be `control` or `shift`.
|
||||
final boolean help_available = (helpTranslationKey != null) && Auxiliaries.hasTranslation(helpTranslationKey + ".help");
|
||||
final boolean tip_available = (advancedTooltipTranslationKey != null) && Auxiliaries.hasTranslation(helpTranslationKey + ".tip");
|
||||
if ((!help_available) && (!tip_available)) return false;
|
||||
String tip_text = "";
|
||||
if (helpCondition()) {
|
||||
if (help_available) tip_text = localize(helpTranslationKey + ".help");
|
||||
} else if (extendedTipCondition()) {
|
||||
if (tip_available) tip_text = localize(advancedTooltipTranslationKey + ".tip");
|
||||
} else if (addAdvancedTooltipHints) {
|
||||
if (tip_available) tip_text += localize(modid + ".tooltip.hint.extended") + (help_available ? " " : "");
|
||||
if (help_available) tip_text += localize(modid + ".tooltip.hint.help");
|
||||
}
|
||||
if (tip_text.isEmpty()) return false;
|
||||
String[] tip_list = tip_text.split("\\r?\\n");
|
||||
for (String tip : tip_list) {
|
||||
tooltip.add(Component.literal(tip.replaceAll("\\s+$", "").replaceAll("^\\s+", "")).withStyle(ChatFormatting.GRAY));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an extended tooltip or help tooltip for a given stack depending on the key states of CTRL and SHIFT.
|
||||
* Format in the lang file is (e.g. for items): "item.MODID.REGISTRYNAME.tip" and "item.MODID.REGISTRYNAME.help".
|
||||
* Return value see method pattern above.
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean addInformation(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag, boolean addAdvancedTooltipHints) {
|
||||
return addInformation(stack.getDescriptionId(), stack.getDescriptionId(), tooltip, flag, addAdvancedTooltipHints);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean addInformation(String translation_key, List<Component> tooltip) {
|
||||
if (!Auxiliaries.hasTranslation(translation_key)) return false;
|
||||
tooltip.add(Component.literal(localize(translation_key).replaceAll("\\s+$", "").replaceAll("^\\s+", "")).withStyle(ChatFormatting.GRAY));
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void playerChatMessage(final Player player, final String message) {
|
||||
player.displayClientMessage(Component.translatable(message.trim()), true);
|
||||
}
|
||||
|
||||
public static @Nullable Component unserializeTextComponent(String serialized) {
|
||||
return Component.Serializer.fromJson(serialized);
|
||||
}
|
||||
|
||||
public static String serializeTextComponent(Component tc) {
|
||||
return (tc == null) ? ("") : (Component.Serializer.toJson(tc));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Tag Handling
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean isInItemTag(Item item, ResourceLocation tag) {
|
||||
return ForgeRegistries.ITEMS.tags().stream().filter(tg -> tg.getKey().location().equals(tag)).anyMatch(tk -> tk.contains(item));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean isInBlockTag(Block block, ResourceLocation tag) {
|
||||
return ForgeRegistries.BLOCKS.tags().stream().filter(tg -> tg.getKey().location().equals(tag)).anyMatch(tk -> tk.contains(block));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ResourceLocation getResourceLocation(Item item) {
|
||||
return ForgeRegistries.ITEMS.getKey(item);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ResourceLocation getResourceLocation(Block block) {
|
||||
return ForgeRegistries.BLOCKS.getKey(block);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ResourceLocation getResourceLocation(net.minecraft.world.inventory.MenuType<?> menu) {
|
||||
return ForgeRegistries.MENU_TYPES.getKey(menu);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ResourceLocation getResourceLocation(net.minecraft.world.level.material.Fluid fluid) {
|
||||
return ForgeRegistries.FLUIDS.getKey(fluid);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Item NBT data
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Equivalent to getDisplayName(), returns null if no custom name is set.
|
||||
*/
|
||||
public static @Nullable Component getItemLabel(ItemStack stack) {
|
||||
CompoundTag nbt = stack.getTagElement("display");
|
||||
if (nbt != null && nbt.contains("Name", 8)) {
|
||||
try {
|
||||
Component tc = unserializeTextComponent(nbt.getString("Name"));
|
||||
if (tc != null) return tc;
|
||||
nbt.remove("Name");
|
||||
} catch (Exception e) {
|
||||
nbt.remove("Name");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ItemStack setItemLabel(ItemStack stack, @Nullable Component name) {
|
||||
if (name != null) {
|
||||
CompoundTag nbt = stack.getOrCreateTagElement("display");
|
||||
nbt.putString("Name", serializeTextComponent(name));
|
||||
} else {
|
||||
if (stack.hasTag()) stack.removeTagKey("display");
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Block handling
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static boolean isWaterLogged(BlockState state) {
|
||||
return state.hasProperty(BlockStateProperties.WATERLOGGED) && state.getValue(BlockStateProperties.WATERLOGGED);
|
||||
}
|
||||
|
||||
public static AABB getPixeledAABB(double x0, double y0, double z0, double x1, double y1, double z1) {
|
||||
return new AABB(x0 / 16.0, y0 / 16.0, z0 / 16.0, x1 / 16.0, y1 / 16.0, z1 / 16.0);
|
||||
}
|
||||
|
||||
public static AABB getRotatedAABB(AABB bb, Direction new_facing) {
|
||||
return getRotatedAABB(bb, new_facing, false);
|
||||
}
|
||||
|
||||
public static AABB[] getRotatedAABB(AABB[] bb, Direction new_facing) {
|
||||
return getRotatedAABB(bb, new_facing, false);
|
||||
}
|
||||
|
||||
public static AABB getRotatedAABB(AABB bb, Direction new_facing, boolean horizontal_rotation) {
|
||||
if (!horizontal_rotation) {
|
||||
switch (new_facing.get3DDataValue()) {
|
||||
case 0:
|
||||
return new AABB(1 - bb.maxX, bb.minZ, bb.minY, 1 - bb.minX, bb.maxZ, bb.maxY); // D
|
||||
case 1:
|
||||
return new AABB(1 - bb.maxX, 1 - bb.maxZ, 1 - bb.maxY, 1 - bb.minX, 1 - bb.minZ, 1 - bb.minY); // U
|
||||
case 2:
|
||||
return new AABB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // N --> bb
|
||||
case 3:
|
||||
return new AABB(1 - bb.maxX, bb.minY, 1 - bb.maxZ, 1 - bb.minX, bb.maxY, 1 - bb.minZ); // S
|
||||
case 4:
|
||||
return new AABB(bb.minZ, bb.minY, 1 - bb.maxX, bb.maxZ, bb.maxY, 1 - bb.minX); // W
|
||||
case 5:
|
||||
return new AABB(1 - bb.maxZ, bb.minY, bb.minX, 1 - bb.minZ, bb.maxY, bb.maxX); // E
|
||||
}
|
||||
} else {
|
||||
switch (new_facing.get3DDataValue()) {
|
||||
case 0:
|
||||
return new AABB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // D --> bb
|
||||
case 1:
|
||||
return new AABB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // U --> bb
|
||||
case 2:
|
||||
return new AABB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ); // N --> bb
|
||||
case 3:
|
||||
return new AABB(1 - bb.maxX, bb.minY, 1 - bb.maxZ, 1 - bb.minX, bb.maxY, 1 - bb.minZ); // S
|
||||
case 4:
|
||||
return new AABB(bb.minZ, bb.minY, 1 - bb.maxX, bb.maxZ, bb.maxY, 1 - bb.minX); // W
|
||||
case 5:
|
||||
return new AABB(1 - bb.maxZ, bb.minY, bb.minX, 1 - bb.minZ, bb.maxY, bb.maxX); // E
|
||||
}
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
||||
public static AABB[] getRotatedAABB(AABB[] bbs, Direction new_facing, boolean horizontal_rotation) {
|
||||
final AABB[] transformed = new AABB[bbs.length];
|
||||
for (int i = 0; i < bbs.length; ++i) transformed[i] = getRotatedAABB(bbs[i], new_facing, horizontal_rotation);
|
||||
return transformed;
|
||||
}
|
||||
|
||||
public static AABB getYRotatedAABB(AABB bb, int clockwise_90deg_steps) {
|
||||
final Direction[] direction_map = new Direction[]{Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST};
|
||||
return getRotatedAABB(bb, direction_map[(clockwise_90deg_steps + 4096) & 0x03], true);
|
||||
}
|
||||
|
||||
public static AABB[] getYRotatedAABB(AABB[] bbs, int clockwise_90deg_steps) {
|
||||
final AABB[] transformed = new AABB[bbs.length];
|
||||
for (int i = 0; i < bbs.length; ++i) transformed[i] = getYRotatedAABB(bbs[i], clockwise_90deg_steps);
|
||||
return transformed;
|
||||
}
|
||||
|
||||
public static AABB getMirroredAABB(AABB bb, Direction.Axis axis) {
|
||||
return switch (axis) {
|
||||
case X -> new AABB(1 - bb.maxX, bb.minY, bb.minZ, 1 - bb.minX, bb.maxY, bb.maxZ);
|
||||
case Y -> new AABB(bb.minX, 1 - bb.maxY, bb.minZ, bb.maxX, 1 - bb.minY, bb.maxZ);
|
||||
case Z -> new AABB(bb.minX, bb.minY, 1 - bb.maxZ, bb.maxX, bb.maxY, 1 - bb.minZ);
|
||||
};
|
||||
}
|
||||
|
||||
public static AABB[] getMirroredAABB(AABB[] bbs, Direction.Axis axis) {
|
||||
final AABB[] transformed = new AABB[bbs.length];
|
||||
for (int i = 0; i < bbs.length; ++i) transformed[i] = getMirroredAABB(bbs[i], axis);
|
||||
return transformed;
|
||||
}
|
||||
|
||||
public static VoxelShape getUnionShape(AABB... aabbs) {
|
||||
VoxelShape shape = Shapes.empty();
|
||||
for (AABB aabb : aabbs) shape = Shapes.joinUnoptimized(shape, Shapes.create(aabb), BooleanOp.OR);
|
||||
return shape;
|
||||
}
|
||||
|
||||
public static VoxelShape getUnionShape(AABB[]... aabb_list) {
|
||||
VoxelShape shape = Shapes.empty();
|
||||
for (AABB[] aabbs : aabb_list) {
|
||||
for (AABB aabb : aabbs) shape = Shapes.joinUnoptimized(shape, Shapes.create(aabb), BooleanOp.OR);
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
public static AABB[] getMappedAABB(AABB[] bbs, Function<AABB, AABB> mapper) {
|
||||
final AABB[] transformed = new AABB[bbs.length];
|
||||
for (int i = 0; i < bbs.length; ++i) transformed[i] = mapper.apply(bbs[i]);
|
||||
return transformed;
|
||||
}
|
||||
|
||||
public static final class BlockPosRange implements Iterable<BlockPos> {
|
||||
private final int x0, x1, y0, y1, z0, z1;
|
||||
|
||||
public BlockPosRange(int x0, int y0, int z0, int x1, int y1, int z1) {
|
||||
this.x0 = Math.min(x0, x1);
|
||||
this.x1 = Math.max(x0, x1);
|
||||
this.y0 = Math.min(y0, y1);
|
||||
this.y1 = Math.max(y0, y1);
|
||||
this.z0 = Math.min(z0, z1);
|
||||
this.z1 = Math.max(z0, z1);
|
||||
}
|
||||
|
||||
public static BlockPosRange of(AABB range) {
|
||||
return new BlockPosRange(
|
||||
(int) Math.floor(range.minX),
|
||||
(int) Math.floor(range.minY),
|
||||
(int) Math.floor(range.minZ),
|
||||
(int) Math.floor(range.maxX - .0625),
|
||||
(int) Math.floor(range.maxY - .0625),
|
||||
(int) Math.floor(range.maxZ - .0625)
|
||||
);
|
||||
}
|
||||
|
||||
public int getXSize() {
|
||||
return x1 - x0 + 1;
|
||||
}
|
||||
|
||||
public int getYSize() {
|
||||
return y1 - y0 + 1;
|
||||
}
|
||||
|
||||
public int getZSize() {
|
||||
return z1 - z0 + 1;
|
||||
}
|
||||
|
||||
public int getArea() {
|
||||
return getXSize() * getZSize();
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return getYSize();
|
||||
}
|
||||
|
||||
public int getVolume() {
|
||||
return getXSize() * getYSize() * getZSize();
|
||||
}
|
||||
|
||||
public BlockPos byXZYIndex(int xyz_index) {
|
||||
final int xsz = getXSize(), ysz = getYSize(), zsz = getZSize();
|
||||
xyz_index = xyz_index % (xsz * ysz * zsz);
|
||||
final int y = xyz_index / (xsz * zsz);
|
||||
xyz_index -= y * (xsz * zsz);
|
||||
final int z = xyz_index / xsz;
|
||||
xyz_index -= z * xsz;
|
||||
final int x = xyz_index;
|
||||
return new BlockPos(x0 + x, y0 + y, z0 + z);
|
||||
}
|
||||
|
||||
public BlockPos byXZIndex(int xz_index, int y_offset) {
|
||||
final int xsz = getXSize(), zsz = getZSize();
|
||||
xz_index = xz_index % (xsz * zsz);
|
||||
final int z = xz_index / xsz;
|
||||
xz_index -= z * xsz;
|
||||
final int x = xz_index;
|
||||
return new BlockPos(x0 + x, y0 + y_offset, z0 + z);
|
||||
}
|
||||
|
||||
public static final class BlockRangeIterator implements Iterator<BlockPos> {
|
||||
private final BlockPosRange range_;
|
||||
private int x, y, z;
|
||||
|
||||
public BlockRangeIterator(BlockPosRange range) {
|
||||
range_ = range;
|
||||
x = range.x0;
|
||||
y = range.y0;
|
||||
z = range.z0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return (z <= range_.z1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
final BlockPos pos = new BlockPos(x, y, z);
|
||||
++x;
|
||||
if (x > range_.x1) {
|
||||
x = range_.x0;
|
||||
++y;
|
||||
if (y > range_.y1) {
|
||||
y = range_.y0;
|
||||
++z;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockRangeIterator iterator() {
|
||||
return new BlockRangeIterator(this);
|
||||
}
|
||||
|
||||
public Stream<BlockPos> stream() {
|
||||
return java.util.stream.StreamSupport.stream(spliterator(), false);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// JAR resource related
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static String loadResourceText(InputStream is) {
|
||||
try {
|
||||
if (is == null) return "";
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
|
||||
return br.lines().collect(Collectors.joining("\n"));
|
||||
} catch (Throwable e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static String loadResourceText(String path) {
|
||||
return loadResourceText(Auxiliaries.class.getResourceAsStream(path));
|
||||
}
|
||||
|
||||
public static void logGitVersion(String mod_name) {
|
||||
try {
|
||||
// Done during construction to have an exact version in case of a crash while registering.
|
||||
String version = Auxiliaries.loadResourceText("/.gitversion-" + modid).trim();
|
||||
logInfo(mod_name + ((version.isEmpty()) ? (" (dev build)") : (" GIT id #" + version)) + ".");
|
||||
} catch (Throwable e) {
|
||||
// (void)e; well, then not. Priority is not to get unneeded crashes because of version logging.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class Containers {
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Slots
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class StorageSlot extends Slot {
|
||||
protected BiConsumer<ItemStack, ItemStack> slot_change_action_ = (oldStack, newStack) -> {
|
||||
};
|
||||
protected int stack_limit_ = 64;
|
||||
public boolean enabled = true;
|
||||
|
||||
public StorageSlot(Container inventory, int index, int x, int y) {
|
||||
super(inventory, index, x, y);
|
||||
}
|
||||
|
||||
public StorageSlot setSlotStackLimit(int limit) {
|
||||
stack_limit_ = Mth.clamp(limit, 1, 64);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxStackSize() {
|
||||
return stack_limit_;
|
||||
}
|
||||
|
||||
public StorageSlot setSlotChangeNotifier(BiConsumer<ItemStack, ItemStack> action) {
|
||||
slot_change_action_ = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQuickCraft(ItemStack oldStack, ItemStack newStack) {
|
||||
slot_change_action_.accept(oldStack, newStack);
|
||||
} // no crafting trigger
|
||||
|
||||
@Override
|
||||
public void set(ItemStack stack) {
|
||||
if (stack.is(getItem().getItem())) {
|
||||
super.set(stack);
|
||||
} else {
|
||||
final ItemStack before = getItem().copy();
|
||||
super.set(stack); // whatever this does else next to setting inventory.
|
||||
slot_change_action_.accept(before, getItem());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPlace(ItemStack stack) {
|
||||
return enabled && this.container.canPlaceItem(this.getSlotIndex(), stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize(ItemStack stack) {
|
||||
return Math.min(getMaxStackSize(), stack_limit_);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public boolean isActive() {
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LockedSlot extends Slot {
|
||||
protected int stack_limit_ = 64;
|
||||
public boolean enabled = true;
|
||||
|
||||
public LockedSlot(Container inventory, int index, int x, int y) {
|
||||
super(inventory, index, x, y);
|
||||
}
|
||||
|
||||
public LockedSlot setSlotStackLimit(int limit) {
|
||||
stack_limit_ = Mth.clamp(limit, 1, 64);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxStackSize() {
|
||||
return stack_limit_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize(ItemStack stack) {
|
||||
return Math.min(getMaxStackSize(), stack_limit_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPlace(ItemStack stack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPickup(Player player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public boolean isActive() {
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static class HiddenSlot extends Slot {
|
||||
public HiddenSlot(Container inventory, int index) {
|
||||
super(inventory, index, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxStackSize(ItemStack stack) {
|
||||
return getMaxStackSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPlace(ItemStack stack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPickup(Player player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public boolean isActive() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,440 +0,0 @@
|
|||
/*
|
||||
* @file Recipes.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Recipe utility functionality.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.player.StackedContents;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.CraftingContainer;
|
||||
import net.minecraft.world.item.EnchantedBookItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.*;
|
||||
import net.minecraft.world.item.enchantment.Enchantment;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentInstance;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.ComposterBlock;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.brewing.BrewingRecipeRegistry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
|
||||
public class Crafting {
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a Crafting recipe by registry name.
|
||||
*/
|
||||
public static Optional<CraftingRecipe> getCraftingRecipe(Level world, ResourceLocation recipe_id) {
|
||||
Recipe<?> recipe = world.getRecipeManager().byKey(recipe_id).orElse(null);
|
||||
return (recipe instanceof CraftingRecipe) ? Optional.of((CraftingRecipe) recipe) : Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of matching recipes by the first N slots (crafting grid slots) of the given inventory.
|
||||
*/
|
||||
public static List<CraftingRecipe> get3x3CraftingRecipes(Level world, Container crafting_grid_slots) {
|
||||
return CraftingGrid.instance3x3.getRecipes(world, crafting_grid_slots);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a recipe by the first N slots (crafting grid slots).
|
||||
*/
|
||||
public static Optional<CraftingRecipe> get3x3CraftingRecipe(Level world, Container crafting_grid_slots) {
|
||||
return get3x3CraftingRecipes(world, crafting_grid_slots).stream().findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result item of the recipe with the given grid layout.
|
||||
*/
|
||||
public static ItemStack get3x3CraftingResult(Level world, Container grid, CraftingRecipe recipe) {
|
||||
return CraftingGrid.instance3x3.getCraftingResult(world, grid, recipe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the items remaining in the grid after crafting 3x3.
|
||||
*/
|
||||
public static List<ItemStack> get3x3RemainingItems(Level world, Container grid, CraftingRecipe recipe) {
|
||||
return CraftingGrid.instance3x3.getRemainingItems(world, grid, recipe);
|
||||
}
|
||||
|
||||
public static List<ItemStack> get3x3Placement(Level world, CraftingRecipe recipe, Container item_inventory, @Nullable Container crafting_grid) {
|
||||
final int width = 3;
|
||||
final int height = 3;
|
||||
if (!recipe.canCraftInDimensions(width, height)) return Collections.emptyList();
|
||||
List<ItemStack> used = new ArrayList<>(); //NonNullList.withSize(width*height);
|
||||
for (int i = width * height; i > 0; --i) used.add(ItemStack.EMPTY);
|
||||
Container check_inventory = Inventories.copyOf(item_inventory);
|
||||
Inventories.InventoryRange source = new Inventories.InventoryRange(check_inventory);
|
||||
final List<Ingredient> ingredients = recipe.getIngredients();
|
||||
final List<ItemStack> preferred = new ArrayList<>(width * height);
|
||||
if (crafting_grid != null) {
|
||||
for (int i = 0; i < crafting_grid.getContainerSize(); ++i) {
|
||||
ItemStack stack = crafting_grid.getItem(i);
|
||||
if (stack.isEmpty()) continue;
|
||||
stack = stack.copy();
|
||||
stack.setCount(1);
|
||||
if (!source.extract(stack).isEmpty()) preferred.add(stack);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < ingredients.size(); ++i) {
|
||||
final Ingredient ingredient = ingredients.get(i);
|
||||
if (ingredient == Ingredient.EMPTY) continue;
|
||||
ItemStack stack = preferred.stream().filter(ingredient).findFirst().orElse(ItemStack.EMPTY);
|
||||
if (!stack.isEmpty()) {
|
||||
preferred.remove(stack);
|
||||
} else {
|
||||
stack = source.stream().filter(ingredient).findFirst().orElse(ItemStack.EMPTY);
|
||||
if (stack.isEmpty()) return Collections.emptyList();
|
||||
stack = stack.copy();
|
||||
stack.setCount(1);
|
||||
if (source.extract(stack).isEmpty()) return Collections.emptyList();
|
||||
}
|
||||
used.set(i, stack);
|
||||
}
|
||||
if (recipe instanceof ShapedRecipe shaped) {
|
||||
List<ItemStack> placement = NonNullList.withSize(width * height, ItemStack.EMPTY);
|
||||
for (int row = 0; row < shaped.getRecipeHeight(); ++row) {
|
||||
for (int col = 0; col < shaped.getRecipeWidth(); ++col) {
|
||||
placement.set(width * row + col, used.get(row * shaped.getRecipeWidth() + col));
|
||||
}
|
||||
}
|
||||
return placement;
|
||||
} else {
|
||||
return used;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recipe for a given input stack to smelt, null if there is no recipe
|
||||
* for the given type (SMELTING,BLASTING,SMOKING, etc).
|
||||
*/
|
||||
public static <T extends Recipe<?>> Optional<AbstractCookingRecipe> getFurnaceRecipe(RecipeType<T> recipe_type, Level world, ItemStack input_stack) {
|
||||
if (input_stack.isEmpty()) {
|
||||
return Optional.empty();
|
||||
} else if (recipe_type == RecipeType.SMELTING) {
|
||||
SimpleContainer inventory = new SimpleContainer(3);
|
||||
inventory.setItem(0, input_stack);
|
||||
SmeltingRecipe recipe = world.getRecipeManager().getRecipeFor(RecipeType.SMELTING, inventory, world).orElse(null);
|
||||
return (recipe == null) ? Optional.empty() : Optional.of(recipe);
|
||||
} else if (recipe_type == RecipeType.BLASTING) {
|
||||
SimpleContainer inventory = new SimpleContainer(3);
|
||||
inventory.setItem(0, input_stack);
|
||||
BlastingRecipe recipe = world.getRecipeManager().getRecipeFor(RecipeType.BLASTING, inventory, world).orElse(null);
|
||||
return (recipe == null) ? Optional.empty() : Optional.of(recipe);
|
||||
} else if (recipe_type == RecipeType.SMOKING) {
|
||||
SimpleContainer inventory = new SimpleContainer(3);
|
||||
inventory.setItem(0, input_stack);
|
||||
SmokingRecipe recipe = world.getRecipeManager().getRecipeFor(RecipeType.SMOKING, inventory, world).orElse(null);
|
||||
return (recipe == null) ? Optional.empty() : Optional.of(recipe);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static <T extends Recipe<?>> int getSmeltingTimeNeeded(RecipeType<T> recipe_type, Level world, ItemStack stack) {
|
||||
if (stack.isEmpty()) return 0;
|
||||
final int t = getFurnaceRecipe(recipe_type, world, stack).map((AbstractCookingRecipe::getCookingTime)).orElse(0);
|
||||
return (t <= 0) ? 200 : t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the burn time of an item when used as fuel, 0 if it is no fuel.
|
||||
*/
|
||||
public static int getFuelBurntime(Level world, ItemStack stack) {
|
||||
if (stack.isEmpty()) return 0;
|
||||
int t = ForgeHooks.getBurnTime(stack, null);
|
||||
return Math.max(t, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an item can be used as fuel.
|
||||
*/
|
||||
public static boolean isFuel(Level world, ItemStack stack) {
|
||||
return (getFuelBurntime(world, stack) > 0) || (stack.getItem() == Items.LAVA_BUCKET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns burntime and remaining stack then the item shall be used as fuel.
|
||||
*/
|
||||
public static Tuple<Integer, ItemStack> consumeFuel(Level world, ItemStack stack) {
|
||||
if (stack.isEmpty()) return new Tuple<>(0, stack);
|
||||
int burnime = getFuelBurntime(world, stack);
|
||||
if ((stack.getItem() == Items.LAVA_BUCKET)) {
|
||||
if (burnime <= 0) burnime = 1000 * 20;
|
||||
return new Tuple<>(burnime, new ItemStack(Items.BUCKET));
|
||||
} else if (burnime <= 0) {
|
||||
return new Tuple<>(0, stack);
|
||||
} else {
|
||||
ItemStack left_over = stack.copy();
|
||||
left_over.shrink(1);
|
||||
return new Tuple<>(burnime, left_over);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the item can be used as brewing fuel.
|
||||
*/
|
||||
public static boolean isBrewingFuel(Level world, ItemStack stack) {
|
||||
return (stack.getItem() == Items.BLAZE_POWDER) || (stack.getItem() == Items.BLAZE_ROD);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if the item can be used as brewing ingredient.
|
||||
*/
|
||||
public static boolean isBrewingIngredient(Level world, ItemStack stack) {
|
||||
return BrewingRecipeRegistry.isValidIngredient(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the item can be used as brewing bottle.
|
||||
*/
|
||||
public static boolean isBrewingInput(Level world, ItemStack stack) {
|
||||
return BrewingRecipeRegistry.isValidInput(stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the burn time for brewing of the given stack.
|
||||
*/
|
||||
public static int getBrewingFuelBurntime(Level world, ItemStack stack) {
|
||||
if (stack.isEmpty()) return 0;
|
||||
if (stack.getItem() == Items.BLAZE_POWDER) return (400 * 20);
|
||||
if (stack.getItem() == Items.BLAZE_ROD) return (400 * 40);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns brewing burn time and remaining stack if the item shall be used as fuel.
|
||||
*/
|
||||
public static Tuple<Integer, ItemStack> consumeBrewingFuel(Level world, ItemStack stack) {
|
||||
int burntime = getBrewingFuelBurntime(world, stack);
|
||||
if (burntime <= 0) return new Tuple<>(0, stack.copy());
|
||||
stack = stack.copy();
|
||||
stack.shrink(1);
|
||||
return new Tuple<>(burntime, stack.isEmpty() ? ItemStack.EMPTY : stack);
|
||||
}
|
||||
|
||||
public static double getCompostingChance(ItemStack stack) {
|
||||
return ComposterBlock.COMPOSTABLES.getOrDefault(stack.getItem(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enchtments bound to the given stack.
|
||||
*/
|
||||
public static Map<Enchantment, Integer> getEnchantmentsOnItem(Level world, ItemStack stack) {
|
||||
return (stack.isEmpty() || (stack.getTag() == null)) ? Collections.emptyMap() : EnchantmentHelper.getEnchantments(stack);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns an enchanted book with the given enchantment, emtpy stack if not applicable.
|
||||
*/
|
||||
public static ItemStack getEnchantmentBook(Level world, Enchantment enchantment, int level) {
|
||||
return ((!enchantment.isAllowedOnBooks()) || (level <= 0)) ? ItemStack.EMPTY : EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, level));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the accumulated repair cost for the given enchantments.
|
||||
*/
|
||||
public static int getEnchantmentRepairCost(Level world, Map<Enchantment, Integer> enchantments) {
|
||||
int repair_cost = 0;
|
||||
for (Map.Entry<Enchantment, Integer> e : enchantments.entrySet())
|
||||
repair_cost = repair_cost * 2 + 1; // @see: RepairContainer.getNewRepairCost()
|
||||
return repair_cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trys to add an enchtment to the given stack, returns boolean success.
|
||||
*/
|
||||
public static boolean addEnchantmentOnItem(Level world, ItemStack stack, Enchantment enchantment, int level) {
|
||||
if (stack.isEmpty() || (level <= 0) || (!stack.isEnchantable()) || (level >= enchantment.getMaxLevel()))
|
||||
return false;
|
||||
final Map<Enchantment, Integer> on_item = getEnchantmentsOnItem(world, stack);
|
||||
if (on_item.keySet().stream().anyMatch(ench -> ench.isCompatibleWith(enchantment))) return false;
|
||||
final ItemStack book = EnchantedBookItem.createForEnchantment(new EnchantmentInstance(enchantment, level));
|
||||
if ((!(stack.isBookEnchantable(book) && enchantment.isAllowedOnBooks())) && (!stack.canApplyAtEnchantingTable(enchantment)) && (!enchantment.canEnchant(stack)))
|
||||
return false;
|
||||
final int existing_level = on_item.getOrDefault(enchantment, 0);
|
||||
if (existing_level > 0) level = Mth.clamp(level + existing_level, 1, enchantment.getMaxLevel());
|
||||
on_item.put(enchantment, level);
|
||||
EnchantmentHelper.setEnchantments(on_item, stack);
|
||||
stack.setRepairCost(getEnchantmentRepairCost(world, on_item));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes enchantments from a stack, returns the removed enchantments.
|
||||
*/
|
||||
public static Map<Enchantment, Integer> removeEnchantmentsOnItem(Level world, ItemStack stack, BiPredicate<Enchantment, Integer> filter) {
|
||||
if (stack.isEmpty()) return Collections.emptyMap();
|
||||
final Map<Enchantment, Integer> on_item = getEnchantmentsOnItem(world, stack);
|
||||
final Map<Enchantment, Integer> removed = new HashMap<>();
|
||||
for (Map.Entry<Enchantment, Integer> e : on_item.entrySet()) {
|
||||
if (filter.test(e.getKey(), e.getValue())) {
|
||||
removed.put(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
for (Enchantment e : removed.keySet()) {
|
||||
on_item.remove(e);
|
||||
}
|
||||
EnchantmentHelper.setEnchantments(on_item, stack);
|
||||
stack.setRepairCost(getEnchantmentRepairCost(world, on_item));
|
||||
return removed;
|
||||
}
|
||||
|
||||
public static final class CraftingGrid implements CraftingContainer {
|
||||
private static final CraftingGrid instance3x3 = new CraftingGrid(3, 3);
|
||||
|
||||
final int _width;
|
||||
|
||||
private CraftingGrid(int width, int height) {
|
||||
_width=width;
|
||||
}
|
||||
|
||||
private void fill(Container grid) {
|
||||
for (int i = 0; i < getContainerSize(); ++i)
|
||||
setItem(i, i >= grid.getContainerSize() ? ItemStack.EMPTY : grid.getItem(i));
|
||||
}
|
||||
|
||||
public List<CraftingRecipe> getRecipes(Level world, Container grid) {
|
||||
fill(grid);
|
||||
return world.getRecipeManager().getRecipesFor(RecipeType.CRAFTING, this, world);
|
||||
}
|
||||
|
||||
public List<ItemStack> getRemainingItems(Level world, Container grid, CraftingRecipe recipe) {
|
||||
fill(grid);
|
||||
return recipe.getRemainingItems(this);
|
||||
}
|
||||
|
||||
public ItemStack getCraftingResult(Level world, Container grid, CraftingRecipe recipe) {
|
||||
fill(grid);
|
||||
return recipe.assemble(this, world.registryAccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return _width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> getItems() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItem(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeItemNoUpdate(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(int i, ItemStack itemStack) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearContent() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillStackedContents(StackedContents stackedContents) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static final class BrewingOutput {
|
||||
public static final int DEFAULT_BREWING_TIME = 400;
|
||||
public static final BrewingOutput EMPTY = new BrewingOutput(ItemStack.EMPTY, new SimpleContainer(1), new SimpleContainer(1), 0, 0, DEFAULT_BREWING_TIME);
|
||||
public final ItemStack item;
|
||||
public final Container potionInventory;
|
||||
public final Container ingredientInventory;
|
||||
public final int potionSlot;
|
||||
public final int ingredientSlot;
|
||||
public final int brewTime;
|
||||
|
||||
public BrewingOutput(ItemStack output_potion, Container potion_inventory, Container ingredient_inventory, int potion_slot, int ingredient_slot, int time_needed) {
|
||||
item = output_potion;
|
||||
potionInventory = potion_inventory;
|
||||
ingredientInventory = ingredient_inventory;
|
||||
potionSlot = potion_slot;
|
||||
ingredientSlot = ingredient_slot;
|
||||
brewTime = time_needed;
|
||||
}
|
||||
|
||||
public static BrewingOutput find(Level world, Container potion_inventory, Container ingredient_inventory) {
|
||||
for (int potion_slot = 0; potion_slot < potion_inventory.getContainerSize(); ++potion_slot) {
|
||||
final ItemStack pstack = potion_inventory.getItem(potion_slot);
|
||||
if (!isBrewingInput(world, pstack)) continue;
|
||||
for (int ingredient_slot = 0; ingredient_slot < ingredient_inventory.getContainerSize(); ++ingredient_slot) {
|
||||
final ItemStack istack = ingredient_inventory.getItem(ingredient_slot);
|
||||
if ((!isBrewingIngredient(world, istack)) || (ingredient_slot == potion_slot) || (isBrewingFuel(world, istack)))
|
||||
continue;
|
||||
final ItemStack result = BrewingRecipeRegistry.getOutput(pstack, istack);
|
||||
if (result.isEmpty()) continue;
|
||||
return new BrewingOutput(result, potion_inventory, ingredient_inventory, potion_slot, ingredient_slot, DEFAULT_BREWING_TIME);
|
||||
}
|
||||
}
|
||||
return BrewingOutput.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,485 +0,0 @@
|
|||
/*
|
||||
* @file Fluidics.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* General fluid handling functionality.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidActionResult;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidUtil;
|
||||
import net.minecraftforge.fluids.IFluidTank;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
|
||||
public class Fluidics {
|
||||
public static class SingleTankFluidHandler implements IFluidHandler {
|
||||
private final IFluidTank tank_;
|
||||
|
||||
public SingleTankFluidHandler(IFluidTank tank) {
|
||||
tank_ = tank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTanks() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack getFluidInTank(int tank) {
|
||||
return tank_.getFluid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankCapacity(int tank) {
|
||||
return tank_.getCapacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
|
||||
return tank_.isFluidValid(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, FluidAction action) {
|
||||
return tank_.fill(resource, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||
return tank_.drain(resource, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||
return tank_.drain(maxDrain, action);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SingleTankOutputFluidHandler implements IFluidHandler {
|
||||
private final IFluidTank tank_;
|
||||
|
||||
public SingleTankOutputFluidHandler(IFluidTank tank) {
|
||||
tank_ = tank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTanks() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack getFluidInTank(int tank) {
|
||||
return tank_.getFluid().copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankCapacity(int tank) {
|
||||
return tank_.getCapacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack resource, FluidAction action) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||
return tank_.drain(resource, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||
return tank_.drain(maxDrain, action);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Tank implements IFluidTank {
|
||||
private Predicate<FluidStack> validator_ = ((e) -> true);
|
||||
private BiConsumer<Tank, Integer> interaction_notifier_ = ((tank, diff) -> {
|
||||
});
|
||||
private FluidStack fluid_ = FluidStack.EMPTY;
|
||||
private int capacity_;
|
||||
private int fill_rate_;
|
||||
private int drain_rate_;
|
||||
|
||||
public Tank(int capacity) {
|
||||
this(capacity, capacity, capacity);
|
||||
}
|
||||
|
||||
public Tank(int capacity, int fill_rate, int drain_rate) {
|
||||
this(capacity, fill_rate, drain_rate, e -> true);
|
||||
}
|
||||
|
||||
public Tank(int capacity, int fill_rate, int drain_rate, Predicate<FluidStack> validator) {
|
||||
capacity_ = capacity;
|
||||
setMaxFillRate(fill_rate);
|
||||
setMaxDrainRate(drain_rate);
|
||||
setValidator(validator);
|
||||
}
|
||||
|
||||
public Tank load(CompoundTag nbt) {
|
||||
if (nbt.contains("tank", Tag.TAG_COMPOUND)) {
|
||||
setFluid(FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
|
||||
} else {
|
||||
clear();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
if (!isEmpty()) {
|
||||
nbt.put("tank", fluid_.writeToNBT(new CompoundTag()));
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
clear();
|
||||
}
|
||||
|
||||
public Tank clear() {
|
||||
setFluid(null);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCapacity() {
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
public Tank setCapacity(int capacity) {
|
||||
capacity_ = capacity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxDrainRate() {
|
||||
return drain_rate_;
|
||||
}
|
||||
|
||||
public Tank setMaxDrainRate(int rate) {
|
||||
drain_rate_ = Mth.clamp(rate, 0, capacity_);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMaxFillRate() {
|
||||
return fill_rate_;
|
||||
}
|
||||
|
||||
public Tank setMaxFillRate(int rate) {
|
||||
fill_rate_ = Mth.clamp(rate, 0, capacity_);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Tank setValidator(Predicate<FluidStack> validator) {
|
||||
validator_ = (validator != null) ? validator : ((e) -> true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Tank setInteractionNotifier(BiConsumer<Tank, Integer> notifier) {
|
||||
interaction_notifier_ = (notifier != null) ? notifier : ((tank, diff) -> {
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public LazyOptional<IFluidHandler> createFluidHandler() {
|
||||
return LazyOptional.of(() -> new Fluidics.SingleTankFluidHandler(this));
|
||||
}
|
||||
|
||||
public LazyOptional<IFluidHandler> createOutputFluidHandler() {
|
||||
return LazyOptional.of(() -> new Fluidics.SingleTankOutputFluidHandler(this));
|
||||
}
|
||||
|
||||
// IFluidTank ------------------------------------------------------------------------------------
|
||||
|
||||
@Nonnull
|
||||
public FluidStack getFluid() {
|
||||
return fluid_;
|
||||
}
|
||||
|
||||
public void setFluid(@Nullable FluidStack stack) {
|
||||
fluid_ = (stack == null) ? FluidStack.EMPTY : stack;
|
||||
}
|
||||
|
||||
public int getFluidAmount() {
|
||||
return fluid_.getAmount();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return fluid_.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return getFluidAmount() >= getCapacity();
|
||||
}
|
||||
|
||||
public boolean isFluidValid(FluidStack stack) {
|
||||
return validator_.test(stack);
|
||||
}
|
||||
|
||||
public boolean isFluidEqual(FluidStack stack) {
|
||||
return (stack == null) ? (fluid_.isEmpty()) : fluid_.isFluidEqual(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack fs, FluidAction action) {
|
||||
if ((fs == null) || fs.isEmpty() || (!isFluidValid(fs))) {
|
||||
return 0;
|
||||
} else if (action.simulate()) {
|
||||
if (fluid_.isEmpty()) return Math.min(capacity_, fs.getAmount());
|
||||
if (!fluid_.isFluidEqual(fs)) return 0;
|
||||
return Math.min(capacity_ - fluid_.getAmount(), fs.getAmount());
|
||||
} else if (fluid_.isEmpty()) {
|
||||
fluid_ = new FluidStack(fs, Math.min(capacity_, fs.getAmount()));
|
||||
return fluid_.getAmount();
|
||||
} else if (!fluid_.isFluidEqual(fs)) {
|
||||
return 0;
|
||||
} else {
|
||||
int amount = capacity_ - fluid_.getAmount();
|
||||
if (fs.getAmount() < amount) {
|
||||
fluid_.grow(fs.getAmount());
|
||||
amount = fs.getAmount();
|
||||
} else {
|
||||
fluid_.setAmount(capacity_);
|
||||
}
|
||||
if (amount != 0) interaction_notifier_.accept(this, amount);
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public FluidStack drain(int maxDrain) {
|
||||
return drain(maxDrain, FluidAction.EXECUTE);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack drain(FluidStack fs, FluidAction action) {
|
||||
return ((fs.isEmpty()) || (!fs.isFluidEqual(fluid_))) ? FluidStack.EMPTY : drain(fs.getAmount(), action);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||
final int amount = Math.min(fluid_.getAmount(), maxDrain);
|
||||
final FluidStack stack = new FluidStack(fluid_, amount);
|
||||
if ((amount > 0) && action.execute()) {
|
||||
fluid_.shrink(amount);
|
||||
if (fluid_.isEmpty()) fluid_ = FluidStack.EMPTY;
|
||||
if (amount != 0) interaction_notifier_.accept(this, -amount);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static @Nullable IFluidHandler handler(Level world, BlockPos pos, @Nullable Direction side) {
|
||||
return FluidUtil.getFluidHandler(world, pos, side).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills or drains items with fluid handlers from or into tile blocks with fluid handlers.
|
||||
*/
|
||||
public static boolean manualFluidHandlerInteraction(Level world, BlockPos pos, @Nullable Direction side, Player player, InteractionHand hand) {
|
||||
return manualTrackedFluidHandlerInteraction(world, pos, side, player, hand) != null;
|
||||
}
|
||||
|
||||
public static boolean manualFluidHandlerInteraction(Player player, InteractionHand hand, IFluidHandler handler) {
|
||||
return FluidUtil.interactWithFluidHandler(player, hand, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills or drains items with fluid handlers from or into tile blocks with fluid handlers.
|
||||
* Returns the fluid and (possibly negative) amount that transferred from the item into the block.
|
||||
*/
|
||||
public static @Nullable Tuple<Fluid, Integer> manualTrackedFluidHandlerInteraction(Level world, BlockPos pos, @Nullable Direction side, Player player, InteractionHand hand) {
|
||||
if (world.isClientSide()) return null;
|
||||
final ItemStack held = player.getItemInHand(hand);
|
||||
if (held.isEmpty()) return null;
|
||||
final IFluidHandler fh = handler(world, pos, side);
|
||||
if (fh == null) return null;
|
||||
final IItemHandler ih = player.getCapability(ForgeCapabilities.ITEM_HANDLER).orElse(null);
|
||||
if (ih == null) return null;
|
||||
FluidActionResult far = FluidUtil.tryFillContainerAndStow(held, fh, ih, Integer.MAX_VALUE, player, true);
|
||||
if (!far.isSuccess()) far = FluidUtil.tryEmptyContainerAndStow(held, fh, ih, Integer.MAX_VALUE, player, true);
|
||||
if (!far.isSuccess()) return null;
|
||||
final ItemStack rstack = far.getResult().copy();
|
||||
player.setItemInHand(hand, far.getResult());
|
||||
final IFluidHandler fh_before = FluidUtil.getFluidHandler(held).orElse(null);
|
||||
final IFluidHandler fh_after = FluidUtil.getFluidHandler(rstack).orElse(null);
|
||||
if ((fh_before == null) || (fh_after == null) || (fh_after.getTanks() != fh_before.getTanks()))
|
||||
return null; // should not be, but y'never know.
|
||||
for (int i = 0; i < fh_before.getTanks(); ++i) {
|
||||
final int vol_before = fh_before.getFluidInTank(i).getAmount();
|
||||
final int vol_after = fh_after.getFluidInTank(i).getAmount();
|
||||
if (vol_before != vol_after) {
|
||||
return new Tuple<>(
|
||||
(vol_before > 0) ? (fh_before.getFluidInTank(i).getFluid()) : (fh_after.getFluidInTank(i).getFluid()),
|
||||
(vol_before - vol_after)
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean manualFluidHandlerInteraction(Player player, InteractionHand hand, Level world, BlockPos pos, @Nullable Direction side) {
|
||||
return FluidUtil.interactWithFluidHandler(player, hand, world, pos, side);
|
||||
}
|
||||
|
||||
public static int fill(Level world, BlockPos pos, Direction side, FluidStack fs, FluidAction action) {
|
||||
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos, side).orElse(null);
|
||||
return (fh == null) ? (0) : (fh.fill(fs, action));
|
||||
}
|
||||
|
||||
public static int fill(Level world, BlockPos pos, Direction side, FluidStack fs) {
|
||||
return fill(world, pos, side, fs, FluidAction.EXECUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fluid tank access when itemized.
|
||||
*/
|
||||
public static class FluidContainerItemCapabilityWrapper implements IFluidHandlerItem, ICapabilityProvider {
|
||||
private final LazyOptional<IFluidHandlerItem> handler_ = LazyOptional.of(() -> this);
|
||||
private final Function<ItemStack, CompoundTag> nbt_getter_;
|
||||
private final BiConsumer<ItemStack, CompoundTag> nbt_setter_;
|
||||
private final Predicate<FluidStack> validator_;
|
||||
private final ItemStack container_;
|
||||
private final int capacity_;
|
||||
private final int transfer_rate_;
|
||||
|
||||
public FluidContainerItemCapabilityWrapper(ItemStack container, int capacity, int transfer_rate,
|
||||
Function<ItemStack, CompoundTag> nbt_getter,
|
||||
BiConsumer<ItemStack, CompoundTag> nbt_setter,
|
||||
Predicate<FluidStack> validator) {
|
||||
container_ = container;
|
||||
capacity_ = capacity;
|
||||
transfer_rate_ = transfer_rate;
|
||||
nbt_getter_ = nbt_getter;
|
||||
nbt_setter_ = nbt_setter;
|
||||
validator_ = (validator != null) ? validator : (e -> true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(Capability<T> capability, @Nullable Direction side) {
|
||||
return (capability == ForgeCapabilities.FLUID_HANDLER) ? handler_.cast() : LazyOptional.empty();
|
||||
}
|
||||
|
||||
protected FluidStack readnbt() {
|
||||
final CompoundTag nbt = nbt_getter_.apply(container_);
|
||||
return ((nbt == null) || (nbt.isEmpty())) ? FluidStack.EMPTY : FluidStack.loadFluidStackFromNBT(nbt);
|
||||
}
|
||||
|
||||
protected void writenbt(FluidStack fs) {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
if (!fs.isEmpty()) fs.writeToNBT(nbt);
|
||||
nbt_setter_.accept(container_, nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getContainer() {
|
||||
return container_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTanks() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack getFluidInTank(int tank) {
|
||||
return readnbt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTankCapacity(int tank) {
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFluidValid(int tank, FluidStack fs) {
|
||||
return isFluidValid(fs);
|
||||
}
|
||||
|
||||
public boolean isFluidValid(FluidStack fs) {
|
||||
return validator_.test(fs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(FluidStack fs, FluidAction action) {
|
||||
if ((fs.isEmpty()) || (!isFluidValid(fs) || (container_.getCount() != 1))) return 0;
|
||||
FluidStack tank = readnbt();
|
||||
final int amount = Math.min(Math.min(fs.getAmount(), transfer_rate_), capacity_ - tank.getAmount());
|
||||
if (amount <= 0) return 0;
|
||||
if (tank.isEmpty()) {
|
||||
if (action.execute()) {
|
||||
tank = new FluidStack(fs.getFluid(), amount, fs.getTag());
|
||||
writenbt(tank);
|
||||
}
|
||||
} else {
|
||||
if (!tank.isFluidEqual(fs)) {
|
||||
return 0;
|
||||
} else if (action.execute()) {
|
||||
tank.grow(amount);
|
||||
writenbt(tank);
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(FluidStack fs, FluidAction action) {
|
||||
if ((fs.isEmpty()) || (container_.getCount() != 1)) return FluidStack.EMPTY;
|
||||
final FluidStack tank = readnbt();
|
||||
if ((!tank.isEmpty()) && (!tank.isFluidEqual(fs))) return FluidStack.EMPTY;
|
||||
return drain(fs.getAmount(), action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(int max, FluidAction action) {
|
||||
if ((max <= 0) || (container_.getCount() != 1)) return FluidStack.EMPTY;
|
||||
FluidStack tank = readnbt();
|
||||
if (tank.isEmpty()) return FluidStack.EMPTY;
|
||||
final int amount = Math.min(Math.min(tank.getAmount(), max), transfer_rate_);
|
||||
final FluidStack fs = tank.copy();
|
||||
fs.setAmount(amount);
|
||||
if (action.execute()) {
|
||||
tank.shrink(amount);
|
||||
writenbt(tank);
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,466 +0,0 @@
|
|||
/*
|
||||
* @file Guis.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Gui Wrappers and Widgets.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.sounds.SoundManager;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
public class Guis {
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Gui base
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static abstract class ContainerGui<T extends AbstractContainerMenu> extends AbstractContainerScreen<T> {
|
||||
protected final ResourceLocation background_image_;
|
||||
protected final Player player_;
|
||||
protected final Guis.BackgroundImage gui_background_;
|
||||
protected final TooltipDisplay tooltip_ = new TooltipDisplay();
|
||||
|
||||
public ContainerGui(T menu, Inventory player_inv, Component title, String background_image, int width, int height) {
|
||||
super(menu, player_inv, title);
|
||||
this.background_image_ = new ResourceLocation(Auxiliaries.modid(), background_image);
|
||||
this.player_ = player_inv.player;
|
||||
this.imageWidth = width;
|
||||
this.imageHeight = height;
|
||||
gui_background_ = new Guis.BackgroundImage(background_image_, width, height, Coord2d.ORIGIN);
|
||||
}
|
||||
|
||||
public ContainerGui(T menu, Inventory player_inv, Component title, String background_image) {
|
||||
super(menu, player_inv, title);
|
||||
this.background_image_ = new ResourceLocation(Auxiliaries.modid(), background_image);
|
||||
this.player_ = player_inv.player;
|
||||
gui_background_ = new Guis.BackgroundImage(background_image_, imageWidth, imageHeight, Coord2d.ORIGIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
gui_background_.init(this, Coord2d.ORIGIN).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(GuiGraphics mx, int mouseX, int mouseY, float partialTicks) {
|
||||
renderBackground(mx);
|
||||
super.render(mx, mouseX, mouseY, partialTicks);
|
||||
if (!tooltip_.render(mx, this, mouseX, mouseY)) renderTooltip(mx, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderLabels(GuiGraphics mx, int x, int y) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected final void renderBg(GuiGraphics mx, float partialTicks, int mouseX, int mouseY) {
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
gui_background_.draw(mx, this);
|
||||
renderBgWidgets(mx, partialTicks, mouseX, mouseY);
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
|
||||
public final ResourceLocation getBackgroundImage() {
|
||||
return background_image_;
|
||||
}
|
||||
|
||||
protected void renderBgWidgets(GuiGraphics mx, float partialTicks, int mouseX, int mouseY) {
|
||||
}
|
||||
|
||||
protected void renderItemTemplate(GuiGraphics mx, ItemStack stack, int x, int y) {
|
||||
final int x0 = getGuiLeft();
|
||||
final int y0 = getGuiTop();
|
||||
|
||||
mx.renderFakeItem(stack, x0 + x, y0 + y);
|
||||
RenderSystem.disableColorLogicOp(); //RenderSystem.disableColorMaterial();
|
||||
RenderSystem.enableDepthTest(); //RenderSystem.enableAlphaTest();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.colorMask(true, true, true, true);
|
||||
RenderSystem.setShaderColor(0.7f, 0.7f, 0.7f, 0.8f);
|
||||
RenderSystem.setShaderTexture(0, background_image_);
|
||||
mx.blit(background_image_,x0 + x, y0 + y, x, y, 16, 16);
|
||||
RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
// Gui elements
|
||||
// -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class Coord2d {
|
||||
public static final Coord2d ORIGIN = new Coord2d(0, 0);
|
||||
public final int x, y;
|
||||
|
||||
public Coord2d(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public static Coord2d of(int x, int y) {
|
||||
return new Coord2d(x, y);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[" + x + "," + y + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class UiWidget extends AbstractWidget {
|
||||
protected static final Component EMPTY_TEXT = Component.literal("");
|
||||
protected static final Function<UiWidget, Component> NO_TOOLTIP = (uiw) -> EMPTY_TEXT;
|
||||
|
||||
private final Minecraft mc_;
|
||||
private Function<UiWidget, Component> tooltip_ = NO_TOOLTIP;
|
||||
private Screen parent_;
|
||||
|
||||
public UiWidget(int x, int y, int width, int height, Component title) {
|
||||
super(x, y, width, height, title);
|
||||
mc_ = Minecraft.getInstance();
|
||||
}
|
||||
|
||||
public UiWidget init(Screen parent) {
|
||||
this.parent_ = parent;
|
||||
this.setX(((parent instanceof AbstractContainerScreen<?>) ? ((AbstractContainerScreen<?>) parent).getGuiLeft() : 0));
|
||||
this.setY(((parent instanceof AbstractContainerScreen<?>) ? ((AbstractContainerScreen<?>) parent).getGuiTop() : 0));
|
||||
return this;
|
||||
}
|
||||
|
||||
public UiWidget init(Screen parent, Coord2d position) {
|
||||
this.parent_ = parent;
|
||||
this.setX(position.x + ((parent instanceof AbstractContainerScreen<?>) ? ((AbstractContainerScreen<?>) parent).getGuiLeft() : 0));
|
||||
this.setY(position.y + ((parent instanceof AbstractContainerScreen<?>) ? ((AbstractContainerScreen<?>) parent).getGuiTop() : 0));
|
||||
return this;
|
||||
}
|
||||
|
||||
public final UiWidget tooltip(Function<UiWidget, Component> tip) {
|
||||
tooltip_ = tip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final UiWidget tooltip(Component tip) {
|
||||
tooltip_ = (o) -> tip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final int getWidth() {
|
||||
return this.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateWidgetNarration(NarrationElementOutput narrationElementOutput) {
|
||||
|
||||
}
|
||||
|
||||
public final int getHeight() {
|
||||
return this.height;
|
||||
}
|
||||
|
||||
public Coord2d getMousePosition() {
|
||||
final Window win = mc_.getWindow();
|
||||
return Coord2d.of(
|
||||
Mth.clamp(((int) (mc_.mouseHandler.xpos() * (double) win.getGuiScaledWidth() / (double) win.getScreenWidth())) - this.getX(), -1, this.width + 1),
|
||||
Mth.clamp(((int) (mc_.mouseHandler.ypos() * (double) win.getGuiScaledHeight() / (double) win.getScreenHeight())) - this.getY(), -1, this.height + 1)
|
||||
);
|
||||
}
|
||||
|
||||
protected final Coord2d screenCoordinates(Coord2d xy, boolean reverse) {
|
||||
return (reverse) ? (Coord2d.of(xy.x + getX(), xy.y + getY())) : (Coord2d.of(xy.x - getX(), xy.y - getY()));
|
||||
}
|
||||
|
||||
public UiWidget show() {
|
||||
visible = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UiWidget hide() {
|
||||
visible = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics mxs, int mouseX, int mouseY, float partialTicks) {
|
||||
//super.renderWidget(mxs, mouseX, mouseY, partialTicks);
|
||||
if (isHovered) renderToolTip(mxs, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void renderToolTip(GuiGraphics mx, int mouseX, int mouseY) {
|
||||
if (!visible || (!active) || (tooltip_ == NO_TOOLTIP)) return;
|
||||
final Component tip = tooltip_.apply(this);
|
||||
if (tip.getString().trim().isEmpty()) return;
|
||||
mx.renderTooltip(mc_.font, Arrays.asList(tip.getVisualOrderText()), mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class HorizontalProgressBar extends UiWidget {
|
||||
private final Coord2d texture_position_base_;
|
||||
private final Coord2d texture_position_filled_;
|
||||
private final ResourceLocation atlas_;
|
||||
private double progress_max_ = 100;
|
||||
private double progress_ = 0;
|
||||
|
||||
public HorizontalProgressBar(ResourceLocation atlas, int width, int height, Coord2d base_texture_xy, Coord2d filled_texture_xy) {
|
||||
super(0, 0, width, height, EMPTY_TEXT);
|
||||
atlas_ = atlas;
|
||||
texture_position_base_ = base_texture_xy;
|
||||
texture_position_filled_ = filled_texture_xy;
|
||||
}
|
||||
|
||||
public HorizontalProgressBar setProgress(double progress) {
|
||||
progress_ = Mth.clamp(progress, 0, progress_max_);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getProgress() {
|
||||
return progress_;
|
||||
}
|
||||
|
||||
public HorizontalProgressBar setMaxProgress(double progress) {
|
||||
progress_max_ = Math.max(progress, 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getMaxProgress() {
|
||||
return progress_max_;
|
||||
}
|
||||
|
||||
public HorizontalProgressBar show() {
|
||||
visible = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HorizontalProgressBar hide() {
|
||||
visible = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playDownSound(SoundManager handler) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics mxs, int mouseX, int mouseY, float partialTicks) {
|
||||
RenderSystem.setShaderTexture(0, atlas_);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
mxs.blit(atlas_, getX(), getY(), texture_position_base_.x, texture_position_base_.y, width, height);
|
||||
if ((progress_max_ > 0) && (progress_ > 0)) {
|
||||
int w = Mth.clamp((int) Math.round((progress_ * width) / progress_max_), 0, width);
|
||||
mxs.blit(atlas_, getX(), getY(), texture_position_filled_.x, texture_position_filled_.y, w, height);
|
||||
}
|
||||
if (isHovered) renderToolTip(mxs, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class BackgroundImage extends UiWidget {
|
||||
private final ResourceLocation atlas_;
|
||||
private final Coord2d atlas_position_;
|
||||
public boolean visible;
|
||||
|
||||
public BackgroundImage(ResourceLocation atlas, int width, int height, Coord2d atlas_position) {
|
||||
super(0, 0, width, height, EMPTY_TEXT);
|
||||
atlas_ = atlas;
|
||||
atlas_position_ = atlas_position;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
visible = true;
|
||||
}
|
||||
|
||||
public void draw(GuiGraphics mx, Screen parent) {
|
||||
if (!visible) return;
|
||||
RenderSystem.setShaderTexture(0, atlas_);
|
||||
mx.blit(atlas_, getX(), getY(), atlas_position_.x, atlas_position_.y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class CheckBox extends UiWidget {
|
||||
private final Coord2d texture_position_off_;
|
||||
private final Coord2d texture_position_on_;
|
||||
private final ResourceLocation atlas_;
|
||||
private boolean checked_ = false;
|
||||
private Consumer<CheckBox> on_click_ = (checkbox) -> {
|
||||
};
|
||||
|
||||
public CheckBox(ResourceLocation atlas, int width, int height, Coord2d atlas_texture_position_off, Coord2d atlas_texture_position_on) {
|
||||
super(0, 0, width, height, EMPTY_TEXT);
|
||||
texture_position_off_ = atlas_texture_position_off;
|
||||
texture_position_on_ = atlas_texture_position_on;
|
||||
atlas_ = atlas;
|
||||
}
|
||||
|
||||
public boolean checked() {
|
||||
return checked_;
|
||||
}
|
||||
|
||||
public CheckBox checked(boolean on) {
|
||||
checked_ = on;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CheckBox onclick(Consumer<CheckBox> action) {
|
||||
on_click_ = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
checked_ = !checked_;
|
||||
on_click_.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics mxs, int mouseX, int mouseY, float partialTicks) {
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderTexture(0, atlas_);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
Coord2d pos = checked_ ? texture_position_on_ : texture_position_off_;
|
||||
mxs.blit(atlas_, getX(), getY(), pos.x, pos.y, width, height);
|
||||
if (isHovered) renderToolTip(mxs, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class ImageButton extends UiWidget {
|
||||
private final Coord2d texture_position_;
|
||||
private final ResourceLocation atlas_;
|
||||
private Consumer<ImageButton> on_click_ = (bt) -> {
|
||||
};
|
||||
|
||||
|
||||
public ImageButton(ResourceLocation atlas, int width, int height, Coord2d atlas_texture_position) {
|
||||
super(0, 0, width, height, Component.empty());
|
||||
texture_position_ = atlas_texture_position;
|
||||
atlas_ = atlas;
|
||||
}
|
||||
|
||||
public ImageButton onclick(Consumer<ImageButton> action) {
|
||||
on_click_ = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
on_click_.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics mxs, int mouseX, int mouseY, float partialTicks) {
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderTexture(0, atlas_);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
Coord2d pos = texture_position_;
|
||||
mxs.blit(atlas_, getX(), getY(), pos.x, pos.y, width, height);
|
||||
if (isHovered) renderToolTip(mxs, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class Image extends UiWidget {
|
||||
private final Coord2d texture_position_;
|
||||
private final ResourceLocation atlas_;
|
||||
|
||||
public Image(ResourceLocation atlas, int width, int height, Coord2d atlas_texture_position) {
|
||||
super(0, 0, width, height, Component.empty());
|
||||
texture_position_ = atlas_texture_position;
|
||||
atlas_ = atlas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics mxs, int mouseX, int mouseY, float partialTicks) {
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderTexture(0, atlas_);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
Coord2d pos = texture_position_;
|
||||
mxs.blit(atlas_, getX(), getY(), pos.x, pos.y, width, height);
|
||||
if (isHovered) renderToolTip(mxs, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class TextBox extends net.minecraft.client.gui.components.EditBox {
|
||||
public TextBox(int x, int y, int width, int height, Component title, Font font) {
|
||||
super(font, x, y, width, height, title);
|
||||
setBordered(false);
|
||||
}
|
||||
|
||||
public TextBox withMaxLength(int len) {
|
||||
super.setMaxLength(len);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextBox withBordered(boolean b) {
|
||||
super.setBordered(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextBox withValue(String s) {
|
||||
super.setValue(s);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextBox withEditable(boolean e) {
|
||||
super.setEditable(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextBox withResponder(Consumer<String> r) {
|
||||
super.setResponder(r);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,409 +0,0 @@
|
|||
/*
|
||||
* @file Networking.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Main client/server message handling.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
public class Networking {
|
||||
private static final String PROTOCOL = "1";
|
||||
private static SimpleChannel DEFAULT_CHANNEL;
|
||||
|
||||
public static void init(String modid) {
|
||||
DEFAULT_CHANNEL = NetworkRegistry.ChannelBuilder
|
||||
.named(new ResourceLocation(modid, "default_ch"))
|
||||
.clientAcceptedVersions(PROTOCOL::equals).serverAcceptedVersions(PROTOCOL::equals).networkProtocolVersion(() -> PROTOCOL)
|
||||
.simpleChannel();
|
||||
int discr = -1;
|
||||
DEFAULT_CHANNEL.registerMessage(++discr, PacketTileNotifyClientToServer.class, PacketTileNotifyClientToServer::compose, PacketTileNotifyClientToServer::parse, PacketTileNotifyClientToServer.Handler::handle);
|
||||
DEFAULT_CHANNEL.registerMessage(++discr, PacketTileNotifyServerToClient.class, PacketTileNotifyServerToClient::compose, PacketTileNotifyServerToClient::parse, PacketTileNotifyServerToClient.Handler::handle);
|
||||
DEFAULT_CHANNEL.registerMessage(++discr, PacketContainerSyncClientToServer.class, PacketContainerSyncClientToServer::compose, PacketContainerSyncClientToServer::parse, PacketContainerSyncClientToServer.Handler::handle);
|
||||
DEFAULT_CHANNEL.registerMessage(++discr, PacketContainerSyncServerToClient.class, PacketContainerSyncServerToClient::compose, PacketContainerSyncServerToClient::parse, PacketContainerSyncServerToClient.Handler::handle);
|
||||
DEFAULT_CHANNEL.registerMessage(++discr, PacketNbtNotifyClientToServer.class, PacketNbtNotifyClientToServer::compose, PacketNbtNotifyClientToServer::parse, PacketNbtNotifyClientToServer.Handler::handle);
|
||||
DEFAULT_CHANNEL.registerMessage(++discr, PacketNbtNotifyServerToClient.class, PacketNbtNotifyServerToClient::compose, PacketNbtNotifyServerToClient::parse, PacketNbtNotifyServerToClient.Handler::handle);
|
||||
DEFAULT_CHANNEL.registerMessage(++discr, OverlayTextMessage.class, OverlayTextMessage::compose, OverlayTextMessage::parse, OverlayTextMessage.Handler::handle);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
// Tile entity notifications
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public interface IPacketTileNotifyReceiver {
|
||||
default void onServerPacketReceived(CompoundTag nbt) {
|
||||
}
|
||||
|
||||
default void onClientPacketReceived(Player player, CompoundTag nbt) {
|
||||
}
|
||||
}
|
||||
|
||||
public static class PacketTileNotifyClientToServer {
|
||||
CompoundTag nbt = null;
|
||||
BlockPos pos = BlockPos.ZERO;
|
||||
|
||||
public static void sendToServer(BlockPos pos, CompoundTag nbt) {
|
||||
if ((pos != null) && (nbt != null))
|
||||
DEFAULT_CHANNEL.sendToServer(new PacketTileNotifyClientToServer(pos, nbt));
|
||||
}
|
||||
|
||||
public static void sendToServer(BlockEntity te, CompoundTag nbt) {
|
||||
if ((te != null) && (nbt != null))
|
||||
DEFAULT_CHANNEL.sendToServer(new PacketTileNotifyClientToServer(te, nbt));
|
||||
}
|
||||
|
||||
public PacketTileNotifyClientToServer() {
|
||||
}
|
||||
|
||||
public PacketTileNotifyClientToServer(BlockPos pos, CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public PacketTileNotifyClientToServer(BlockEntity te, CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
pos = te.getBlockPos();
|
||||
}
|
||||
|
||||
public static PacketTileNotifyClientToServer parse(final FriendlyByteBuf buf) {
|
||||
return new PacketTileNotifyClientToServer(buf.readBlockPos(), buf.readNbt());
|
||||
}
|
||||
|
||||
public static void compose(final PacketTileNotifyClientToServer pkt, final FriendlyByteBuf buf) {
|
||||
buf.writeBlockPos(pkt.pos);
|
||||
buf.writeNbt(pkt.nbt);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static class Handler {
|
||||
public static void handle(final PacketTileNotifyClientToServer pkt, final Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
Player player = ctx.get().getSender();
|
||||
if (player == null) return;
|
||||
Level world = player.level();
|
||||
final BlockEntity te = world.getBlockEntity(pkt.pos);
|
||||
if (!(te instanceof IPacketTileNotifyReceiver)) return;
|
||||
((IPacketTileNotifyReceiver) te).onClientPacketReceived(ctx.get().getSender(), pkt.nbt);
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PacketTileNotifyServerToClient {
|
||||
CompoundTag nbt = null;
|
||||
BlockPos pos = BlockPos.ZERO;
|
||||
|
||||
public static void sendToPlayer(Player player, BlockEntity te, CompoundTag nbt) {
|
||||
if ((!(player instanceof ServerPlayer)) || (player instanceof FakePlayer) || (te == null) || (nbt == null))
|
||||
return;
|
||||
DEFAULT_CHANNEL.sendTo(new PacketTileNotifyServerToClient(te, nbt), ((ServerPlayer) player).connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
public static void sendToPlayers(BlockEntity te, CompoundTag nbt) {
|
||||
if (te == null || te.getLevel() == null) return;
|
||||
for (Player player : te.getLevel().players()) sendToPlayer(player, te, nbt);
|
||||
}
|
||||
|
||||
public PacketTileNotifyServerToClient() {
|
||||
}
|
||||
|
||||
public PacketTileNotifyServerToClient(BlockPos pos, CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public PacketTileNotifyServerToClient(BlockEntity te, CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
pos = te.getBlockPos();
|
||||
}
|
||||
|
||||
public static PacketTileNotifyServerToClient parse(final FriendlyByteBuf buf) {
|
||||
return new PacketTileNotifyServerToClient(buf.readBlockPos(), buf.readNbt());
|
||||
}
|
||||
|
||||
public static void compose(final PacketTileNotifyServerToClient pkt, final FriendlyByteBuf buf) {
|
||||
buf.writeBlockPos(pkt.pos);
|
||||
buf.writeNbt(pkt.nbt);
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(final PacketTileNotifyServerToClient pkt, final Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
Level world = SidedProxy.getWorldClientSide();
|
||||
if (world == null) return;
|
||||
final BlockEntity te = world.getBlockEntity(pkt.pos);
|
||||
if (!(te instanceof IPacketTileNotifyReceiver)) return;
|
||||
((IPacketTileNotifyReceiver) te).onServerPacketReceived(pkt.nbt);
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
// (GUI) Container synchronization
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public interface INetworkSynchronisableContainer {
|
||||
void onServerPacketReceived(int windowId, CompoundTag nbt);
|
||||
|
||||
void onClientPacketReceived(int windowId, Player player, CompoundTag nbt);
|
||||
}
|
||||
|
||||
public static class PacketContainerSyncClientToServer {
|
||||
int id = -1;
|
||||
CompoundTag nbt = null;
|
||||
|
||||
public static void sendToServer(int windowId, CompoundTag nbt) {
|
||||
if (nbt != null) DEFAULT_CHANNEL.sendToServer(new PacketContainerSyncClientToServer(windowId, nbt));
|
||||
}
|
||||
|
||||
public static void sendToServer(AbstractContainerMenu container, CompoundTag nbt) {
|
||||
if (nbt != null)
|
||||
DEFAULT_CHANNEL.sendToServer(new PacketContainerSyncClientToServer(container.containerId, nbt));
|
||||
}
|
||||
|
||||
public PacketContainerSyncClientToServer() {
|
||||
}
|
||||
|
||||
public PacketContainerSyncClientToServer(int id, CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static PacketContainerSyncClientToServer parse(final FriendlyByteBuf buf) {
|
||||
return new PacketContainerSyncClientToServer(buf.readInt(), buf.readNbt());
|
||||
}
|
||||
|
||||
public static void compose(final PacketContainerSyncClientToServer pkt, final FriendlyByteBuf buf) {
|
||||
buf.writeInt(pkt.id);
|
||||
buf.writeNbt(pkt.nbt);
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(final PacketContainerSyncClientToServer pkt, final Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
Player player = ctx.get().getSender();
|
||||
if ((player == null) || !(player.containerMenu instanceof INetworkSynchronisableContainer)) return;
|
||||
if (player.containerMenu.containerId != pkt.id) return;
|
||||
((INetworkSynchronisableContainer) player.containerMenu).onClientPacketReceived(pkt.id, player, pkt.nbt);
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PacketContainerSyncServerToClient {
|
||||
int id = -1;
|
||||
CompoundTag nbt = null;
|
||||
|
||||
public static void sendToPlayer(Player player, int windowId, CompoundTag nbt) {
|
||||
if ((!(player instanceof ServerPlayer)) || (player instanceof FakePlayer) || (nbt == null)) return;
|
||||
DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(windowId, nbt), ((ServerPlayer) player).connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
public static void sendToPlayer(Player player, AbstractContainerMenu container, CompoundTag nbt) {
|
||||
if ((!(player instanceof ServerPlayer)) || (player instanceof FakePlayer) || (nbt == null)) return;
|
||||
DEFAULT_CHANNEL.sendTo(new PacketContainerSyncServerToClient(container.containerId, nbt), ((ServerPlayer) player).connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
public static <C extends AbstractContainerMenu & INetworkSynchronisableContainer>
|
||||
void sendToListeners(Level world, C container, CompoundTag nbt) {
|
||||
for (Player player : world.players()) {
|
||||
if (player.containerMenu.containerId != container.containerId) continue;
|
||||
sendToPlayer(player, container.containerId, nbt);
|
||||
}
|
||||
}
|
||||
|
||||
public PacketContainerSyncServerToClient() {
|
||||
}
|
||||
|
||||
public PacketContainerSyncServerToClient(int id, CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static PacketContainerSyncServerToClient parse(final FriendlyByteBuf buf) {
|
||||
return new PacketContainerSyncServerToClient(buf.readInt(), buf.readNbt());
|
||||
}
|
||||
|
||||
public static void compose(final PacketContainerSyncServerToClient pkt, final FriendlyByteBuf buf) {
|
||||
buf.writeInt(pkt.id);
|
||||
buf.writeNbt(pkt.nbt);
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(final PacketContainerSyncServerToClient pkt, final Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
Player player = SidedProxy.getPlayerClientSide();
|
||||
if ((player == null) || !(player.containerMenu instanceof INetworkSynchronisableContainer)) return;
|
||||
if (player.containerMenu.containerId != pkt.id) return;
|
||||
((INetworkSynchronisableContainer) player.containerMenu).onServerPacketReceived(pkt.id, pkt.nbt);
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
// World notifications
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class PacketNbtNotifyClientToServer {
|
||||
public static final Map<String, BiConsumer<Player, CompoundTag>> handlers = new HashMap<>();
|
||||
final CompoundTag nbt;
|
||||
|
||||
public static void sendToServer(CompoundTag nbt) {
|
||||
if (nbt != null) DEFAULT_CHANNEL.sendToServer(new PacketNbtNotifyClientToServer(nbt));
|
||||
}
|
||||
|
||||
public PacketNbtNotifyClientToServer(CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
}
|
||||
|
||||
public static PacketNbtNotifyClientToServer parse(final FriendlyByteBuf buf) {
|
||||
return new PacketNbtNotifyClientToServer(buf.readNbt());
|
||||
}
|
||||
|
||||
public static void compose(final PacketNbtNotifyClientToServer pkt, final FriendlyByteBuf buf) {
|
||||
buf.writeNbt(pkt.nbt);
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(final PacketNbtNotifyClientToServer pkt, final Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
final ServerPlayer player = ctx.get().getSender();
|
||||
if (player == null) return;
|
||||
final String hnd = pkt.nbt.getString("hnd");
|
||||
if (hnd.isEmpty()) return;
|
||||
if (handlers.containsKey(hnd)) handlers.get(hnd).accept(player, pkt.nbt);
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PacketNbtNotifyServerToClient {
|
||||
public static final Map<String, Consumer<CompoundTag>> handlers = new HashMap<>();
|
||||
final CompoundTag nbt;
|
||||
|
||||
public static void sendToPlayer(Player player, CompoundTag nbt) {
|
||||
if ((!(player instanceof ServerPlayer)) || (player instanceof FakePlayer) || (nbt == null)) return;
|
||||
DEFAULT_CHANNEL.sendTo(new PacketNbtNotifyServerToClient(nbt), ((ServerPlayer) player).connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
public static void sendToPlayers(Level world, CompoundTag nbt) {
|
||||
for (Player player : world.players()) sendToPlayer(player, nbt);
|
||||
}
|
||||
|
||||
public PacketNbtNotifyServerToClient(CompoundTag nbt) {
|
||||
this.nbt = nbt;
|
||||
}
|
||||
|
||||
public static PacketNbtNotifyServerToClient parse(final FriendlyByteBuf buf) {
|
||||
return new PacketNbtNotifyServerToClient(buf.readNbt());
|
||||
}
|
||||
|
||||
public static void compose(final PacketNbtNotifyServerToClient pkt, final FriendlyByteBuf buf) {
|
||||
buf.writeNbt(pkt.nbt);
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(final PacketNbtNotifyServerToClient pkt, final Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
final String hnd = pkt.nbt.getString("hnd");
|
||||
if (hnd.isEmpty()) return;
|
||||
if (handlers.containsKey(hnd)) handlers.get(hnd).accept(pkt.nbt);
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
// Main window GUI text message
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class OverlayTextMessage {
|
||||
public static final int DISPLAY_TIME_MS = 3000;
|
||||
private static BiConsumer<Component, Integer> handler_ = null;
|
||||
private final Component data_;
|
||||
private int delay_ = DISPLAY_TIME_MS;
|
||||
|
||||
private Component data() {
|
||||
return data_;
|
||||
}
|
||||
|
||||
private int delay() {
|
||||
return delay_;
|
||||
}
|
||||
|
||||
public static void setHandler(BiConsumer<Component, Integer> handler) {
|
||||
if (handler_ == null) handler_ = handler;
|
||||
}
|
||||
|
||||
public static void sendToPlayer(Player player, Component message, int delay) {
|
||||
if ((!(player instanceof ServerPlayer)) || (player instanceof FakePlayer) || Auxiliaries.isEmpty(message))
|
||||
return;
|
||||
DEFAULT_CHANNEL.sendTo(new OverlayTextMessage(message, delay), ((ServerPlayer) player).connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
public OverlayTextMessage() {
|
||||
data_ = Component.translatable("[unset]");
|
||||
}
|
||||
|
||||
public OverlayTextMessage(final Component tct, int delay) {
|
||||
data_ = tct.copy();
|
||||
delay_ = delay;
|
||||
}
|
||||
|
||||
public static OverlayTextMessage parse(final FriendlyByteBuf buf) {
|
||||
try {
|
||||
return new OverlayTextMessage(buf.readComponent(), DISPLAY_TIME_MS);
|
||||
} catch (Throwable e) {
|
||||
return new OverlayTextMessage(Component.translatable("[incorrect translation]"), DISPLAY_TIME_MS);
|
||||
}
|
||||
}
|
||||
|
||||
public static void compose(final OverlayTextMessage pkt, final FriendlyByteBuf buf) {
|
||||
try {
|
||||
buf.writeComponent(pkt.data());
|
||||
} catch (Throwable e) {
|
||||
Auxiliaries.logger().error("OverlayTextMessage.toBytes() failed: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Handler {
|
||||
public static void handle(final OverlayTextMessage pkt, final Supplier<NetworkEvent.Context> ctx) {
|
||||
if (handler_ != null) ctx.get().enqueueWork(() -> handler_.accept(pkt.data(), pkt.delay()));
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* @file OptionalRecipeCondition.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Recipe condition to enable opt'ing out JSON based recipes.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.common.crafting.conditions.ICondition;
|
||||
import net.minecraftforge.common.crafting.conditions.IConditionSerializer;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
|
||||
public class OptionalRecipeCondition implements ICondition {
|
||||
private static ResourceLocation NAME;
|
||||
|
||||
private final List<ResourceLocation> all_required;
|
||||
private final List<ResourceLocation> any_missing;
|
||||
private final List<ResourceLocation> all_required_tags;
|
||||
private final List<ResourceLocation> any_missing_tags;
|
||||
private final @Nullable ResourceLocation result;
|
||||
private final boolean result_is_tag;
|
||||
private final boolean experimental;
|
||||
|
||||
private static boolean with_experimental = false;
|
||||
private static boolean without_recipes = false;
|
||||
private static Predicate<Block> block_optouts = (block) -> false;
|
||||
private static Predicate<Item> item_optouts = (item) -> false;
|
||||
|
||||
public static void init(String modid, Logger logger) {
|
||||
NAME = new ResourceLocation(modid, "optional");
|
||||
}
|
||||
|
||||
public static void on_config(boolean enable_experimental, boolean disable_all_recipes,
|
||||
Predicate<Block> block_optout_provider,
|
||||
Predicate<Item> item_optout_provider) {
|
||||
with_experimental = enable_experimental;
|
||||
without_recipes = disable_all_recipes;
|
||||
block_optouts = block_optout_provider;
|
||||
item_optouts = item_optout_provider;
|
||||
}
|
||||
|
||||
public OptionalRecipeCondition(ResourceLocation result, List<ResourceLocation> required, List<ResourceLocation> missing, List<ResourceLocation> required_tags, List<ResourceLocation> missing_tags, boolean isexperimental, boolean result_is_tag) {
|
||||
all_required = required;
|
||||
any_missing = missing;
|
||||
all_required_tags = required_tags;
|
||||
any_missing_tags = missing_tags;
|
||||
this.result = result;
|
||||
this.result_is_tag = result_is_tag;
|
||||
experimental = isexperimental;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getID() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Optional recipe, all-required: [");
|
||||
for (ResourceLocation e : all_required) sb.append(e.toString()).append(",");
|
||||
for (ResourceLocation e : all_required_tags) sb.append("#").append(e.toString()).append(",");
|
||||
sb.delete(sb.length() - 1, sb.length()).append("], any-missing: [");
|
||||
for (ResourceLocation e : any_missing) sb.append(e.toString()).append(",");
|
||||
for (ResourceLocation e : any_missing_tags) sb.append("#").append(e.toString()).append(",");
|
||||
sb.delete(sb.length() - 1, sb.length()).append("]");
|
||||
if (experimental) sb.append(" EXPERIMENTAL");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(IContext context) {
|
||||
if (without_recipes) return false;
|
||||
if ((experimental) && (!with_experimental)) return false;
|
||||
final IForgeRegistry<Item> item_registry = ForgeRegistries.ITEMS;
|
||||
//final Collection<ResourceLocation> item_tags = SerializationTags.getInstance().getOrEmpty(Registry.ITEM_REGISTRY).getAvailableTags();
|
||||
if (result != null) {
|
||||
boolean item_registered = item_registry.containsKey(result);
|
||||
if (!item_registered) return false; // required result not registered
|
||||
if (item_optouts.test(item_registry.getValue(result))) return false;
|
||||
if (ForgeRegistries.BLOCKS.containsKey(result) && block_optouts.test(ForgeRegistries.BLOCKS.getValue(result)))
|
||||
return false;
|
||||
}
|
||||
if (!all_required.isEmpty()) {
|
||||
for (ResourceLocation rl : all_required) {
|
||||
if (!item_registry.containsKey(rl)) return false;
|
||||
}
|
||||
}
|
||||
if (!all_required_tags.isEmpty()) {
|
||||
for (ResourceLocation rl : all_required_tags) {
|
||||
if (item_registry.tags().getTagNames().noneMatch(tk -> tk.location().equals(rl)))
|
||||
return false; // if(!item_tags.contains(rl)) return false;
|
||||
}
|
||||
}
|
||||
if (!any_missing.isEmpty()) {
|
||||
for (ResourceLocation rl : any_missing) {
|
||||
if (!item_registry.containsKey(rl)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!any_missing_tags.isEmpty()) {
|
||||
for (ResourceLocation rl : any_missing_tags) {
|
||||
if (item_registry.tags().getTagNames().noneMatch(tk -> tk.location().equals(rl)))
|
||||
return true; // if(!item_tags.contains(rl)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Serializer implements IConditionSerializer<OptionalRecipeCondition> {
|
||||
public static final Serializer INSTANCE = new Serializer();
|
||||
|
||||
@Override
|
||||
public ResourceLocation getID() {
|
||||
return OptionalRecipeCondition.NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonObject json, OptionalRecipeCondition condition) {
|
||||
JsonArray required = new JsonArray();
|
||||
JsonArray missing = new JsonArray();
|
||||
for (ResourceLocation e : condition.all_required) required.add(e.toString());
|
||||
for (ResourceLocation e : condition.any_missing) missing.add(e.toString());
|
||||
json.add("required", required);
|
||||
json.add("missing", missing);
|
||||
if (condition.result != null) {
|
||||
json.addProperty("result", (condition.result_is_tag ? "#" : "") + condition.result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalRecipeCondition read(JsonObject json) {
|
||||
List<ResourceLocation> required = new ArrayList<>();
|
||||
List<ResourceLocation> missing = new ArrayList<>();
|
||||
List<ResourceLocation> required_tags = new ArrayList<>();
|
||||
List<ResourceLocation> missing_tags = new ArrayList<>();
|
||||
ResourceLocation result = null;
|
||||
boolean experimental = false;
|
||||
boolean result_is_tag = false;
|
||||
if (json.has("result")) {
|
||||
String s = json.get("result").getAsString();
|
||||
if (s.startsWith("#")) {
|
||||
result = new ResourceLocation(s.substring(1));
|
||||
result_is_tag = true;
|
||||
} else {
|
||||
result = new ResourceLocation(s);
|
||||
}
|
||||
}
|
||||
if (json.has("required")) {
|
||||
for (JsonElement e : GsonHelper.getAsJsonArray(json, "required")) {
|
||||
String s = e.getAsString();
|
||||
if (s.startsWith("#")) {
|
||||
required_tags.add(new ResourceLocation(s.substring(1)));
|
||||
} else {
|
||||
required.add(new ResourceLocation(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (json.has("missing")) {
|
||||
for (JsonElement e : GsonHelper.getAsJsonArray(json, "missing")) {
|
||||
String s = e.getAsString();
|
||||
if (s.startsWith("#")) {
|
||||
missing_tags.add(new ResourceLocation(s.substring(1)));
|
||||
} else {
|
||||
missing.add(new ResourceLocation(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (json.has("experimental")) experimental = json.get("experimental").getAsBoolean();
|
||||
return new OptionalRecipeCondition(result, required, missing, required_tags, missing_tags, experimental, result_is_tag);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* @file Overlay.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Renders status messages in one line.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
public class Overlay {
|
||||
public static void show(Player player, final Component message) {
|
||||
Networking.OverlayTextMessage.sendToPlayer(player, message, 3000);
|
||||
}
|
||||
|
||||
public static void show(Player player, final Component message, int delay) {
|
||||
Networking.OverlayTextMessage.sendToPlayer(player, message, delay);
|
||||
}
|
||||
|
||||
public static void show(BlockState state, BlockPos pos) {
|
||||
show(state, pos, 100);
|
||||
}
|
||||
|
||||
public static void show(BlockState state, BlockPos pos, int displayTimeoutMs) {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> (() -> TextOverlayGui.show(state, pos, displayTimeoutMs)));
|
||||
} // Only called when client side
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Client side handler
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class TextOverlayGui extends Screen {
|
||||
public static final TextOverlayGui INSTANCE = new TextOverlayGui();
|
||||
private static final Component EMPTY_TEXT = Component.literal("");
|
||||
private static final BlockState EMPTY_STATE = null;
|
||||
private static double overlay_y_ = 0.75;
|
||||
private static int text_color_ = 0x00ffaa00;
|
||||
private static int border_color_ = 0xaa333333;
|
||||
private static int background_color1_ = 0xaa333333;
|
||||
private static int background_color2_ = 0xaa444444;
|
||||
private static long text_deadline_ = 0;
|
||||
private static Component text_ = EMPTY_TEXT;
|
||||
private static long state_deadline_ = 0;
|
||||
private static @Nullable BlockState state_ = EMPTY_STATE;
|
||||
private static BlockPos pos_ = BlockPos.ZERO;
|
||||
|
||||
public static void on_config(double overlay_y) {
|
||||
on_config(overlay_y, 0x00ffaa00, 0xaa333333, 0xaa333333, 0xaa444444);
|
||||
}
|
||||
|
||||
public static void on_config(double overlay_y, int text_color, int border_color, int background_color1, int background_color2) {
|
||||
overlay_y_ = overlay_y;
|
||||
text_color_ = text_color;
|
||||
border_color_ = border_color;
|
||||
background_color1_ = background_color1;
|
||||
background_color2_ = background_color2;
|
||||
}
|
||||
|
||||
public static synchronized Component text() {
|
||||
return text_;
|
||||
}
|
||||
|
||||
public static synchronized long deadline() {
|
||||
return text_deadline_;
|
||||
}
|
||||
|
||||
public static synchronized void hide() {
|
||||
text_deadline_ = 0;
|
||||
text_ = EMPTY_TEXT;
|
||||
}
|
||||
|
||||
public static synchronized void show(Component s, int displayTimeoutMs) {
|
||||
text_ = (s == null) ? (EMPTY_TEXT) : (s.copy());
|
||||
text_deadline_ = System.currentTimeMillis() + displayTimeoutMs;
|
||||
}
|
||||
|
||||
public static synchronized void show(String s, int displayTimeoutMs) {
|
||||
text_ = ((s == null) || (s.isEmpty())) ? (EMPTY_TEXT) : (Component.literal(s));
|
||||
text_deadline_ = System.currentTimeMillis() + displayTimeoutMs;
|
||||
}
|
||||
|
||||
public static synchronized void show(BlockState state, BlockPos pos, int displayTimeoutMs) {
|
||||
pos_ = new BlockPos(pos);
|
||||
state_ = state;
|
||||
state_deadline_ = System.currentTimeMillis() + displayTimeoutMs;
|
||||
}
|
||||
|
||||
private static synchronized Optional<Tuple<BlockState, BlockPos>> state_pos() {
|
||||
return ((state_deadline_ < System.currentTimeMillis()) || (state_ == EMPTY_STATE)) ? Optional.empty() : Optional.of(new Tuple<>(state_, pos_));
|
||||
}
|
||||
|
||||
TextOverlayGui() {
|
||||
super(Component.literal(""));
|
||||
}
|
||||
|
||||
public void onRenderGui(final GuiGraphics mxs) {
|
||||
if (deadline() < System.currentTimeMillis()) return;
|
||||
if (text() == EMPTY_TEXT) return;
|
||||
String txt = text().getString();
|
||||
if (txt.isEmpty()) return;
|
||||
final net.minecraft.client.Minecraft mc = net.minecraft.client.Minecraft.getInstance();
|
||||
final Window win = mc.getWindow();
|
||||
final Font fr = mc.font;
|
||||
final boolean was_unicode = fr.isBidirectional();
|
||||
final int cx = win.getGuiScaledWidth() / 2;
|
||||
final int cy = (int) (win.getGuiScaledHeight() * overlay_y_);
|
||||
final int w = fr.width(txt);
|
||||
final int h = fr.lineHeight;
|
||||
mxs.fillGradient(cx - (w / 2) - 3, cy - 2, cx + (w / 2) + 2, cy + h + 2, 0xaa333333, 0xaa444444);
|
||||
mxs.hLine(cx - (w / 2) - 3, cx + (w / 2) + 2, cy - 2, 0xaa333333);
|
||||
mxs.hLine(cx - (w / 2) - 3, cx + (w / 2) + 2, cy + h + 2, 0xaa333333);
|
||||
mxs.vLine(cx - (w / 2) - 3, cy - 2, cy + h + 2, 0xaa333333);
|
||||
mxs.vLine(cx + (w / 2) + 2, cy - 2, cy + h + 2, 0xaa333333);
|
||||
mxs.drawCenteredString(fr, text(), cx, cy + 1, 0x00ffaa00);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onRenderWorldOverlay(final com.mojang.blaze3d.vertex.PoseStack mxs, final double partialTick) {
|
||||
final Optional<Tuple<BlockState, BlockPos>> sp = state_pos();
|
||||
if (sp.isEmpty()) return;
|
||||
final ClientLevel world = Minecraft.getInstance().level;
|
||||
final LocalPlayer player = Minecraft.getInstance().player;
|
||||
if ((player == null) || (world == null)) return;
|
||||
final BlockState state = sp.get().getA();
|
||||
final BlockPos pos = sp.get().getB();
|
||||
final int light = (world.hasChunkAt(pos)) ? LightTexture.pack(world.getBrightness(LightLayer.BLOCK, pos), world.getBrightness(LightLayer.SKY, pos)) : LightTexture.pack(15, 15);
|
||||
final MultiBufferSource buffer = Minecraft.getInstance().renderBuffers().bufferSource();
|
||||
final double px = Mth.lerp(partialTick, player.xo, player.getX());
|
||||
final double py = Mth.lerp(partialTick, player.yo, player.getY());
|
||||
final double pz = Mth.lerp(partialTick, player.zo, player.getZ());
|
||||
mxs.pushPose();
|
||||
mxs.translate((pos.getX() - px), (pos.getY() - py - player.getEyeHeight()), (pos.getZ() - pz));
|
||||
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(state, mxs, buffer, light, OverlayTexture.NO_OVERLAY);
|
||||
mxs.popPose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
# Engineer's Decor LibMC
|
||||
____________
|
||||
|
||||
As Engineer's Decor has been abandoned and discontinued, i've adopted the LibMC, and split the mod up among my various mods. Engineer's Decor blocks, and items, will now reside in Thresholds.
|
|
@ -1,263 +0,0 @@
|
|||
/*
|
||||
* @file Registries.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Common game registry handling.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.world.flag.FeatureFlags;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Registries {
|
||||
private static String modid = null;
|
||||
private static String creative_tab_icon = "";
|
||||
private static CreativeModeTab creative_tab = null;
|
||||
private static final Map<String, TagKey<Block>> registered_block_tag_keys = new HashMap<>();
|
||||
private static final Map<String, TagKey<Item>> registered_item_tag_keys = new HashMap<>();
|
||||
|
||||
private static final Map<String, RegistryObject<Block>> registered_blocks = new HashMap<>();
|
||||
private static final Map<String, RegistryObject<Item>> registered_items = new HashMap<>();
|
||||
private static final Map<String, RegistryObject<BlockEntityType<?>>> registered_block_entity_types = new HashMap<>();
|
||||
private static final Map<String, RegistryObject<EntityType<?>>> registered_entity_types = new HashMap<>();
|
||||
private static final Map<String, RegistryObject<MenuType<?>>> registered_menu_types = new HashMap<>();
|
||||
private static final Map<String, RegistryObject<RecipeSerializer<?>>> recipe_serializers = new HashMap<>();
|
||||
private static final Map<String, RegistryObject<CreativeModeTab>> registered_tabs = new HashMap<>();
|
||||
|
||||
public static final List<Supplier<? extends ItemLike>> tabItems = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
private static DeferredRegister<Block> BLOCKS;
|
||||
private static DeferredRegister<Item> ITEMS;
|
||||
private static DeferredRegister<CreativeModeTab> TABS;
|
||||
private static DeferredRegister<BlockEntityType<?>> BLOCK_ENTITIES;
|
||||
private static DeferredRegister<MenuType<?>> MENUS;
|
||||
private static DeferredRegister<EntityType<?>> ENTITIES;
|
||||
private static DeferredRegister<RecipeSerializer<?>> RECIPE_SERIALIZERS;
|
||||
private static List<DeferredRegister<?>> MOD_REGISTRIES;
|
||||
|
||||
public static void init(String mod_id, String creative_tab_icon_item_name, IEventBus bus) {
|
||||
modid = mod_id;
|
||||
creative_tab_icon = creative_tab_icon_item_name;
|
||||
BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, modid);
|
||||
ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, modid);
|
||||
BLOCK_ENTITIES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITY_TYPES, modid);
|
||||
MENUS = DeferredRegister.create(ForgeRegistries.MENU_TYPES, modid);
|
||||
ENTITIES = DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, modid);
|
||||
RECIPE_SERIALIZERS = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, modid);
|
||||
TABS = DeferredRegister.create(net.minecraft.core.registries.Registries.CREATIVE_MODE_TAB, modid);
|
||||
|
||||
Consumer<DeferredRegister<?>> consumer = (X)->{
|
||||
X.register(bus);
|
||||
};
|
||||
|
||||
List.of(BLOCKS, ITEMS, BLOCK_ENTITIES, MENUS, ENTITIES, RECIPE_SERIALIZERS, TABS).forEach(consumer);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static Block getBlock(String block_name) {
|
||||
return registered_blocks.get(block_name).get();
|
||||
}
|
||||
|
||||
public static <T extends Item> RegistryObject<T> withTab(RegistryObject<T> item)
|
||||
{
|
||||
tabItems.add(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public static Item getItem(String name) {
|
||||
return registered_items.get(name).get();
|
||||
}
|
||||
|
||||
public static EntityType<?> getEntityType(String name) {
|
||||
return registered_entity_types.get(name).get();
|
||||
}
|
||||
|
||||
public static BlockEntityType<?> getBlockEntityType(String block_name) {
|
||||
return registered_block_entity_types.get(block_name).get();
|
||||
}
|
||||
|
||||
public static MenuType<?> getMenuType(String name) {
|
||||
return registered_menu_types.get(name).get();
|
||||
}
|
||||
|
||||
public static RecipeSerializer<?> getRecipeSerializer(String name) {
|
||||
return recipe_serializers.get(name).get();
|
||||
}
|
||||
|
||||
public static BlockEntityType<?> getBlockEntityTypeOfBlock(String block_name) {
|
||||
return getBlockEntityType("tet_" + block_name);
|
||||
}
|
||||
|
||||
public static BlockEntityType<?> getBlockEntityTypeOfBlock(Block block) {
|
||||
return getBlockEntityTypeOfBlock(ForgeRegistries.BLOCKS.getKey(block).getPath());
|
||||
}
|
||||
|
||||
public static MenuType<?> getMenuTypeOfBlock(String name) {
|
||||
return getMenuType("ct_" + name);
|
||||
}
|
||||
|
||||
public static MenuType<?> getMenuTypeOfBlock(Block block) {
|
||||
return getMenuTypeOfBlock(ForgeRegistries.BLOCKS.getKey(block).getPath());
|
||||
}
|
||||
|
||||
public static TagKey<Block> getBlockTagKey(String name) {
|
||||
return registered_block_tag_keys.get(name);
|
||||
}
|
||||
|
||||
public static TagKey<Item> getItemTagKey(String name) {
|
||||
return registered_item_tag_keys.get(name);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@Nonnull
|
||||
public static List<Block> getRegisteredBlocks() {
|
||||
return Collections.unmodifiableList(registered_blocks.values().stream().map(RegistryObject::get).toList());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static List<Item> getRegisteredItems() {
|
||||
return Collections.unmodifiableList(registered_items.values().stream().map(RegistryObject::get).toList());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static List<BlockEntityType<?>> getRegisteredBlockEntityTypes() {
|
||||
return Collections.unmodifiableList(registered_block_entity_types.values().stream().map(RegistryObject::get).toList());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static List<EntityType<?>> getRegisteredEntityTypes() {
|
||||
return Collections.unmodifiableList(registered_entity_types.values().stream().map(RegistryObject::get).toList());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
public static <T extends Item> void addItem(String registry_name, Supplier<T> supplier) {
|
||||
registered_items.put(registry_name, withTab(ITEMS.register(registry_name, supplier)));
|
||||
|
||||
}
|
||||
|
||||
public static <T extends Block> void addBlock(String registry_name, Supplier<T> block_supplier) {
|
||||
registered_blocks.put(registry_name, BLOCKS.register(registry_name, block_supplier));
|
||||
registered_items.put(registry_name, withTab(ITEMS.register(registry_name, () -> new BlockItem(registered_blocks.get(registry_name).get(), (new Item.Properties())))));
|
||||
}
|
||||
|
||||
public static <T extends CreativeModeTab> void addCreativeModeTab(String id, Component title, ItemStack icon)
|
||||
{
|
||||
registered_tabs.put(id, TABS.register(id, ()-> CreativeModeTab
|
||||
.builder()
|
||||
.icon(()->icon)
|
||||
.title(title)
|
||||
.withSearchBar()
|
||||
|
||||
.displayItems((display, output) -> tabItems.forEach(it->output.accept(it.get())))
|
||||
|
||||
.build()
|
||||
));
|
||||
}
|
||||
|
||||
public static <TB extends Block, TI extends Item> void addBlock(String registry_name, Supplier<TB> block_supplier, Supplier<TI> item_supplier) {
|
||||
registered_blocks.put(registry_name, BLOCKS.register(registry_name, block_supplier));
|
||||
registered_items.put(registry_name, ITEMS.register(registry_name, item_supplier));
|
||||
}
|
||||
|
||||
public static <T extends BlockEntity> void addBlockEntityType(String registry_name, BlockEntityType.BlockEntitySupplier<T> ctor, String... block_names) {
|
||||
registered_block_entity_types.put(registry_name, BLOCK_ENTITIES.register(registry_name, () -> {
|
||||
final Block[] blocks = Arrays.stream(block_names).map(s -> {
|
||||
Block b = BLOCKS.getEntries().stream().filter((ro) -> ro.getId().getPath().equals(s)).findFirst().map(RegistryObject::get).orElse(null);
|
||||
if (b == null) Auxiliaries.logError("registered_blocks does not encompass '" + s + "'");
|
||||
return b;
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList()).toArray(new Block[]{});
|
||||
return BlockEntityType.Builder.of(ctor, blocks).build(null);
|
||||
}));
|
||||
}
|
||||
|
||||
public static <T extends EntityType<?>> void addEntityType(String registry_name, Supplier<EntityType<?>> supplier) {
|
||||
registered_entity_types.put(registry_name, ENTITIES.register(registry_name, supplier));
|
||||
}
|
||||
|
||||
public static <T extends MenuType<?>> void addMenuType(String registry_name, MenuType.MenuSupplier<?> supplier, FeatureFlagSet flags) {
|
||||
registered_menu_types.put(registry_name, MENUS.register(registry_name, () -> new MenuType<>(supplier, flags)));
|
||||
}
|
||||
|
||||
public static void addRecipeSerializer(String registry_name, Supplier<? extends RecipeSerializer<?>> serializer_supplier) {
|
||||
recipe_serializers.put(registry_name, RECIPE_SERIALIZERS.register(registry_name, serializer_supplier));
|
||||
}
|
||||
|
||||
public static void addOptionalBlockTag(String tag_name, ResourceLocation... default_blocks) {
|
||||
final Set<Supplier<Block>> default_suppliers = new HashSet<>();
|
||||
for (ResourceLocation rl : default_blocks) default_suppliers.add(() -> ForgeRegistries.BLOCKS.getValue(rl));
|
||||
final TagKey<Block> key = ForgeRegistries.BLOCKS.tags().createOptionalTagKey(new ResourceLocation(modid, tag_name), default_suppliers);
|
||||
registered_block_tag_keys.put(tag_name, key);
|
||||
}
|
||||
|
||||
public static void addOptionaItemTag(String tag_name, ResourceLocation... default_items) {
|
||||
final Set<Supplier<Item>> default_suppliers = new HashSet<>();
|
||||
for (ResourceLocation rl : default_items) default_suppliers.add(() -> ForgeRegistries.ITEMS.getValue(rl));
|
||||
final TagKey<Item> key = ForgeRegistries.ITEMS.tags().createOptionalTagKey(new ResourceLocation(modid, tag_name), default_suppliers);
|
||||
registered_item_tag_keys.put(tag_name, key);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@Deprecated
|
||||
/**
|
||||
* This function is to be removed as it cannot add items to a tab anymore
|
||||
*/
|
||||
public static <TB extends Block, TI extends Item> void addBlock(String registry_name, Supplier<TB> block_supplier, BiFunction<Block, Item.Properties, Item> item_builder) {
|
||||
addBlock(registry_name, block_supplier, () -> item_builder.apply(registered_blocks.get(registry_name).get(), (new Item.Properties())));
|
||||
}
|
||||
|
||||
public static void addBlock(String registry_name, Supplier<? extends Block> block_supplier, BlockEntityType.BlockEntitySupplier<?> block_entity_ctor) {
|
||||
addBlock(registry_name, block_supplier);
|
||||
addBlockEntityType("tet_" + registry_name, block_entity_ctor, registry_name);
|
||||
}
|
||||
|
||||
public static void addBlock(String registry_name, Supplier<? extends Block> block_supplier, BiFunction<Block, Item.Properties, Item> item_builder, BlockEntityType.BlockEntitySupplier<?> block_entity_ctor) {
|
||||
addBlock(registry_name, block_supplier, item_builder);
|
||||
addBlockEntityType("tet_" + registry_name, block_entity_ctor, registry_name);
|
||||
}
|
||||
|
||||
public static void addBlock(String registry_name, Supplier<? extends Block> block_supplier, BiFunction<Block, Item.Properties, Item> item_builder, BlockEntityType.BlockEntitySupplier<?> block_entity_ctor, MenuType.MenuSupplier<?> menu_type_supplier, FeatureFlagSet menuFlags) {
|
||||
addBlock(registry_name, block_supplier, item_builder);
|
||||
addBlockEntityType("tet_" + registry_name, block_entity_ctor, registry_name);
|
||||
addMenuType("ct_" + registry_name, menu_type_supplier, menuFlags);
|
||||
}
|
||||
|
||||
public static void addBlock(String registry_name, Supplier<? extends Block> block_supplier, BlockEntityType.BlockEntitySupplier<?> block_entity_ctor, MenuType.MenuSupplier<?> menu_type_supplier, FeatureFlagSet menuFlags) {
|
||||
addBlock(registry_name, block_supplier, block_entity_ctor);
|
||||
addMenuType("ct_" + registry_name, menu_type_supplier, menuFlags);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* @file RfEnergy.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* General RF/FE energy handling functionality.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.energy.IEnergyStorage;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class RfEnergy {
|
||||
public static int feed(Level world, BlockPos pos, @Nullable Direction side, int rf_energy) {
|
||||
final BlockEntity te = world.getBlockEntity(pos);
|
||||
if (te == null) return 0;
|
||||
final IEnergyStorage es = te.getCapability(ForgeCapabilities.ENERGY, side).orElse(null);
|
||||
if (es == null) return 0;
|
||||
return es.receiveEnergy(rf_energy, false);
|
||||
}
|
||||
|
||||
public static class Battery implements IEnergyStorage {
|
||||
protected int capacity_;
|
||||
protected int charge_rate_;
|
||||
protected int discharge_rate_;
|
||||
protected int energy_;
|
||||
|
||||
public Battery(int capacity) {
|
||||
this(capacity, capacity);
|
||||
}
|
||||
|
||||
public Battery(int capacity, int transfer_rate) {
|
||||
this(capacity, transfer_rate, transfer_rate, 0);
|
||||
}
|
||||
|
||||
public Battery(int capacity, int charge_rate, int discharge_rate) {
|
||||
this(capacity, charge_rate, discharge_rate, 0);
|
||||
}
|
||||
|
||||
public Battery(int capacity, int charge_rate, int discharge_rate, int energy) {
|
||||
capacity_ = Math.max(capacity, 1);
|
||||
charge_rate_ = Mth.clamp(charge_rate, 0, capacity_);
|
||||
discharge_rate_ = Mth.clamp(discharge_rate, 0, capacity_);
|
||||
energy_ = Mth.clamp(energy, 0, capacity_);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
|
||||
public Battery setMaxEnergyStored(int capacity) {
|
||||
capacity_ = Math.max(capacity, 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Battery setEnergyStored(int energy) {
|
||||
energy_ = Mth.clamp(energy, 0, capacity_);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Battery setChargeRate(int in_rate) {
|
||||
charge_rate_ = Mth.clamp(in_rate, 0, capacity_);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Battery setDischargeRate(int out_rate) {
|
||||
discharge_rate_ = Mth.clamp(out_rate, 0, capacity_);
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getChargeRate() {
|
||||
return charge_rate_;
|
||||
}
|
||||
|
||||
public int getDischargeRate() {
|
||||
return discharge_rate_;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return energy_ <= 0;
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return energy_ >= capacity_;
|
||||
}
|
||||
|
||||
public int getSOC() {
|
||||
return (int) Mth.clamp((100.0 * energy_ / capacity_ + .5), 0, 100);
|
||||
}
|
||||
|
||||
public int getComparatorOutput() {
|
||||
return (int) Mth.clamp((15.0 * energy_ / capacity_ + .2), 0, 15);
|
||||
}
|
||||
|
||||
public boolean draw(int energy) {
|
||||
if (energy_ < energy) return false;
|
||||
energy_ -= energy;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean feed(int energy) {
|
||||
energy_ = Math.min(energy_ + energy, capacity_);
|
||||
return energy_ >= capacity_;
|
||||
}
|
||||
|
||||
public Battery clear() {
|
||||
energy_ = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Battery load(CompoundTag nbt, String key) {
|
||||
setEnergyStored(nbt.getInt(key));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Battery load(CompoundTag nbt) {
|
||||
return load(nbt, "Energy");
|
||||
}
|
||||
|
||||
public CompoundTag save(CompoundTag nbt, String key) {
|
||||
nbt.putInt(key, energy_);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
return save(nbt, "Energy");
|
||||
}
|
||||
|
||||
public LazyOptional<IEnergyStorage> createEnergyHandler() {
|
||||
return LazyOptional.of(() -> this);
|
||||
}
|
||||
|
||||
// IEnergyStorage ------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public int receiveEnergy(int feed_energy, boolean simulate) {
|
||||
if (!canReceive()) return 0;
|
||||
int e = Math.min(Math.min(charge_rate_, feed_energy), capacity_ - energy_);
|
||||
if (!simulate) energy_ += e;
|
||||
return e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int extractEnergy(int draw_energy, boolean simulate) {
|
||||
if (!canExtract()) return 0;
|
||||
int e = Math.min(Math.min(discharge_rate_, draw_energy), energy_);
|
||||
if (!simulate) energy_ -= e;
|
||||
return e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEnergyStored() {
|
||||
return energy_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxEnergyStored() {
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExtract() {
|
||||
return discharge_rate_ > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReceive() {
|
||||
return charge_rate_ > 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* @file RsSignals.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* General redstone signal related functionality.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class RsSignals {
|
||||
|
||||
public static boolean hasSignalConnector(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction realSide) {
|
||||
return state.isSignalSource();
|
||||
}
|
||||
|
||||
public static int fromContainer(@Nullable Container container) {
|
||||
if (container == null) return 0;
|
||||
final double max = container.getMaxStackSize();
|
||||
if (max <= 0) return 0;
|
||||
boolean nonempty = false;
|
||||
double fill_level = 0;
|
||||
for (int i = 0; i < container.getContainerSize(); ++i) {
|
||||
ItemStack stack = container.getItem(i);
|
||||
if (stack.isEmpty() || (stack.getMaxStackSize() <= 0)) continue;
|
||||
fill_level += ((double) stack.getCount()) / Math.min(max, stack.getMaxStackSize());
|
||||
nonempty = true;
|
||||
}
|
||||
fill_level /= container.getContainerSize();
|
||||
return (int) (Math.floor(fill_level * 14) + (nonempty ? 1 : 0)); // vanilla compliant calculation.
|
||||
}
|
||||
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* @file SidedProxy.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* General client/server sidedness selection proxy.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SidedProxy {
|
||||
@Nullable
|
||||
public static Player getPlayerClientSide() {
|
||||
return proxy.getPlayerClientSide();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Level getWorldClientSide() {
|
||||
return proxy.getWorldClientSide();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Minecraft mc() {
|
||||
return proxy.mc();
|
||||
}
|
||||
|
||||
public static Optional<Boolean> isCtrlDown() {
|
||||
return proxy.isCtrlDown();
|
||||
}
|
||||
|
||||
public static Optional<Boolean> isShiftDown() {
|
||||
return proxy.isShiftDown();
|
||||
}
|
||||
|
||||
public static Optional<String> getClipboard() {
|
||||
return proxy.getClipboard();
|
||||
}
|
||||
|
||||
public static boolean setClipboard(String text) {
|
||||
return proxy.setClipboard(text);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
|
||||
private static final ISidedProxy proxy = DistExecutor.unsafeRunForDist(() -> ClientProxy::new, () -> ServerProxy::new);
|
||||
|
||||
private interface ISidedProxy {
|
||||
default @Nullable Player getPlayerClientSide() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default @Nullable Level getWorldClientSide() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default @Nullable Minecraft mc() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Optional<Boolean> isCtrlDown() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
default Optional<Boolean> isShiftDown() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
default Optional<String> getClipboard() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
default boolean setClipboard(String text) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ClientProxy implements ISidedProxy {
|
||||
public @Nullable Player getPlayerClientSide() {
|
||||
return Minecraft.getInstance().player;
|
||||
}
|
||||
|
||||
public @Nullable Level getWorldClientSide() {
|
||||
return Minecraft.getInstance().level;
|
||||
}
|
||||
|
||||
public @Nullable Minecraft mc() {
|
||||
return Minecraft.getInstance();
|
||||
}
|
||||
|
||||
public Optional<Boolean> isCtrlDown() {
|
||||
return Optional.of(Auxiliaries.isCtrlDown());
|
||||
}
|
||||
|
||||
public Optional<Boolean> isShiftDown() {
|
||||
return Optional.of(Auxiliaries.isShiftDown());
|
||||
}
|
||||
|
||||
public Optional<String> getClipboard() {
|
||||
return (mc() == null) ? Optional.empty() : Optional.of(net.minecraft.client.gui.font.TextFieldHelper.getClipboardContents(mc()));
|
||||
}
|
||||
|
||||
public boolean setClipboard(String text) {
|
||||
if (mc() == null) {
|
||||
return false;
|
||||
}
|
||||
net.minecraft.client.gui.font.TextFieldHelper.setClipboardContents(Minecraft.getInstance(), text);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ServerProxy implements ISidedProxy {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
/*
|
||||
* @file SlabSliceBlock.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Half slab ("slab slices") characteristics class. Actually
|
||||
* it's now a quarter slab, but who cares.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SlabSliceBlock extends StandardBlocks.WaterLoggable implements StandardBlocks.IStandardBlock {
|
||||
public static final IntegerProperty PARTS = IntegerProperty.create("parts", 0, 14);
|
||||
|
||||
protected static final VoxelShape[] AABBs = {
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 2. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 4. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 6. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 8. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 10. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 12. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 14. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 2. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 4. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 6. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 8. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 10. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 12. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 14. / 16, 0, 1, 16. / 16, 1)),
|
||||
Shapes.create(new AABB(0, 0, 0, 1, 1, 1)) // <- with 4bit fill
|
||||
};
|
||||
|
||||
protected static final int[] num_slabs_contained_in_parts_ = {1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0x1}; // <- with 4bit fill
|
||||
private static boolean with_pickup = false;
|
||||
|
||||
public static void on_config(boolean direct_slab_pickup) {
|
||||
with_pickup = direct_slab_pickup;
|
||||
}
|
||||
|
||||
public SlabSliceBlock(long config, BlockBehaviour.Properties builder) {
|
||||
super(config, builder);
|
||||
}
|
||||
|
||||
protected boolean is_cube(BlockState state) {
|
||||
return state.getValue(PARTS) == 0x07;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
|
||||
if (!Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true)) return;
|
||||
if (with_pickup) Auxiliaries.Tooltip.addInformation("engineersdecor.tooltip.slabpickup", tooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderTypeHint getRenderTypeHint() {
|
||||
return (((config & StandardBlocks.CFG_TRANSLUCENT) != 0) ? (RenderTypeHint.TRANSLUCENT) : (RenderTypeHint.CUTOUT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
|
||||
return AABBs[state.getValue(PARTS) & 0xf];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return getShape(state, world, pos, selectionContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(PARTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
final BlockPos pos = context.getClickedPos();
|
||||
BlockState state = context.getLevel().getBlockState(pos);
|
||||
if (state.getBlock() == this) {
|
||||
int parts = state.getValue(PARTS);
|
||||
if (parts == 7) return null; // -> is already a full block.
|
||||
parts += (parts < 7) ? 1 : -1;
|
||||
if (parts == 7) state = state.setValue(WATERLOGGED, false);
|
||||
return state.setValue(PARTS, parts);
|
||||
} else {
|
||||
final Direction face = context.getClickedFace();
|
||||
final BlockState placement_state = super.getStateForPlacement(context); // fluid state
|
||||
if (face == Direction.UP) return placement_state.setValue(PARTS, 0);
|
||||
if (face == Direction.DOWN) return placement_state.setValue(PARTS, 14);
|
||||
if (!face.getAxis().isHorizontal()) return placement_state;
|
||||
final boolean isupper = ((context.getClickLocation().y() - context.getClickedPos().getY()) > 0.5);
|
||||
return placement_state.setValue(PARTS, isupper ? 14 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
|
||||
if (context.getItemInHand().getItem() != this.asItem()) return false;
|
||||
if (!context.replacingClickedOnBlock()) return true;
|
||||
final Direction face = context.getClickedFace();
|
||||
final int parts = state.getValue(PARTS);
|
||||
if (parts == 7) return false;
|
||||
if ((face == Direction.UP) && (parts < 7)) return true;
|
||||
if ((face == Direction.DOWN) && (parts > 7)) return true;
|
||||
if (!face.getAxis().isHorizontal()) return false;
|
||||
final boolean isupper = ((context.getClickLocation().y() - context.getClickedPos().getY()) > 0.5);
|
||||
return isupper ? (parts == 0) : (parts == 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState rotate(BlockState state, Rotation rot) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDynamicDropList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion) {
|
||||
return new ArrayList<>(Collections.singletonList(new ItemStack(this.asItem(), num_slabs_contained_in_parts_[state.getValue(PARTS) & 0xf])));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void attack(BlockState state, Level world, BlockPos pos, Player player) {
|
||||
if ((world.isClientSide) || (!with_pickup)) return;
|
||||
final ItemStack stack = player.getMainHandItem();
|
||||
if (stack.isEmpty() || (Block.byItem(stack.getItem()) != this)) return;
|
||||
if (stack.getCount() >= stack.getMaxStackSize()) return;
|
||||
Vec3 lv = player.getLookAngle();
|
||||
Direction facing = Direction.getNearest((float) lv.x, (float) lv.y, (float) lv.z);
|
||||
if ((facing != Direction.UP) && (facing != Direction.DOWN)) return;
|
||||
if (state.getBlock() != this) return;
|
||||
int parts = state.getValue(PARTS);
|
||||
if ((facing == Direction.DOWN) && (parts <= 7)) {
|
||||
if (parts > 0) {
|
||||
world.setBlock(pos, state.setValue(PARTS, parts - 1), 3);
|
||||
} else {
|
||||
world.removeBlock(pos, false);
|
||||
}
|
||||
} else if ((facing == Direction.UP) && (parts >= 7)) {
|
||||
if (parts < 14) {
|
||||
world.setBlock(pos, state.setValue(PARTS, parts + 1), 3);
|
||||
} else {
|
||||
world.removeBlock(pos, false);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (!player.isCreative()) {
|
||||
stack.grow(1);
|
||||
if (player.getInventory() != null) player.getInventory().setChanged();
|
||||
}
|
||||
SoundType st = this.getSoundType(state, world, pos, null);
|
||||
world.playSound(player, pos, st.getPlaceSound(), SoundSource.BLOCKS, (st.getVolume() + 1f) / 2.5f, 0.9f * st.getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
|
||||
return (state.getValue(PARTS) != 14) && (super.placeLiquid(world, pos, state, fluidState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
|
||||
return (state.getValue(PARTS) != 14) && (super.canPlaceLiquid(world, pos, state, fluid));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,698 +0,0 @@
|
|||
/*
|
||||
* @file StandardBlocks.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Common functionality class for decor blocks.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.level.storage.loot.LootParams;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.shapes.BooleanOp;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class StandardBlocks {
|
||||
public static final long CFG_DEFAULT = 0x0000000000000000L; // no special config
|
||||
public static final long CFG_CUTOUT = 0x0000000000000001L; // cutout rendering
|
||||
public static final long CFG_MIPPED = 0x0000000000000002L; // cutout mipped rendering
|
||||
public static final long CFG_TRANSLUCENT = 0x0000000000000004L; // indicates a block/pane is glass like (transparent, etc)
|
||||
public static final long CFG_WATERLOGGABLE = 0x0000000000000008L; // The derived block extends IWaterLoggable
|
||||
public static final long CFG_HORIZIONTAL = 0x0000000000000010L; // horizontal block, affects bounding box calculation at construction time and placement
|
||||
public static final long CFG_LOOK_PLACEMENT = 0x0000000000000020L; // placed in direction the player is looking when placing.
|
||||
public static final long CFG_FACING_PLACEMENT = 0x0000000000000040L; // placed on the facing the player has clicked.
|
||||
public static final long CFG_OPPOSITE_PLACEMENT = 0x0000000000000080L; // placed placed in the opposite direction of the face the player clicked.
|
||||
public static final long CFG_FLIP_PLACEMENT_IF_SAME = 0x0000000000000100L; // placement direction flipped if an instance of the same class was clicked
|
||||
public static final long CFG_FLIP_PLACEMENT_SHIFTCLICK = 0x0000000000000200L; // placement direction flipped if player is sneaking
|
||||
public static final long CFG_STRICT_CONNECTIONS = 0x0000000000000400L; // blocks do not connect to similar blocks around (implementation details may vary a bit)
|
||||
public static final long CFG_AI_PASSABLE = 0x0000000000000800L; // does not block movement path for AI, needed for non-opaque blocks with collision shapes not thin at the bottom or one side.
|
||||
|
||||
public interface IStandardBlock {
|
||||
default long config() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
default boolean hasDynamicDropList() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) {
|
||||
return Collections.singletonList((!world.isClientSide()) ? (new ItemStack(state.getBlock().asItem())) : (ItemStack.EMPTY));
|
||||
}
|
||||
|
||||
enum RenderTypeHint {SOLID, CUTOUT, CUTOUT_MIPPED, TRANSLUCENT, TRANSLUCENT_NO_CRUMBLING}
|
||||
|
||||
default RenderTypeHint getRenderTypeHint() {
|
||||
return getRenderTypeHint(config());
|
||||
}
|
||||
|
||||
default RenderTypeHint getRenderTypeHint(long config) {
|
||||
if ((config & CFG_CUTOUT) != 0) return RenderTypeHint.CUTOUT;
|
||||
if ((config & CFG_MIPPED) != 0) return RenderTypeHint.CUTOUT_MIPPED;
|
||||
if ((config & CFG_TRANSLUCENT) != 0) return RenderTypeHint.TRANSLUCENT;
|
||||
return RenderTypeHint.SOLID;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BaseBlock extends Block implements IStandardBlock, SimpleWaterloggedBlock {
|
||||
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||
public final long config;
|
||||
|
||||
public BaseBlock(long conf, BlockBehaviour.Properties properties) {
|
||||
super(properties);
|
||||
config = conf;
|
||||
BlockState state = getStateDefinition().any();
|
||||
if ((conf & CFG_WATERLOGGABLE) != 0) state = state.setValue(WATERLOGGED, false);
|
||||
registerDefaultState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long config() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
|
||||
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderTypeHint getRenderTypeHint() {
|
||||
return getRenderTypeHint(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) {
|
||||
return ((config & CFG_AI_PASSABLE) != 0) && (super.isPathfindable(state, world, pos, type));
|
||||
}
|
||||
|
||||
public boolean hasSignalConnector(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) {
|
||||
return state.isSignalSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
final boolean rsup = (state.hasBlockEntity() && (state.getBlock() != newState.getBlock()));
|
||||
super.onRemove(state, world, pos, newState, isMoving);
|
||||
if (rsup) world.updateNeighbourForOutputSignal(pos, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
|
||||
return (((config & CFG_WATERLOGGABLE) == 0) || (!state.getValue(WATERLOGGED))) && super.propagatesSkylightDown(state, reader, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public FluidState getFluidState(BlockState state) {
|
||||
return (((config & CFG_WATERLOGGABLE) != 0) && state.getValue(WATERLOGGED)) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
|
||||
if (((config & CFG_WATERLOGGABLE) != 0) && (state.getValue(WATERLOGGED)))
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override // SimpleWaterloggedBlock
|
||||
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
|
||||
return ((config & CFG_WATERLOGGABLE) != 0) && SimpleWaterloggedBlock.super.canPlaceLiquid(world, pos, state, fluid);
|
||||
}
|
||||
|
||||
@Override // SimpleWaterloggedBlock
|
||||
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
|
||||
return ((config & CFG_WATERLOGGABLE) != 0) && SimpleWaterloggedBlock.super.placeLiquid(world, pos, state, fluidState);
|
||||
}
|
||||
|
||||
@Override // SimpleWaterloggedBlock
|
||||
public ItemStack pickupBlock(LevelAccessor world, BlockPos pos, BlockState state) {
|
||||
return ((config & CFG_WATERLOGGABLE) != 0) ? (SimpleWaterloggedBlock.super.pickupBlock(world, pos, state)) : (ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override // SimpleWaterloggedBlock
|
||||
public Optional<SoundEvent> getPickupSound() {
|
||||
return ((config & CFG_WATERLOGGABLE) != 0) ? (SimpleWaterloggedBlock.super.getPickupSound()) : Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Cutout extends BaseBlock implements IStandardBlock {
|
||||
private final VoxelShape vshape;
|
||||
|
||||
public Cutout(long conf, BlockBehaviour.Properties properties) {
|
||||
this(conf, properties, Auxiliaries.getPixeledAABB(0, 0, 0, 16, 16, 16));
|
||||
}
|
||||
|
||||
public Cutout(long conf, BlockBehaviour.Properties properties, AABB aabb) {
|
||||
this(conf, properties, Shapes.create(aabb));
|
||||
}
|
||||
|
||||
public Cutout(long conf, BlockBehaviour.Properties properties, AABB[] aabbs) {
|
||||
this(conf, properties, Arrays.stream(aabbs).map(Shapes::create).reduce(Shapes.empty(), (shape, aabb) -> Shapes.joinUnoptimized(shape, aabb, BooleanOp.OR)));
|
||||
}
|
||||
|
||||
public Cutout(long conf, BlockBehaviour.Properties properties, VoxelShape voxel_shape) {
|
||||
super(conf, properties);
|
||||
vshape = voxel_shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
|
||||
return vshape;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return vshape;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
BlockState state = super.getStateForPlacement(context);
|
||||
if ((config & CFG_WATERLOGGABLE) != 0) {
|
||||
FluidState fs = context.getLevel().getFluidState(context.getClickedPos());
|
||||
state = state.setValue(WATERLOGGED, fs.getType() == Fluids.WATER);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public PushReaction getPistonPushReaction(BlockState state) {
|
||||
return PushReaction.NORMAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
|
||||
if ((config & CFG_WATERLOGGABLE) != 0) {
|
||||
if (state.getValue(WATERLOGGED)) return false;
|
||||
}
|
||||
return super.propagatesSkylightDown(state, reader, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public FluidState getFluidState(BlockState state) {
|
||||
if ((config & CFG_WATERLOGGABLE) != 0) {
|
||||
return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
|
||||
}
|
||||
return super.getFluidState(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
|
||||
if ((config & CFG_WATERLOGGABLE) != 0) {
|
||||
if (state.getValue(WATERLOGGED))
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
public static class WaterLoggable extends Cutout implements IStandardBlock {
|
||||
public WaterLoggable(long config, BlockBehaviour.Properties properties) {
|
||||
super(config | CFG_WATERLOGGABLE, properties);
|
||||
}
|
||||
|
||||
public WaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, aabb);
|
||||
}
|
||||
|
||||
public WaterLoggable(long config, BlockBehaviour.Properties properties, VoxelShape voxel_shape) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, voxel_shape);
|
||||
}
|
||||
|
||||
public WaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, aabbs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(WATERLOGGED);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Directed extends Cutout implements IStandardBlock {
|
||||
public static final DirectionProperty FACING = BlockStateProperties.FACING;
|
||||
protected final Map<BlockState, VoxelShape> vshapes;
|
||||
|
||||
public Directed(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
|
||||
super(config, properties);
|
||||
registerDefaultState(super.defaultBlockState().setValue(FACING, Direction.UP));
|
||||
vshapes = shape_supplier.apply(getStateDefinition().getPossibleStates());
|
||||
}
|
||||
|
||||
public Directed(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
|
||||
this(config, properties, (states) -> {
|
||||
final Map<BlockState, VoxelShape> vshapes = new HashMap<>();
|
||||
final ArrayList<VoxelShape> indexed_shapes = shape_supplier.get();
|
||||
for (BlockState state : states)
|
||||
vshapes.put(state, indexed_shapes.get(state.getValue(FACING).get3DDataValue()));
|
||||
return vshapes;
|
||||
});
|
||||
}
|
||||
|
||||
public Directed(long config, BlockBehaviour.Properties properties, final AABB[] unrotatedAABBs) {
|
||||
this(config, properties, (states) -> {
|
||||
final boolean is_horizontal = ((config & CFG_HORIZIONTAL) != 0);
|
||||
Map<BlockState, VoxelShape> vshapes = new HashMap<>();
|
||||
for (BlockState state : states) {
|
||||
vshapes.put(state, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, state.getValue(FACING), is_horizontal)));
|
||||
}
|
||||
return vshapes;
|
||||
});
|
||||
}
|
||||
|
||||
public Directed(long config, BlockBehaviour.Properties properties, final AABB unrotatedAABB) {
|
||||
this(config, properties, new AABB[]{unrotatedAABB});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
|
||||
return vshapes.get(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return getShape(state, world, pos, selectionContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(FACING);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
BlockState state = super.getStateForPlacement(context);
|
||||
if (state == null) return null;
|
||||
Direction facing = context.getClickedFace();
|
||||
if ((config & (CFG_HORIZIONTAL | CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL | CFG_LOOK_PLACEMENT)) {
|
||||
// horizontal placement in direction the player is looking
|
||||
facing = context.getHorizontalDirection();
|
||||
} else if ((config & (CFG_HORIZIONTAL | CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL)) {
|
||||
// horizontal placement on a face
|
||||
if (((facing == Direction.UP) || (facing == Direction.DOWN))) return null;
|
||||
} else if ((config & CFG_LOOK_PLACEMENT) != 0) {
|
||||
// placement in direction the player is looking, with up and down
|
||||
facing = context.getNearestLookingDirection();
|
||||
}
|
||||
if ((config & CFG_OPPOSITE_PLACEMENT) != 0) facing = facing.getOpposite();
|
||||
if (((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer() != null) && (context.getPlayer().isShiftKeyDown()))
|
||||
facing = facing.getOpposite();
|
||||
return state.setValue(FACING, facing);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AxisAligned extends Cutout implements IStandardBlock {
|
||||
public static final EnumProperty<Direction.Axis> AXIS = BlockStateProperties.AXIS;
|
||||
protected final ArrayList<VoxelShape> vshapes;
|
||||
|
||||
public AxisAligned(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
|
||||
super(config, properties);
|
||||
registerDefaultState(super.defaultBlockState().setValue(AXIS, Direction.Axis.X));
|
||||
vshapes = shape_supplier.get();
|
||||
}
|
||||
|
||||
public AxisAligned(long config, BlockBehaviour.Properties properties, final AABB[] unrotatedAABBs) {
|
||||
this(config, properties, () -> new ArrayList<>(Arrays.asList(
|
||||
Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, Direction.EAST, false)),
|
||||
Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, Direction.UP, false)),
|
||||
Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, Direction.SOUTH, false)),
|
||||
Shapes.block()
|
||||
)));
|
||||
}
|
||||
|
||||
public AxisAligned(long config, BlockBehaviour.Properties properties, final AABB unrotatedAABB) {
|
||||
this(config, properties, new AABB[]{unrotatedAABB});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
|
||||
return vshapes.get((state.getValue(AXIS)).ordinal() & 0x3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return getShape(state, world, pos, selectionContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(AXIS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
Direction facing;
|
||||
if ((config & CFG_LOOK_PLACEMENT) != 0) {
|
||||
facing = context.getNearestLookingDirection();
|
||||
} else {
|
||||
facing = context.getClickedFace();
|
||||
}
|
||||
return super.getStateForPlacement(context).setValue(AXIS, facing.getAxis());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState rotate(BlockState state, Rotation rotation) {
|
||||
switch (rotation) {
|
||||
case CLOCKWISE_90:
|
||||
case COUNTERCLOCKWISE_90:
|
||||
switch (state.getValue(AXIS)) {
|
||||
case X:
|
||||
return state.setValue(AXIS, Direction.Axis.Z);
|
||||
case Z:
|
||||
return state.setValue(AXIS, Direction.Axis.X);
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Horizontal extends Cutout implements IStandardBlock {
|
||||
public static final DirectionProperty HORIZONTAL_FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||
protected final Map<BlockState, VoxelShape> vshapes;
|
||||
protected final Map<BlockState, VoxelShape> cshapes;
|
||||
|
||||
public Horizontal(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
|
||||
super(config | CFG_HORIZIONTAL, properties);
|
||||
registerDefaultState(super.defaultBlockState().setValue(HORIZONTAL_FACING, Direction.NORTH));
|
||||
vshapes = shape_supplier.apply(getStateDefinition().getPossibleStates());
|
||||
cshapes = shape_supplier.apply(getStateDefinition().getPossibleStates());
|
||||
}
|
||||
|
||||
public Horizontal(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
|
||||
this(config, properties, (states) -> {
|
||||
final Map<BlockState, VoxelShape> vshapes = new HashMap<>();
|
||||
final ArrayList<VoxelShape> indexed_shapes = shape_supplier.get();
|
||||
for (BlockState state : states)
|
||||
vshapes.put(state, indexed_shapes.get(state.getValue(HORIZONTAL_FACING).get3DDataValue()));
|
||||
return vshapes;
|
||||
});
|
||||
}
|
||||
|
||||
public Horizontal(long config, BlockBehaviour.Properties properties, final AABB unrotatedAABB) {
|
||||
this(config, properties, new AABB[]{unrotatedAABB});
|
||||
}
|
||||
|
||||
public Horizontal(long config, BlockBehaviour.Properties properties, final AABB[] unrotatedAABBs) {
|
||||
this(config, properties, (states) -> {
|
||||
Map<BlockState, VoxelShape> vshapes = new HashMap<>();
|
||||
for (BlockState state : states) {
|
||||
vshapes.put(state, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, state.getValue(HORIZONTAL_FACING), true)));
|
||||
}
|
||||
return vshapes;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(HORIZONTAL_FACING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
|
||||
return vshapes.get(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return cshapes.get(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
BlockState state = super.getStateForPlacement(context);
|
||||
if (state == null) return null;
|
||||
Direction facing = context.getClickedFace();
|
||||
if ((config & CFG_LOOK_PLACEMENT) != 0) {
|
||||
// horizontal placement in direction the player is looking
|
||||
facing = context.getHorizontalDirection();
|
||||
} else {
|
||||
// horizontal placement on a face
|
||||
facing = ((facing == Direction.UP) || (facing == Direction.DOWN)) ? (context.getHorizontalDirection()) : facing;
|
||||
}
|
||||
if ((config & CFG_OPPOSITE_PLACEMENT) != 0) facing = facing.getOpposite();
|
||||
if (((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer() != null) && (context.getPlayer().isShiftKeyDown()))
|
||||
facing = facing.getOpposite();
|
||||
return state.setValue(HORIZONTAL_FACING, facing);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState rotate(BlockState state, Rotation rot) {
|
||||
return state.setValue(HORIZONTAL_FACING, rot.rotate(state.getValue(HORIZONTAL_FACING)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
||||
return state.rotate(mirrorIn.getRotation(state.getValue(HORIZONTAL_FACING)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class DirectedWaterLoggable extends Directed implements IStandardBlock {
|
||||
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, aabb);
|
||||
}
|
||||
|
||||
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, aabbs);
|
||||
}
|
||||
|
||||
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, shape_supplier);
|
||||
}
|
||||
|
||||
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, shape_supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(WATERLOGGED);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AxisAlignedWaterLoggable extends AxisAligned implements IStandardBlock {
|
||||
public AxisAlignedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, aabb);
|
||||
}
|
||||
|
||||
public AxisAlignedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, aabbs);
|
||||
}
|
||||
|
||||
public AxisAlignedWaterLoggable(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
|
||||
super(config | CFG_WATERLOGGABLE, properties, shape_supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(WATERLOGGED);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HorizontalWaterLoggable extends Horizontal implements IStandardBlock {
|
||||
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
|
||||
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, aabb);
|
||||
}
|
||||
|
||||
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
|
||||
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, aabbs);
|
||||
}
|
||||
|
||||
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
|
||||
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, shape_supplier);
|
||||
}
|
||||
|
||||
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
|
||||
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, shape_supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(WATERLOGGED);
|
||||
}
|
||||
}
|
||||
|
||||
static public class HorizontalFourWayWaterLoggable extends WaterLoggable implements IStandardBlock {
|
||||
public static final BooleanProperty NORTH = BlockStateProperties.NORTH;
|
||||
public static final BooleanProperty EAST = BlockStateProperties.EAST;
|
||||
public static final BooleanProperty SOUTH = BlockStateProperties.SOUTH;
|
||||
public static final BooleanProperty WEST = BlockStateProperties.WEST;
|
||||
protected final Map<BlockState, VoxelShape> shapes;
|
||||
protected final Map<BlockState, VoxelShape> collision_shapes;
|
||||
|
||||
public HorizontalFourWayWaterLoggable(long config, BlockBehaviour.Properties properties, AABB base_aabb, final AABB[] side_aabb, int railing_height_extension) {
|
||||
super(config, properties, base_aabb);
|
||||
Map<BlockState, VoxelShape> build_shapes = new HashMap<>();
|
||||
Map<BlockState, VoxelShape> build_collision_shapes = new HashMap<>();
|
||||
for (BlockState state : getStateDefinition().getPossibleStates()) {
|
||||
{
|
||||
VoxelShape shape = ((base_aabb.getXsize() == 0) || (base_aabb.getYsize() == 0) || (base_aabb.getZsize() == 0)) ? Shapes.empty() : Shapes.create(base_aabb);
|
||||
if (state.getValue(NORTH))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.NORTH, true)), BooleanOp.OR);
|
||||
if (state.getValue(EAST))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.EAST, true)), BooleanOp.OR);
|
||||
if (state.getValue(SOUTH))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.SOUTH, true)), BooleanOp.OR);
|
||||
if (state.getValue(WEST))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.WEST, true)), BooleanOp.OR);
|
||||
if (shape.isEmpty()) shape = Shapes.block();
|
||||
build_shapes.put(state.setValue(WATERLOGGED, false), shape);
|
||||
build_shapes.put(state.setValue(WATERLOGGED, true), shape);
|
||||
}
|
||||
{
|
||||
// how the hack to extend a shape, these are the above with y+4px.
|
||||
VoxelShape shape = ((base_aabb.getXsize() == 0) || (base_aabb.getYsize() == 0) || (base_aabb.getZsize() == 0)) ? Shapes.empty() : Shapes.create(base_aabb);
|
||||
if (state.getValue(NORTH))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
|
||||
Direction.NORTH, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
|
||||
if (state.getValue(EAST))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
|
||||
Direction.EAST, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
|
||||
if (state.getValue(SOUTH))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
|
||||
Direction.SOUTH, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
|
||||
if (state.getValue(WEST))
|
||||
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
|
||||
Direction.WEST, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
|
||||
if (shape.isEmpty()) shape = Shapes.block();
|
||||
build_collision_shapes.put(state.setValue(WATERLOGGED, false), shape);
|
||||
build_collision_shapes.put(state.setValue(WATERLOGGED, true), shape);
|
||||
}
|
||||
}
|
||||
shapes = build_shapes;
|
||||
collision_shapes = build_collision_shapes;
|
||||
registerDefaultState(super.defaultBlockState().setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false).setValue(WATERLOGGED, false));
|
||||
}
|
||||
|
||||
public HorizontalFourWayWaterLoggable(long config, BlockBehaviour.Properties properties, AABB base_aabb, final AABB side_aabb, int railing_height_extension) {
|
||||
this(config, properties, base_aabb, new AABB[]{side_aabb}, railing_height_extension);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(NORTH, EAST, SOUTH, WEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
return super.getStateForPlacement(context).setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
|
||||
return shapes.getOrDefault(state, Shapes.block());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
|
||||
return collision_shapes.getOrDefault(state, Shapes.block());
|
||||
}
|
||||
|
||||
public static BooleanProperty getDirectionProperty(Direction face) {
|
||||
return switch (face) {
|
||||
case EAST -> HorizontalFourWayWaterLoggable.EAST;
|
||||
case SOUTH -> HorizontalFourWayWaterLoggable.SOUTH;
|
||||
case WEST -> HorizontalFourWayWaterLoggable.WEST;
|
||||
default -> HorizontalFourWayWaterLoggable.NORTH;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* @file StandardDoorBlock.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Door blocks, almost entirely based on vanilla.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.DoorBlock;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockSetType;
|
||||
import net.minecraft.world.level.block.state.properties.DoorHingeSide;
|
||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.shapes.BooleanOp;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class StandardDoorBlock extends DoorBlock implements StandardBlocks.IStandardBlock {
|
||||
private final long config_;
|
||||
protected final VoxelShape[][][][] shapes_;
|
||||
protected final SoundEvent open_sound_;
|
||||
protected final SoundEvent close_sound_;
|
||||
|
||||
public StandardDoorBlock(long config, BlockBehaviour.Properties properties, AABB[] open_aabbs_top, AABB[] open_aabbs_bottom, AABB[] closed_aabbs_top, AABB[] closed_aabbs_bottom, SoundEvent open_sound, SoundEvent close_sound, BlockSetType blockSetType) {
|
||||
super(properties, blockSetType);
|
||||
VoxelShape[][][][] shapes = new VoxelShape[Direction.values().length][2][2][2];
|
||||
for (Direction facing : Direction.values()) {
|
||||
for (boolean open : new boolean[]{false, true}) {
|
||||
for (DoubleBlockHalf half : new DoubleBlockHalf[]{DoubleBlockHalf.UPPER, DoubleBlockHalf.LOWER}) {
|
||||
for (boolean hinge_right : new boolean[]{false, true}) {
|
||||
VoxelShape shape = Shapes.empty();
|
||||
if (facing.getAxis() == Direction.Axis.Y) {
|
||||
shape = Shapes.block();
|
||||
} else {
|
||||
final AABB[] aabbs = (open) ? ((half == DoubleBlockHalf.UPPER) ? open_aabbs_top : open_aabbs_bottom) : ((half == DoubleBlockHalf.UPPER) ? closed_aabbs_top : closed_aabbs_bottom);
|
||||
for (AABB e : aabbs) {
|
||||
AABB aabb = Auxiliaries.getRotatedAABB(e, facing, true);
|
||||
if (!hinge_right)
|
||||
aabb = Auxiliaries.getMirroredAABB(aabb, facing.getClockWise().getAxis());
|
||||
shape = Shapes.join(shape, Shapes.create(aabb), BooleanOp.OR);
|
||||
}
|
||||
}
|
||||
shapes[facing.ordinal()][open ? 1 : 0][hinge_right ? 1 : 0][half == DoubleBlockHalf.UPPER ? 0 : 1] = shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
config_ = config;
|
||||
shapes_ = shapes;
|
||||
open_sound_ = open_sound;
|
||||
close_sound_ = close_sound;
|
||||
}
|
||||
|
||||
public StandardDoorBlock(long config, BlockBehaviour.Properties properties, AABB open_aabb, AABB closed_aabb, SoundEvent open_sound, SoundEvent close_sound, BlockSetType blockSetType) {
|
||||
this(config, properties, new AABB[]{open_aabb}, new AABB[]{open_aabb}, new AABB[]{closed_aabb}, new AABB[]{closed_aabb}, open_sound, close_sound, blockSetType);
|
||||
}
|
||||
|
||||
public StandardDoorBlock(long config, BlockBehaviour.Properties properties, SoundEvent open_sound, SoundEvent close_sound, BlockSetType blockSetType) {
|
||||
this(
|
||||
config, properties,
|
||||
Auxiliaries.getPixeledAABB(13, 0, 0, 16, 16, 16),
|
||||
Auxiliaries.getPixeledAABB(0, 0, 13, 16, 16, 16),
|
||||
open_sound,
|
||||
close_sound,
|
||||
blockSetType
|
||||
);
|
||||
}
|
||||
|
||||
public StandardDoorBlock(long config, BlockBehaviour.Properties properties) {
|
||||
this(
|
||||
config, properties,
|
||||
Auxiliaries.getPixeledAABB(13, 0, 0, 16, 16, 16),
|
||||
Auxiliaries.getPixeledAABB(0, 0, 13, 16, 16, 16),
|
||||
SoundEvents.WOODEN_DOOR_OPEN,
|
||||
SoundEvents.WOODEN_DOOR_CLOSE,
|
||||
BlockSetType.OAK
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long config() {
|
||||
return config_;
|
||||
}
|
||||
|
||||
protected void sound(BlockGetter world, BlockPos pos, boolean open) {
|
||||
if (world instanceof Level)
|
||||
((Level) world).playSound(null, pos, open ? open_sound_ : close_sound_, SoundSource.BLOCKS, 0.7f, 1f);
|
||||
}
|
||||
|
||||
protected void actuate_adjacent_wing(BlockState state, BlockGetter world_ro, BlockPos pos, boolean open) {
|
||||
if (!(world_ro instanceof final Level world)) return;
|
||||
final BlockPos adjecent_pos = pos.relative((state.getValue(HINGE) == DoorHingeSide.LEFT) ? (state.getValue(FACING).getClockWise()) : (state.getValue(FACING).getCounterClockWise()));
|
||||
if (!world.isLoaded(adjecent_pos)) return;
|
||||
BlockState adjacent_state = world.getBlockState(adjecent_pos);
|
||||
if (adjacent_state.getBlock() != this) return;
|
||||
if (adjacent_state.getValue(OPEN) == open) return;
|
||||
world.setBlock(adjecent_pos, adjacent_state.setValue(OPEN, open), 2 | 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
|
||||
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
|
||||
return shapes_[state.getValue(FACING).ordinal()][state.getValue(OPEN) ? 1 : 0][state.getValue(HINGE) == DoorHingeSide.RIGHT ? 1 : 0][state.getValue(HALF) == DoubleBlockHalf.UPPER ? 0 : 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
setOpen(player, world, state, pos, !state.getValue(OPEN));
|
||||
return InteractionResult.sidedSuccess(world.isClientSide());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) {
|
||||
boolean powered = world.hasNeighborSignal(pos) || world.hasNeighborSignal(pos.relative(state.getValue(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN));
|
||||
if ((block == this) || (powered == state.getValue(POWERED))) return;
|
||||
world.setBlock(pos, state.setValue(POWERED, powered).setValue(OPEN, powered), 2);
|
||||
actuate_adjacent_wing(state, world, pos, powered);
|
||||
if (powered != state.getValue(OPEN)) sound(world, pos, powered);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOpen(@Nullable Entity entity, Level world, BlockState state, BlockPos pos, boolean open) {
|
||||
if (!state.is(this) || (state.getValue(OPEN) == open)) return;
|
||||
state = state.setValue(OPEN, open);
|
||||
world.setBlock(pos, state, 2 | 8);
|
||||
sound(world, pos, open);
|
||||
actuate_adjacent_wing(state, world, pos, open);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* @file StandardEntityBlocks.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Common functionality class for blocks with block entities.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEventListener;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
public class StandardEntityBlocks {
|
||||
public interface IStandardEntityBlock<ET extends StandardBlockEntity> extends EntityBlock {
|
||||
|
||||
default boolean isBlockEntityTicking(Level world, BlockState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default InteractionResult useOpenGui(BlockState state, Level world, BlockPos pos, Player player) {
|
||||
if (world.isClientSide()) return InteractionResult.SUCCESS;
|
||||
final BlockEntity te = world.getBlockEntity(pos);
|
||||
if (!(te instanceof MenuProvider) || ((player instanceof FakePlayer))) return InteractionResult.FAIL;
|
||||
player.openMenu((MenuProvider) te);
|
||||
return InteractionResult.CONSUME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||
BlockEntityType<?> tet = Registries.getBlockEntityTypeOfBlock(state.getBlock());
|
||||
return (tet == null) ? null : tet.create(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level world, BlockState state, BlockEntityType<T> te_type) {
|
||||
return (world.isClientSide || (!isBlockEntityTicking(world, state))) ? (null) : ((Level w, BlockPos p, BlockState s, T te) -> ((StandardBlockEntity) te).tick());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default <T extends BlockEntity> GameEventListener getListener(ServerLevel world, T te) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class StandardBlockEntity extends BlockEntity {
|
||||
public StandardBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
* @file StandardFenceBlock.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Wall blocks.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.FenceGateBlock;
|
||||
import net.minecraft.world.level.block.WallBlock;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.level.block.state.properties.WallSide;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class StandardFenceBlock extends WallBlock implements StandardBlocks.IStandardBlock {
|
||||
public static final BooleanProperty UP = BlockStateProperties.UP;
|
||||
public static final EnumProperty<WallSide> WALL_EAST = BlockStateProperties.EAST_WALL;
|
||||
public static final EnumProperty<WallSide> WALL_NORTH = BlockStateProperties.NORTH_WALL;
|
||||
public static final EnumProperty<WallSide> WALL_SOUTH = BlockStateProperties.SOUTH_WALL;
|
||||
public static final EnumProperty<WallSide> WALL_WEST = BlockStateProperties.WEST_WALL;
|
||||
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||
private final Map<BlockState, VoxelShape> shape_voxels;
|
||||
private final Map<BlockState, VoxelShape> collision_shape_voxels;
|
||||
private final long config;
|
||||
|
||||
public StandardFenceBlock(long config, BlockBehaviour.Properties properties) {
|
||||
this(config, properties, 1.5, 16, 1.5, 0, 14, 16);
|
||||
}
|
||||
|
||||
public StandardFenceBlock(long config, BlockBehaviour.Properties properties, double pole_width, double pole_height, double side_width, double side_min_y, double side_max_low_y, double side_max_tall_y) {
|
||||
super(properties);
|
||||
shape_voxels = buildShapes(pole_width, pole_height, side_width, side_min_y, side_max_low_y, side_max_tall_y);
|
||||
collision_shape_voxels = buildShapes(pole_width, 24, pole_width, 0, 24, 24);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long config() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
|
||||
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
|
||||
}
|
||||
|
||||
private static VoxelShape combinedShape(VoxelShape pole, WallSide height, VoxelShape low, VoxelShape high) {
|
||||
if (height == WallSide.TALL) return Shapes.or(pole, high);
|
||||
if (height == WallSide.LOW) return Shapes.or(pole, low);
|
||||
return pole;
|
||||
}
|
||||
|
||||
protected Map<BlockState, VoxelShape> buildShapes(double pole_width, double pole_height, double side_width, double side_min_y, double side_max_low_y, double side_max_tall_y) {
|
||||
final double px0 = 8.0 - pole_width, px1 = 8.0 + pole_width, sx0 = 8.0 - side_width, sx1 = 8.0 + side_width;
|
||||
VoxelShape vp = Block.box(px0, 0, px0, px1, pole_height, px1);
|
||||
VoxelShape vs1 = Block.box(sx0, side_min_y, 0, sx1, side_max_low_y, sx1);
|
||||
VoxelShape vs2 = Block.box(sx0, side_min_y, sx0, sx1, side_max_low_y, 16);
|
||||
VoxelShape vs3 = Block.box(0, side_min_y, sx0, sx1, side_max_low_y, sx1);
|
||||
VoxelShape vs4 = Block.box(sx0, side_min_y, sx0, 16, side_max_low_y, sx1);
|
||||
VoxelShape vs5 = Block.box(sx0, side_min_y, 0, sx1, side_max_tall_y, sx1);
|
||||
VoxelShape vs6 = Block.box(sx0, side_min_y, sx0, sx1, side_max_tall_y, 16);
|
||||
VoxelShape vs7 = Block.box(0, side_min_y, sx0, sx1, side_max_tall_y, sx1);
|
||||
VoxelShape vs8 = Block.box(sx0, side_min_y, sx0, 16, side_max_tall_y, sx1);
|
||||
ImmutableMap.Builder<BlockState, VoxelShape> builder = ImmutableMap.builder();
|
||||
for (Boolean up : UP.getPossibleValues()) {
|
||||
for (WallSide wh_east : WALL_EAST.getPossibleValues()) {
|
||||
for (WallSide wh_north : WALL_NORTH.getPossibleValues()) {
|
||||
for (WallSide wh_west : WALL_WEST.getPossibleValues()) {
|
||||
for (WallSide wh_south : WALL_SOUTH.getPossibleValues()) {
|
||||
VoxelShape shape = Shapes.empty();
|
||||
shape = combinedShape(shape, wh_east, vs4, vs8);
|
||||
shape = combinedShape(shape, wh_west, vs3, vs7);
|
||||
shape = combinedShape(shape, wh_north, vs1, vs5);
|
||||
shape = combinedShape(shape, wh_south, vs2, vs6);
|
||||
if (up) shape = Shapes.or(shape, vp);
|
||||
BlockState bs = defaultBlockState().setValue(UP, up)
|
||||
.setValue(WALL_EAST, wh_east)
|
||||
.setValue(WALL_NORTH, wh_north)
|
||||
.setValue(WALL_WEST, wh_west)
|
||||
.setValue(WALL_SOUTH, wh_south);
|
||||
builder.put(bs.setValue(WATERLOGGED, false), shape);
|
||||
builder.put(bs.setValue(WATERLOGGED, true), shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return shape_voxels.getOrDefault(state, Shapes.block());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return collision_shape_voxels.getOrDefault(state, Shapes.block());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
}
|
||||
|
||||
protected boolean attachesTo(BlockState facingState, LevelReader world, BlockPos facingPos, Direction side) {
|
||||
final Block block = facingState.getBlock();
|
||||
if ((block instanceof FenceGateBlock) || (block instanceof StandardFenceBlock) || (block instanceof VariantWallBlock))
|
||||
return true;
|
||||
final BlockState oppositeState = world.getBlockState(facingPos.relative(side, 2));
|
||||
if (!(oppositeState.getBlock() instanceof StandardFenceBlock)) return false;
|
||||
return facingState.isRedstoneConductor(world, facingPos) && canSupportCenter(world, facingPos, side);
|
||||
}
|
||||
|
||||
protected WallSide selectWallHeight(LevelReader world, BlockPos pos, Direction direction) {
|
||||
return WallSide.LOW; // @todo: implement
|
||||
}
|
||||
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
LevelReader world = context.getLevel();
|
||||
BlockPos pos = context.getClickedPos();
|
||||
FluidState fs = context.getLevel().getFluidState(context.getClickedPos());
|
||||
boolean n = attachesTo(world.getBlockState(pos.north()), world, pos.north(), Direction.SOUTH);
|
||||
boolean e = attachesTo(world.getBlockState(pos.east()), world, pos.east(), Direction.WEST);
|
||||
boolean s = attachesTo(world.getBlockState(pos.south()), world, pos.south(), Direction.NORTH);
|
||||
boolean w = attachesTo(world.getBlockState(pos.west()), world, pos.west(), Direction.EAST);
|
||||
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
|
||||
return defaultBlockState()
|
||||
.setValue(UP, not_straight)
|
||||
.setValue(WALL_NORTH, n ? selectWallHeight(world, pos, Direction.NORTH) : WallSide.NONE)
|
||||
.setValue(WALL_EAST, e ? selectWallHeight(world, pos, Direction.EAST) : WallSide.NONE)
|
||||
.setValue(WALL_SOUTH, s ? selectWallHeight(world, pos, Direction.SOUTH) : WallSide.NONE)
|
||||
.setValue(WALL_WEST, w ? selectWallHeight(world, pos, Direction.WEST) : WallSide.NONE)
|
||||
.setValue(WATERLOGGED, fs.getType() == Fluids.WATER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState state, Direction side, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
|
||||
if (state.getValue(BlockStateProperties.WATERLOGGED))
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
|
||||
if (side == Direction.DOWN) return super.updateShape(state, side, facingState, world, pos, facingPos);
|
||||
boolean n = (side == Direction.NORTH) ? attachesTo(facingState, world, facingPos, side) : (state.getValue(WALL_NORTH) != WallSide.NONE);
|
||||
boolean e = (side == Direction.EAST) ? attachesTo(facingState, world, facingPos, side) : (state.getValue(WALL_EAST) != WallSide.NONE);
|
||||
boolean s = (side == Direction.SOUTH) ? attachesTo(facingState, world, facingPos, side) : (state.getValue(WALL_SOUTH) != WallSide.NONE);
|
||||
boolean w = (side == Direction.WEST) ? attachesTo(facingState, world, facingPos, side) : (state.getValue(WALL_WEST) != WallSide.NONE);
|
||||
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
|
||||
return state.setValue(UP, not_straight)
|
||||
.setValue(WALL_NORTH, n ? selectWallHeight(world, pos, Direction.NORTH) : WallSide.NONE)
|
||||
.setValue(WALL_EAST, e ? selectWallHeight(world, pos, Direction.EAST) : WallSide.NONE)
|
||||
.setValue(WALL_SOUTH, s ? selectWallHeight(world, pos, Direction.SOUTH) : WallSide.NONE)
|
||||
.setValue(WALL_WEST, w ? selectWallHeight(world, pos, Direction.WEST) : WallSide.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public PushReaction getPistonPushReaction(BlockState state) {
|
||||
return PushReaction.NORMAL;
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* @file StandardStairsBlock.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Stairs and roof blocks, almost entirely based on vanilla stairs.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.block.StairBlock;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class StandardStairsBlock extends StairBlock implements StandardBlocks.IStandardBlock {
|
||||
private final long config;
|
||||
|
||||
public StandardStairsBlock(long config, java.util.function.Supplier<BlockState> state, BlockBehaviour.Properties properties) {
|
||||
super(state, properties);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
|
||||
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public PushReaction getPistonPushReaction(BlockState state) {
|
||||
return PushReaction.NORMAL;
|
||||
}
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* @file Tooltip.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Delayed tooltip for a selected area. Constructed with a
|
||||
* GUI, invoked in `render()`.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.network.chat.*;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class TooltipDisplay {
|
||||
private static long default_delay = 800;
|
||||
private static int default_max_deviation = 1;
|
||||
|
||||
public static void config(long delay, int max_deviation) {
|
||||
default_delay = clamp(delay, 500, 5000);
|
||||
default_max_deviation = Mth.clamp(max_deviation, 1, 5);
|
||||
}
|
||||
private static long clamp(long p1, long a, long b) {
|
||||
return p1 < a ? a : Math.min(p1, b);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
|
||||
public static class TipRange {
|
||||
public final int x0, y0, x1, y1;
|
||||
public final Supplier<Component> text;
|
||||
|
||||
public TipRange(int x, int y, int w, int h, Component text) {
|
||||
this(x, y, w, h, () -> text);
|
||||
}
|
||||
|
||||
public TipRange(int x, int y, int w, int h, Supplier<Component> text) {
|
||||
this.text = text;
|
||||
this.x0 = x;
|
||||
this.y0 = y;
|
||||
this.x1 = x0 + w - 1;
|
||||
this.y1 = y0 + h - 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
|
||||
private List<TipRange> ranges = new ArrayList<>();
|
||||
private long delay = default_delay;
|
||||
private int max_deviation = default_max_deviation;
|
||||
private int x_last, y_last;
|
||||
private long t;
|
||||
private static boolean had_render_exception = false;
|
||||
|
||||
public TooltipDisplay() {
|
||||
t = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public TooltipDisplay init(List<TipRange> ranges, long delay_ms, int max_deviation_xy) {
|
||||
this.ranges = ranges;
|
||||
this.delay = delay_ms;
|
||||
this.max_deviation = max_deviation_xy;
|
||||
t = System.currentTimeMillis();
|
||||
x_last = y_last = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TooltipDisplay init(List<TipRange> ranges) {
|
||||
return init(ranges, default_delay, default_max_deviation);
|
||||
}
|
||||
|
||||
public TooltipDisplay init(TipRange... ranges) {
|
||||
return init(Arrays.asList(ranges), default_delay, default_max_deviation);
|
||||
}
|
||||
|
||||
public TooltipDisplay delay(int ms) {
|
||||
delay = (ms <= 0) ? default_delay : ms;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void resetTimer() {
|
||||
t = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public <T extends AbstractContainerMenu> boolean render(GuiGraphics mx, final AbstractContainerScreen<T> gui, int x, int y) {
|
||||
if (had_render_exception) return false;
|
||||
if ((Math.abs(x - x_last) > max_deviation) || (Math.abs(y - y_last) > max_deviation)) {
|
||||
x_last = x;
|
||||
y_last = y;
|
||||
resetTimer();
|
||||
return false;
|
||||
} else if (Math.abs(System.currentTimeMillis() - t) < delay) {
|
||||
return false;
|
||||
} else if (ranges.stream().noneMatch(
|
||||
(tip) -> {
|
||||
if ((x < tip.x0) || (x > tip.x1) || (y < tip.y0) || (y > tip.y1)) return false;
|
||||
String text = tip.text.get().toString();
|
||||
if (text.isEmpty()) return false;
|
||||
try {
|
||||
mx.renderComponentTooltip(Minecraft.getInstance().font, tip.text.get().toFlatList(Style.EMPTY), x, y);
|
||||
} catch (Exception ex) {
|
||||
had_render_exception = true;
|
||||
Auxiliaries.logError("Tooltip rendering disabled due to exception: '" + ex.getMessage() + "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
) {
|
||||
resetTimer();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* @file VariantSlabBlock.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Standard half block horizontal slab characteristics class.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||
import net.minecraft.world.level.block.state.properties.SlabType;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class VariantSlabBlock extends StandardBlocks.WaterLoggable implements StandardBlocks.IStandardBlock {
|
||||
public static final EnumProperty<SlabType> TYPE = BlockStateProperties.SLAB_TYPE;
|
||||
public static final IntegerProperty TEXTURE_VARIANT = IntegerProperty.create("tvariant", 0, 3);
|
||||
|
||||
protected static final VoxelShape[] AABBs = {
|
||||
Shapes.create(new AABB(0, 8. / 16, 0, 1, 16. / 16, 1)), // top slab
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 8. / 16, 1)), // bottom slab
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 16. / 16, 1)), // both slabs
|
||||
Shapes.create(new AABB(0, 0. / 16, 0, 1, 16. / 16, 1)) // << 2bit fill
|
||||
};
|
||||
protected static final int[] num_slabs_contained_in_parts_ = {1, 1, 2, 2};
|
||||
private static boolean with_pickup = false;
|
||||
|
||||
public static void on_config(boolean direct_slab_pickup) {
|
||||
with_pickup = direct_slab_pickup;
|
||||
}
|
||||
|
||||
protected boolean is_cube(BlockState state) {
|
||||
return state.getValue(TYPE) == SlabType.DOUBLE;
|
||||
}
|
||||
|
||||
public VariantSlabBlock(long config, BlockBehaviour.Properties builder) {
|
||||
super(config, builder);
|
||||
registerDefaultState(defaultBlockState().setValue(TYPE, SlabType.BOTTOM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderTypeHint getRenderTypeHint() {
|
||||
return (((config & StandardBlocks.CFG_TRANSLUCENT) != 0) ? (RenderTypeHint.TRANSLUCENT) : (RenderTypeHint.CUTOUT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
|
||||
if (!Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true)) return;
|
||||
if (with_pickup && Auxiliaries.Tooltip.helpCondition())
|
||||
Auxiliaries.Tooltip.addInformation("engineersdecor.tooltip.slabpickup", "engineersdecor.tooltip.slabpickup", tooltip, flag, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) {
|
||||
return (adjacentBlockState == state) || (super.skipRendering(state, adjacentBlockState, side));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
|
||||
return AABBs[state.getValue(TYPE).ordinal() & 0x3];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return getShape(state, world, pos, selectionContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(TYPE, TEXTURE_VARIANT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
BlockPos pos = context.getClickedPos();
|
||||
if (context.getLevel().getBlockState(pos).getBlock() == this)
|
||||
return context.getLevel().getBlockState(pos).setValue(TYPE, SlabType.DOUBLE).setValue(WATERLOGGED, false);
|
||||
final int rnd = Mth.clamp((int) (Mth.getSeed(context.getClickedPos()) & 0x3), 0, 3);
|
||||
final Direction face = context.getClickedFace();
|
||||
final BlockState placement_state = super.getStateForPlacement(context).setValue(TEXTURE_VARIANT, rnd); // fluid state
|
||||
if (face == Direction.UP) return placement_state.setValue(TYPE, SlabType.BOTTOM);
|
||||
if (face == Direction.DOWN) return placement_state.setValue(TYPE, SlabType.TOP);
|
||||
if (!face.getAxis().isHorizontal()) return placement_state;
|
||||
final boolean isupper = ((context.getClickLocation().y() - context.getClickedPos().getY()) > 0.5);
|
||||
return placement_state.setValue(TYPE, isupper ? SlabType.TOP : SlabType.BOTTOM);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean canBeReplaced(BlockState state, BlockPlaceContext context) {
|
||||
if (context.getItemInHand().getItem() != this.asItem()) return false;
|
||||
if (!context.replacingClickedOnBlock()) return true;
|
||||
final Direction face = context.getClickedFace();
|
||||
final SlabType type = state.getValue(TYPE);
|
||||
if ((face == Direction.UP) && (type == SlabType.BOTTOM)) return true;
|
||||
if ((face == Direction.DOWN) && (type == SlabType.TOP)) return true;
|
||||
if (!face.getAxis().isHorizontal()) return false;
|
||||
final boolean isupper = ((context.getClickLocation().y() - context.getClickedPos().getY()) > 0.5);
|
||||
return isupper ? (type == SlabType.BOTTOM) : (type == SlabType.TOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState rotate(BlockState state, Rotation rot) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDynamicDropList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion) {
|
||||
return new ArrayList<>(Collections.singletonList(new ItemStack(this.asItem(), num_slabs_contained_in_parts_[state.getValue(TYPE).ordinal() & 0x3])));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void attack(BlockState state, Level world, BlockPos pos, Player player) {
|
||||
if ((world.isClientSide) || (!with_pickup)) return;
|
||||
final ItemStack stack = player.getMainHandItem();
|
||||
if (stack.isEmpty() || (Block.byItem(stack.getItem()) != this)) return;
|
||||
if (stack.getCount() >= stack.getMaxStackSize()) return;
|
||||
Vec3 lv = player.getLookAngle();
|
||||
Direction facing = Direction.getNearest((float) lv.x, (float) lv.y, (float) lv.z);
|
||||
if ((facing != Direction.UP) && (facing != Direction.DOWN)) return;
|
||||
if (state.getBlock() != this) return;
|
||||
SlabType type = state.getValue(TYPE);
|
||||
if (facing == Direction.DOWN) {
|
||||
if (type == SlabType.DOUBLE) {
|
||||
world.setBlock(pos, state.setValue(TYPE, SlabType.BOTTOM), 3);
|
||||
} else {
|
||||
world.removeBlock(pos, false);
|
||||
}
|
||||
} else if (facing == Direction.UP) {
|
||||
if (type == SlabType.DOUBLE) {
|
||||
world.setBlock(pos, state.setValue(TYPE, SlabType.TOP), 3);
|
||||
} else {
|
||||
world.removeBlock(pos, false);
|
||||
}
|
||||
}
|
||||
if (!player.isCreative()) {
|
||||
stack.grow(1);
|
||||
if (player.getInventory() != null) player.getInventory().setChanged();
|
||||
}
|
||||
SoundType st = this.getSoundType(state, world, pos, null);
|
||||
world.playSound(player, pos, st.getPlaceSound(), SoundSource.BLOCKS, (st.getVolume() + 1f) / 2.5f, 0.9f * st.getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
|
||||
return (state.getValue(TYPE) != SlabType.DOUBLE) && super.placeLiquid(world, pos, state, fluidState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
|
||||
return (state.getValue(TYPE) != SlabType.DOUBLE) && super.canPlaceLiquid(world, pos, state, fluid);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* @file VariantWallBlock.java
|
||||
* @author Stefan Wilhelm (wile)
|
||||
* @copyright (C) 2020 Stefan Wilhelm
|
||||
* @license MIT (see https://opensource.org/licenses/MIT)
|
||||
*
|
||||
* Wall blocks.
|
||||
*/
|
||||
package dev.zontreck.libzontreck.edlibmc;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.FenceGateBlock;
|
||||
import net.minecraft.world.level.block.WallBlock;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.*;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.minecraft.world.level.material.PushReaction;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class VariantWallBlock extends WallBlock implements StandardBlocks.IStandardBlock {
|
||||
public static final BooleanProperty UP = BlockStateProperties.UP;
|
||||
public static final EnumProperty<WallSide> WALL_EAST = BlockStateProperties.EAST_WALL;
|
||||
public static final EnumProperty<WallSide> WALL_NORTH = BlockStateProperties.NORTH_WALL;
|
||||
public static final EnumProperty<WallSide> WALL_SOUTH = BlockStateProperties.SOUTH_WALL;
|
||||
public static final EnumProperty<WallSide> WALL_WEST = BlockStateProperties.WEST_WALL;
|
||||
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
|
||||
public static final IntegerProperty TEXTURE_VARIANT = IntegerProperty.create("tvariant", 0, 7);
|
||||
private final Map<BlockState, VoxelShape> shape_voxels;
|
||||
private final Map<BlockState, VoxelShape> collision_shape_voxels;
|
||||
private final long config;
|
||||
|
||||
public VariantWallBlock(long config, BlockBehaviour.Properties builder) {
|
||||
super(builder);
|
||||
shape_voxels = buildWallShapes(4, 16, 4, 0, 16, 16);
|
||||
collision_shape_voxels = buildWallShapes(6, 16, 5, 0, 24, 24);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long config() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
|
||||
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
|
||||
}
|
||||
|
||||
private static VoxelShape combinedShape(VoxelShape pole, WallSide height, VoxelShape low, VoxelShape high) {
|
||||
if (height == WallSide.TALL) return Shapes.or(pole, high);
|
||||
if (height == WallSide.LOW) return Shapes.or(pole, low);
|
||||
return pole;
|
||||
}
|
||||
|
||||
protected Map<BlockState, VoxelShape> buildWallShapes(double pole_width, double pole_height, double side_width, double side_min_y, double side_max_low_y, double side_max_tall_y) {
|
||||
final double px0 = 8.0 - pole_width, px1 = 8.0 + pole_width, sx0 = 8.0 - side_width, sx1 = 8.0 + side_width;
|
||||
VoxelShape vp = Block.box(px0, 0, px0, px1, pole_height, px1);
|
||||
VoxelShape vs1 = Block.box(sx0, side_min_y, 0, sx1, side_max_low_y, sx1);
|
||||
VoxelShape vs2 = Block.box(sx0, side_min_y, sx0, sx1, side_max_low_y, 16);
|
||||
VoxelShape vs3 = Block.box(0, side_min_y, sx0, sx1, side_max_low_y, sx1);
|
||||
VoxelShape vs4 = Block.box(sx0, side_min_y, sx0, 16, side_max_low_y, sx1);
|
||||
VoxelShape vs5 = Block.box(sx0, side_min_y, 0, sx1, side_max_tall_y, sx1);
|
||||
VoxelShape vs6 = Block.box(sx0, side_min_y, sx0, sx1, side_max_tall_y, 16);
|
||||
VoxelShape vs7 = Block.box(0, side_min_y, sx0, sx1, side_max_tall_y, sx1);
|
||||
VoxelShape vs8 = Block.box(sx0, side_min_y, sx0, 16, side_max_tall_y, sx1);
|
||||
Builder<BlockState, VoxelShape> builder = ImmutableMap.builder();
|
||||
for (Boolean up : UP.getPossibleValues()) {
|
||||
for (WallSide wh_east : WALL_EAST.getPossibleValues()) {
|
||||
for (WallSide wh_north : WALL_NORTH.getPossibleValues()) {
|
||||
for (WallSide wh_west : WALL_WEST.getPossibleValues()) {
|
||||
for (WallSide wh_south : WALL_SOUTH.getPossibleValues()) {
|
||||
VoxelShape shape = Shapes.empty();
|
||||
shape = combinedShape(shape, wh_east, vs4, vs8);
|
||||
shape = combinedShape(shape, wh_west, vs3, vs7);
|
||||
shape = combinedShape(shape, wh_north, vs1, vs5);
|
||||
shape = combinedShape(shape, wh_south, vs2, vs6);
|
||||
if (up) shape = Shapes.or(shape, vp);
|
||||
BlockState bs = defaultBlockState().setValue(UP, up)
|
||||
.setValue(WALL_EAST, wh_east)
|
||||
.setValue(WALL_NORTH, wh_north)
|
||||
.setValue(WALL_WEST, wh_west)
|
||||
.setValue(WALL_SOUTH, wh_south);
|
||||
final VoxelShape tvs = shape;
|
||||
TEXTURE_VARIANT.getPossibleValues().forEach((tv) -> {
|
||||
builder.put(bs.setValue(TEXTURE_VARIANT, tv).setValue(WATERLOGGED, false), tvs);
|
||||
builder.put(bs.setValue(TEXTURE_VARIANT, tv).setValue(WATERLOGGED, true), tvs);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return shape_voxels.getOrDefault(state, Shapes.block());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
|
||||
return collision_shape_voxels.getOrDefault(state, Shapes.block());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
super.createBlockStateDefinition(builder);
|
||||
builder.add(TEXTURE_VARIANT);
|
||||
}
|
||||
|
||||
protected boolean attachesTo(BlockState facingState, LevelReader world, BlockPos facingPos, Direction side) {
|
||||
final Block block = facingState.getBlock();
|
||||
if ((block instanceof FenceGateBlock) || (block instanceof WallBlock)) return true;
|
||||
final BlockState oppositeState = world.getBlockState(facingPos.relative(side, 2));
|
||||
if (!(oppositeState.getBlock() instanceof VariantWallBlock)) return false;
|
||||
return facingState.isRedstoneConductor(world, facingPos) && Block.canSupportCenter(world, facingPos, side);
|
||||
}
|
||||
|
||||
protected WallSide selectWallHeight(LevelReader world, BlockPos pos, Direction direction) {
|
||||
return WallSide.LOW;
|
||||
}
|
||||
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
LevelReader world = context.getLevel();
|
||||
BlockPos pos = context.getClickedPos();
|
||||
FluidState fs = context.getLevel().getFluidState(context.getClickedPos());
|
||||
boolean n = attachesTo(world.getBlockState(pos.north()), world, pos.north(), Direction.SOUTH);
|
||||
boolean e = attachesTo(world.getBlockState(pos.east()), world, pos.east(), Direction.WEST);
|
||||
boolean s = attachesTo(world.getBlockState(pos.south()), world, pos.south(), Direction.NORTH);
|
||||
boolean w = attachesTo(world.getBlockState(pos.west()), world, pos.west(), Direction.EAST);
|
||||
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
|
||||
return defaultBlockState().setValue(UP, not_straight)
|
||||
.setValue(WALL_NORTH, n ? selectWallHeight(world, pos, Direction.NORTH) : WallSide.NONE)
|
||||
.setValue(WALL_EAST, e ? selectWallHeight(world, pos, Direction.EAST) : WallSide.NONE)
|
||||
.setValue(WALL_SOUTH, s ? selectWallHeight(world, pos, Direction.SOUTH) : WallSide.NONE)
|
||||
.setValue(WALL_WEST, w ? selectWallHeight(world, pos, Direction.WEST) : WallSide.NONE)
|
||||
.setValue(WATERLOGGED, fs.getType() == Fluids.WATER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState state, Direction side, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
|
||||
if (state.getValue(WATERLOGGED)) world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
|
||||
if (side == Direction.DOWN) return super.updateShape(state, side, facingState, world, pos, facingPos);
|
||||
boolean n = (side == Direction.NORTH) ? this.attachesTo(facingState, world, facingPos, side) : state.getValue(WALL_NORTH) != WallSide.NONE;
|
||||
boolean e = (side == Direction.EAST) ? this.attachesTo(facingState, world, facingPos, side) : state.getValue(WALL_EAST) != WallSide.NONE;
|
||||
boolean s = (side == Direction.SOUTH) ? this.attachesTo(facingState, world, facingPos, side) : state.getValue(WALL_SOUTH) != WallSide.NONE;
|
||||
boolean w = (side == Direction.WEST) ? this.attachesTo(facingState, world, facingPos, side) : state.getValue(WALL_WEST) != WallSide.NONE;
|
||||
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
|
||||
return state.setValue(UP, not_straight)
|
||||
.setValue(WALL_NORTH, n ? selectWallHeight(world, pos, Direction.NORTH) : WallSide.NONE)
|
||||
.setValue(WALL_EAST, e ? selectWallHeight(world, pos, Direction.EAST) : WallSide.NONE)
|
||||
.setValue(WALL_SOUTH, s ? selectWallHeight(world, pos, Direction.SOUTH) : WallSide.NONE)
|
||||
.setValue(WALL_WEST, w ? selectWallHeight(world, pos, Direction.WEST) : WallSide.NONE)
|
||||
.setValue(TEXTURE_VARIANT, ((int) Mth.getSeed(pos)) & 0x7);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPossibleToRespawnInThis(BlockState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public PushReaction getPistonPushReaction(BlockState state) {
|
||||
return PushReaction.NORMAL;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import dev.zontreck.ariaslib.terminal.Task;
|
|||
import dev.zontreck.ariaslib.util.DelayedExecutorService;
|
||||
import dev.zontreck.libzontreck.LibZontreck;
|
||||
import dev.zontreck.libzontreck.exceptions.InvalidSideException;
|
||||
import dev.zontreck.libzontreck.memory.PlayerContainer;
|
||||
import dev.zontreck.libzontreck.memory.player.PlayerContainer;
|
||||
import dev.zontreck.libzontreck.networking.ModMessages;
|
||||
import dev.zontreck.libzontreck.networking.packets.S2CServerAvailable;
|
||||
import dev.zontreck.libzontreck.networking.packets.S2CWalletInitialSyncPacket;
|
||||
|
|
|
@ -4,13 +4,13 @@ import dev.zontreck.libzontreck.api.Vector3;
|
|||
import dev.zontreck.libzontreck.exceptions.InvalidDeserialization;
|
||||
import dev.zontreck.libzontreck.vectors.WorldPosition;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public class SavedBlock implements Cloneable
|
||||
{
|
||||
|
@ -88,7 +88,7 @@ public class SavedBlock implements Cloneable
|
|||
{
|
||||
ServerLevel level = position.getActualDimension();
|
||||
|
||||
BlockState state = NbtUtils.readBlockState(level.holderLookup(Registries.BLOCK), blockState);
|
||||
BlockState state = NbtUtils.readBlockState(blockState);
|
||||
|
||||
return new PrimitiveBlock(this, state.getBlock(), state, blockEntity, position.Position.asBlockPos(), level);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package dev.zontreck.libzontreck.networking;
|
||||
|
||||
import dev.zontreck.libzontreck.LibZontreck;
|
||||
import dev.zontreck.libzontreck.events.RegisterPacketsEvent;
|
||||
import dev.zontreck.libzontreck.networking.packets.IPacket;
|
||||
import dev.zontreck.libzontreck.networking.packets.S2CCloseChestGUI;
|
||||
import dev.zontreck.libzontreck.networking.packets.S2CPlaySoundPacket;
|
||||
|
|
|
@ -6,6 +6,7 @@ import dev.zontreck.libzontreck.currency.events.WalletUpdatedEvent;
|
|||
import dev.zontreck.libzontreck.util.ServerUtilities;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
|
@ -63,8 +64,7 @@ public class S2CWalletUpdatedPacket implements IPacket
|
|||
return ServerUtilities.handlePacket(supplier, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Bus.Post(new WalletUpdatedEvent(ID, oldBal, balance, tx));
|
||||
|
||||
MinecraftForge.EVENT_BUS.post(new WalletUpdatedEvent(ID, oldBal, balance, tx));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public class WorldPosition implements Cloneable
|
|||
}
|
||||
|
||||
public WorldPosition(ServerPlayer player) {
|
||||
this(new Vector3d(player.position()), player.serverLevel());
|
||||
this(new Vector3d(player.position()), player.getLevel());
|
||||
}
|
||||
|
||||
public WorldPosition(Vector3d pos, ServerLevel lvl) {
|
||||
|
|
Reference in a new issue