Skip to content

Instantly share code, notes, and snippets.

@TechTastic
Created April 10, 2023 20:11
package net.techtastic.tat.sources;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.techtastic.tat.api.altar.source.IAltarSource;
import net.techtastic.tat.block.entity.AltarBlockEntity;
public class AltarBlockEntitySource implements IAltarSource {
private final AltarBlockEntity altar;
public AltarBlockEntitySource(AltarBlockEntity altar) {
this.altar = altar;
}
@Override
public double getMaxPower() {
return this.altar.getMaxPower();
}
@Override
public double getCurrentPower() {
return this.altar.getCurrentPower();
}
@Override
public double getRange() {
return this.altar.getRange();
}
@Override
public double getRate() {
return this.altar.getRate();
}
@Override
public void setMaxPower(double newMaxPower) {
this.altar.setMaxPower(newMaxPower);
}
@Override
public void setCurrentPower(double newPower) {
this.altar.setCurrentPower(newPower);
}
@Override
public void setRange(double newRange) {
this.altar.setRange(newRange);
}
@Override
public void setRate(double newRate) {
this.altar.setRate(newRate);
}
@Override
public boolean drawPowerFromAltar(Level level, BlockPos sink, BlockPos source, double amount) {
return this.altar.drawPowerFromAltar(level, sink, source, amount);
}
}
package net.techtastic.tat.api.altar.source;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
public class AltarSources {
private static final List<IAltarSourceProvider> providers = new ArrayList<>();
public static void registerAltarSourceProvider(IAltarSourceProvider provider) {
providers.add(provider);
}
public static IAltarSource testForAltarSource(Level level, BlockPos pos) {
if (pos == null) return null;
List<IAltarSourceProvider> currentProviders = new ArrayList<>(providers);
for (IAltarSourceProvider provider : currentProviders) {
Optional<IAltarSource> source = provider.getAltarSource(level, pos);
if (source.isPresent())
return source.get();
}
return null;
}
}
package net.techtastic.tat.block.entity;
import dev.architectury.registry.menu.ExtendedMenuProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.Containers;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.WorldlyContainer;
import net.minecraft.world.entity.player.Inventory;
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.ContainerData;
import net.minecraft.world.inventory.StackedContentsCompatible;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.techtastic.tat.api.altar.source.AltarSources;
import net.techtastic.tat.api.altar.source.IAltarSource;
import net.techtastic.tat.block.TATBlockEntities;
import net.techtastic.tat.block.custom.DistilleryBlock;
import net.techtastic.tat.item.TATItems;
import net.techtastic.tat.recipe.DistilleryRecipe;
import net.techtastic.tat.screen.DistilleryMenu;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class DistilleryBlockEntity extends BaseContainerBlockEntity implements StackedContentsCompatible, WorldlyContainer, ExtendedMenuProvider {
public NonNullList<ItemStack> inventory;
protected final ContainerData data;
private int craftProgress = 0;
private int maxCraftProgress = 38;
private int powerProgress = 0;
private int maxPowerProgress = 4;
private boolean hasAltar = false;
private int ticks = 1;
private BlockPos altarPos = null;
public DistilleryBlockEntity(BlockPos blockPos, BlockState blockState) {
super(TATBlockEntities.DISTILLERY_BLOCK_ENTITY.get(), blockPos, blockState);
this.inventory = NonNullList.withSize(7, ItemStack.EMPTY);
this.data = new ContainerData() {
@Override
public int get(int i) {
return switch (i) {
case 0 -> DistilleryBlockEntity.this.craftProgress;
case 1 -> DistilleryBlockEntity.this.maxCraftProgress;
case 2 -> DistilleryBlockEntity.this.powerProgress;
case 3 -> DistilleryBlockEntity.this.maxPowerProgress;
case 4 -> DistilleryBlockEntity.this.hasAltar ? 1 : 0;
default -> 0;
};
}
@Override
public void set(int i, int j) {
switch (i) {
case 0 -> DistilleryBlockEntity.this.craftProgress = j;
case 1 -> DistilleryBlockEntity.this.maxCraftProgress = j;
case 2 -> DistilleryBlockEntity.this.powerProgress = j;
case 3 -> DistilleryBlockEntity.this.maxPowerProgress = j;
case 4 -> DistilleryBlockEntity.this.hasAltar = j == 1;
}
}
@Override
public int getCount() {
return 5;
}
};
}
@Override
public Component getDisplayName() {
return new TranslatableComponent("block.tat.distillery");
}
@Override
protected Component getDefaultName() {
return new TranslatableComponent("block.tat.distillery");
}
@Override
protected AbstractContainerMenu createMenu(int i, @NotNull Inventory inventory) {
return new DistilleryMenu(i, inventory, this, this.data);
}
@Override
protected void saveAdditional(CompoundTag compoundTag) {
ContainerHelper.saveAllItems(compoundTag, this.inventory);
compoundTag.putInt("ToilAndTrouble$craftProgress", this.craftProgress);
compoundTag.putInt("ToilAndTrouble$powerProgress", this.powerProgress);
compoundTag.putBoolean("ToilAndTrouble$hasAltar", this.hasAltar);
super.saveAdditional(compoundTag);
}
@Override
public void load(@NotNull CompoundTag compoundTag) {
super.load(compoundTag);
this.inventory = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
ContainerHelper.loadAllItems(compoundTag, this.inventory);
this.craftProgress = compoundTag.getInt("ToilAndTrouble$craftProgress");
this.powerProgress = compoundTag.getInt("ToilAndTrouble$powerProgress");
this.hasAltar = compoundTag.getBoolean("ToilAndTrouble$hasAltar");
}
public void drops() {
assert this.level != null;
Containers.dropContents(this.level, this.worldPosition, this);
}
public SimpleContainer getContainer() {
SimpleContainer container = new SimpleContainer(7);
this.inventory.forEach(stack ->
container.setItem(this.inventory.indexOf(stack), stack)
);
return container;
}
public static void tick(Level pLevel, BlockPos pPos, BlockState pState, DistilleryBlockEntity entity) {
if (pLevel.isClientSide) return;
System.err.println("This is Ticking!");
int ticks = entity.getTicks();
if (ticks % 5 == 0 || AltarSources.testForAltarSource(pLevel, entity.altarPos) == null) {
System.err.println("Uh Oh Spaghetti-o! " + ticks + ", " + entity.altarPos + ", " + entity.hasAltar);
entity.altarPos = findNearestAltar(pLevel, pPos);
entity.hasAltar = AltarSources.testForAltarSource(pLevel, entity.altarPos) != null;
System.err.println("Uh Oh Spaghetti-o 2! " + ticks + ", " + entity.altarPos + ", " + entity.hasAltar);
entity.resetTicks();
entity.setChanged();
}
int jars = getJarCount(entity);
if (pState.getValue(DistilleryBlock.JARS) != jars) {
pState.setValue(DistilleryBlock.JARS, switch (jars) {
case 0, 1, 2, 3, 4 -> jars;
default -> 4;
});
entity.setChanged();
}
if (!hasRecipe(entity) || !entity.hasAltar) {
System.err.println("Has No Recipe or No Altar? " + hasRecipe(entity) + " : " + entity.hasAltar);
if (pState.getValue(DistilleryBlock.POWERED))
pLevel.setBlockAndUpdate(pPos, pState.setValue(DistilleryBlock.POWERED, false));
entity.resetCraftProgress();
entity.resetPowerProgress();
entity.setChanged();
return;
}
IAltarSource altar = AltarSources.testForAltarSource(pLevel, entity.altarPos);
System.err.println("Altar? " + altar);
if (altar == null) return;
System.err.println("Altar Source is not null!");
boolean pullPower = altar.drawPowerFromAltar(pLevel, pPos, entity.altarPos, 2);
System.err.println("Can we pull power? " + pullPower);
if (!pullPower) {
if (pState.getValue(DistilleryBlock.POWERED))
pLevel.setBlockAndUpdate(pPos, pState.setValue(DistilleryBlock.POWERED, false));
return;
}
if (!pState.getValue(DistilleryBlock.POWERED))
pLevel.setBlockAndUpdate(pPos, pState.setValue(DistilleryBlock.POWERED, true));
entity.powerProgress++;
if (entity.powerProgress > entity.maxPowerProgress) {
entity.craftProgress++;
entity.resetPowerProgress();
}
if (entity.craftProgress > entity.maxCraftProgress) {
craftItem(entity);
entity.resetPowerProgress();
}
entity.incrementTicks();
entity.setChanged();
}
public int getTicks() {
return this.ticks;
}
public void incrementTicks() {
this.ticks += 1;
}
public void resetTicks() {
this.ticks = 1;
}
public static BlockPos findNearestAltar(Level level, BlockPos center) {
Stream<BlockPos> allPositions =
BlockPos.betweenClosedStream(
BoundingBox.fromCorners(
center.offset(-15, -15, -15),
center.offset(15, 15, 15)));
BlockPos closest = null;
for (BlockPos pos : allPositions.toList()) {
if (AltarSources.testForAltarSource(level, pos) == null)
continue;
System.err.println("This block is an Altar! " + pos);
if (closest == null || center.distSqr(closest) > center.distSqr(pos))
closest = pos;
}
return closest;
}
private static boolean hasRecipe(DistilleryBlockEntity entity) {
Level level = entity.level;
assert level != null;
Optional<DistilleryRecipe> match = level.getRecipeManager()
.getRecipeFor(DistilleryRecipe.Type.INSTANCE, entity.getContainer(), level);
return match.isPresent() &&
canInsertItemsIntoOutputSlots(entity, match.get().getOutputs()) &&
hasJarInSlot(entity, match.get().getJarCount());
}
private static boolean hasJarInSlot(DistilleryBlockEntity entity, int required) {
return entity.getItem(2).is(TATItems.CLAY_JAR.get()) && entity.getItem(2).getCount() >= required;
}
private static int getJarCount(DistilleryBlockEntity entity) {
return entity.getItem(2).getCount();
}
private static void craftItem(DistilleryBlockEntity entity) {
Level level = entity.level;
assert level != null;
Optional<DistilleryRecipe> match = level.getRecipeManager()
.getRecipeFor(DistilleryRecipe.Type.INSTANCE, entity.getContainer(), level);
if (match.isEmpty()) return;
DistilleryRecipe recipe = match.get();
NonNullList<ItemStack> outputs = recipe.getOutputs();
entity.removeItem(0, 1);
entity.removeItem(1, 1);
entity.removeItem(2, recipe.getJarCount());
addOutput(entity, outputs.get(0), 3);
addOutput(entity, outputs.get(1), 4);
addOutput(entity, outputs.get(2), 5);
addOutput(entity, outputs.get(3), 6);
}
private static void addOutput(DistilleryBlockEntity entity, ItemStack recipeOutput, int slot) {
entity.setItem(slot, new ItemStack(recipeOutput.getItem(), entity.getItem(slot).getCount() + recipeOutput.getCount()));
}
private void resetCraftProgress() {
this.craftProgress = 0;
}
private void resetPowerProgress() {
this.powerProgress = 0;
}
private static boolean canInsertItemIntoOutputSlot(DistilleryBlockEntity inventory, ItemStack output, int slot) {
return inventory.getItem(slot).getItem() == output.getItem() || inventory.getItem(slot).isEmpty();
}
private static boolean canInsertItemsIntoOutputSlots(DistilleryBlockEntity inventory, List<ItemStack> results) {
return canInsertItemIntoOutputSlot(inventory, results.get(0), 3) && canInsertAmountIntoOutputSlot(inventory, 3) &&
canInsertItemIntoOutputSlot(inventory, results.get(1), 4) && canInsertAmountIntoOutputSlot(inventory, 4) &&
canInsertItemIntoOutputSlot(inventory, results.get(2), 5) && canInsertAmountIntoOutputSlot(inventory, 5) &&
canInsertItemIntoOutputSlot(inventory, results.get(3), 6) && canInsertAmountIntoOutputSlot(inventory, 6);
}
private static boolean canInsertAmountIntoOutputSlot(DistilleryBlockEntity inventory, int slot) {
return inventory.getItem(slot).getMaxStackSize() > inventory.getItem(slot).getCount();
}
@Override
public int getContainerSize() {
return 7;
}
@Override
public boolean isEmpty() {
for (ItemStack stack : this.inventory) {
if (!stack.isEmpty())
return false;
}
return true;
}
@Override
public ItemStack getItem(int i) {
return this.inventory.get(i);
}
@Override
public ItemStack removeItem(int i, int j) {
ItemStack itemStack = ContainerHelper.removeItem(this.inventory, i, j);
if (!itemStack.isEmpty())
this.setChanged();
return itemStack;
}
@Override
public ItemStack removeItemNoUpdate(int i) {
ItemStack itemStack = this.inventory.get(i);
if (itemStack.isEmpty())
return ItemStack.EMPTY;
this.inventory.set(i, ItemStack.EMPTY);
return itemStack;
}
@Override
public void setItem(int i, @NotNull ItemStack itemStack) {
this.inventory.set(i, itemStack);
if (!itemStack.isEmpty() && itemStack.getCount() > this.getMaxStackSize())
itemStack.setCount(this.getMaxStackSize());
this.setChanged();
}
@Override
public boolean stillValid(@NotNull Player player) {
return true;
}
@Override
public void clearContent() {
this.inventory.clear();
this.setChanged();
}
@Override
public int[] getSlotsForFace(Direction direction) {
return switch (direction) {
case UP, NORTH, SOUTH, WEST, EAST -> new int[] {0, 1, 2};
case DOWN -> new int[] {3, 4, 5, 6};
};
}
@Override
public boolean canPlaceItemThroughFace(int i, @NotNull ItemStack itemStack, @Nullable Direction direction) {
return switch (i) {
case 0, 1 -> true;
case 2 -> itemStack.is(TATItems.CLAY_JAR.get());
default -> false;
};
}
@Override
public boolean canTakeItemThroughFace(int i, @NotNull ItemStack itemStack, @NotNull Direction direction) {
return switch (i) {
case 0, 1, 2 -> false;
default -> true;
};
}
@Override
public void fillStackedContents(StackedContents stackedContents) {
this.inventory.forEach(stackedContents::accountStack);
}
@Override
public void saveExtraData(FriendlyByteBuf buf) {
buf.writeBlockPos(worldPosition);
}
}
package net.techtastic.tat.api.altar.source;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
public interface IAltarSource {
default double getRange() {
return 0.0;
}
default void setRange(double newRange) {
}
default double getCurrentPower() {
return 0.0;
}
default void setCurrentPower(double newPower) {
}
default double getMaxPower() {
return 0.0;
}
default void setMaxPower(double newMaxPower) {
}
default double getRate() {
return 0.0;
}
default void setRate(double newRate) {
}
boolean drawPowerFromAltar(Level level, BlockPos sink, BlockPos source, double amount);
}
package net.techtastic.tat.api.altar.source;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import java.util.Optional;
public interface IAltarSourceProvider {
default Optional<IAltarSource> getAltarSource(Level level, BlockPos pos) {
return Optional.empty();
}
}
package net.techtastic.tat.sources;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.techtastic.tat.api.altar.source.IAltarSource;
import net.techtastic.tat.api.altar.source.IAltarSourceProvider;
import net.techtastic.tat.block.custom.AltarBlock;
import net.techtastic.tat.block.entity.AltarBlockEntity;
import java.util.Optional;
public class TATAltarSourceProvider implements IAltarSourceProvider {
@Override
public Optional<IAltarSource> getAltarSource(Level level, BlockPos pos) {
BlockEntity be = level.getBlockEntity(pos);
BlockState state = level.getBlockState(pos);
System.err.println("Testing " + pos + "and it has " + state + " and " + be);
if (be instanceof AltarBlockEntity altar && altar.isMaster()) {
System.err.println("This is an Altar and is th Master Altar!");
return Optional.of(new AltarBlockEntitySource(altar));
}
else
return Optional.empty();
}
}
package net.techtastic.tat;
import dev.architectury.registry.ReloadListenerRegistry;
import net.minecraft.server.packs.PackType;
import net.techtastic.tat.api.altar.augment.AltarAugments;
import net.techtastic.tat.api.altar.source.AltarSources;
import net.techtastic.tat.augments.TATAugmentProvider;
import net.techtastic.tat.dataloader.altar.nature.NatureBlocksDataResolver;
import net.techtastic.tat.sources.TATAltarSourceProvider;
public class TATExtras {
public static void registerResourceListeners() {
ReloadListenerRegistry.register(PackType.SERVER_DATA, NatureBlocksDataResolver.loader);
}
public static void registerAltarAugments() {
AltarAugments.registerAltarAugmentProvider(new TATAugmentProvider());
}
public static void registerAltarSources() {
AltarSources.registerAltarSourceProvider(new TATAltarSourceProvider());
}
public static void register() {
registerResourceListeners();
registerAltarAugments();
registerAltarSources();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment