Fix compilation errors

This commit is contained in:
zontreck 2024-09-12 18:00:40 -07:00
parent 21a40835b5
commit d86f5b87f1
29 changed files with 9 additions and 6622 deletions

View file

@ -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;
}

View file

@ -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.
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}
}

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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.
}
}

View file

@ -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 {
}
}

View file

@ -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));
}
}

View file

@ -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;
};
}
}
}

View file

@ -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);
}
}

View file

@ -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() {
}
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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));
}
});
}

View file

@ -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) {