Skip to content

Commit

Permalink
Add redstone support, config for power usage for harvester
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremiahwinsley committed Oct 19, 2024
1 parent 4345d6b commit f61c74b
Show file tree
Hide file tree
Showing 22 changed files with 376 additions and 20 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@
# are changed when only line endings change.
src/generated/**/.cache/cache text eol=lf
src/generated/**/*.json text eol=lf

src/generated/** linguist-generated=true
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ dependencies {
implementation "net.neoforged:neoforge:${neo_version}"

runtimeOnly "curse.maven:emi-580555:5704405"
// runtimeOnly fg.deobf("curse.maven:jei-238222:4712868")
implementation "curse.maven:jei-238222:5802637"
runtimeOnly "curse.maven:jade-324717:5493270"
compileOnly "curse.maven:ftb-teams-forge-404468:5448371"
runtimeOnly "curse.maven:powah-rearchitected-633483:5735677"
runtimeOnly "curse.maven:cloth-config-348521:5729127"

runtimeOnly "curse.maven:mystical-agriculture-246640:5654250"
runtimeOnly "curse.maven:mystical-agradditions-256247:5648567"
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ mod_name=Pylons
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=All Rights Reserved
# The mod version. See https://semver.org/
mod_version=5.0.2
mod_version=5.1.0
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
Expand Down
7 changes: 7 additions & 0 deletions src/generated/resources/assets/pylons/lang/en_us.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions src/main/java/net/permutated/pylons/ConfigManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ public static class ServerConfig {
public final ModConfigSpec.IntValue harvesterWorkDelay;
public final ModConfigSpec.BooleanValue harvesterRequiresTool;
public final ModConfigSpec.BooleanValue harvesterCanBeAutomated;
public final ModConfigSpec.BooleanValue harvesterRequiresPower;
public final ModConfigSpec.IntValue harvesterPowerCost;
public final ModConfigSpec.IntValue harvesterPowerBuffer;


ServerConfig(ModConfigSpec.Builder builder) {
Expand Down Expand Up @@ -137,6 +140,19 @@ public static class ServerConfig {
"By default, unbreakable tools are required for full automation.")
.define("harvesterCanBeAutomated", false);

harvesterRequiresPower = builder
.comment("Whether the harvester requires power to work.",
"If enabled, it will disable the tool requirement and instead have an RF cost per block.")
.define("harvesterRequiresPower", false);

harvesterPowerCost = builder
.comment("The RF cost per block harvested, if power usage is enabled.")
.defineInRange("harvesterPowerCost", 5, 1, 10_000);

harvesterPowerBuffer = builder
.comment("Buffer size should be greater than power cost per block * 80.")
.defineInRange("harvesterPowerBuffer", 1_000, 100, 1_000_000);

builder.pop();
}
}
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/net/permutated/pylons/compat/jei/JEIPlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.permutated.pylons.compat.jei;

import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.registration.IRecipeRegistration;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.permutated.pylons.ModRegistry;
import net.permutated.pylons.util.Constants;
import net.permutated.pylons.util.ResourceUtil;

import static net.permutated.pylons.util.TranslationKey.translateJei;

@JeiPlugin
public class JEIPlugin implements IModPlugin {

@Override
public ResourceLocation getPluginUid() {
return ResourceUtil.prefix("jei_plugin");
}

@Override
public void registerRecipes(IRecipeRegistration registration) {
registration.addIngredientInfo(new ItemStack(ModRegistry.EXPULSION_PYLON.get()), VanillaTypes.ITEM_STACK, translateJei(Constants.EXPULSION_PYLON));
registration.addIngredientInfo(new ItemStack(ModRegistry.HARVESTER_PYLON.get()), VanillaTypes.ITEM_STACK, translateJei(Constants.HARVESTER_PYLON));
registration.addIngredientInfo(new ItemStack(ModRegistry.INFUSION_PYLON.get()), VanillaTypes.ITEM_STACK, translateJei(Constants.INFUSION_PYLON));
registration.addIngredientInfo(new ItemStack(ModRegistry.INTERDICTION_PYLON.get()), VanillaTypes.ITEM_STACK, translateJei(Constants.INTERDICTION_PYLON));
}
}
48 changes: 48 additions & 0 deletions src/main/java/net/permutated/pylons/data/client/Languages.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import net.neoforged.neoforge.common.data.LanguageProvider;
import net.permutated.pylons.ModRegistry;
import net.permutated.pylons.Pylons;
import net.permutated.pylons.util.Constants;

import static net.permutated.pylons.util.TranslationKey.chat;
import static net.permutated.pylons.util.TranslationKey.gui;
import static net.permutated.pylons.util.TranslationKey.jei;
import static net.permutated.pylons.util.TranslationKey.tab;
import static net.permutated.pylons.util.TranslationKey.tooltip;

Expand Down Expand Up @@ -41,6 +43,7 @@ protected void addTranslations() {
add(gui("insideWorldSpawn"), "Too close to world spawn.");
add(gui("toolMissing"), "Hoe required for operation.");
add(gui("inventoryMissing"), "Place inventory above pylon.");
add(gui("energyMissing"), "Not enough power.");
add(gui("inventoryFull"), "Inventory is full.");
add(gui("working"), "Pylon is working.");
add(gui("whitelist"), "Add players to whitelist:");
Expand All @@ -49,6 +52,8 @@ protected void addTranslations() {
add(gui("workArea"), "Work area (in chunks)");
add(gui("workAreaBlocks"), "Work area (in blocks)");
add(gui("toggleWork"), "Working status");
add(gui("fluxBar"), "Redstone Flux:");
add(gui("fluxData"), "%d/%d RF stored");
add(tab(), "Pylons");

add(chat("expelled"), "You have been expelled from %s's chunk!");
Expand Down Expand Up @@ -95,6 +100,49 @@ protected void addTranslations() {
add(tooltip("expulsion"), "Used in the Expulsion Pylon.");
add(tooltip("infusion"), "Used in the Infusion Pylon.");
add(tooltip("interdiction"), "Used in the Interdiction Pylon.");

add(jei(Constants.HARVESTER_PYLON), """
Harvests crops in a radius (from 3x3 to 9x9 blocks) around the pylon and outputs to an inventory above.
Place the pylon inside the water block of the farm, or level with the crops.
By default (configurable) this will require a hoe in the pylon, and use 1 durability per harvest,
unless the hoe is unbreakable. Unbreaking and other durability enchants are supported.
Optionally can be configured to require power instead of durability.
Can be toggled automatically with redstone.
""");

add(jei(Constants.INFUSION_PYLON), """
Allows you to apply effects to yourself from any distance with activated Potion Filters.
By default (configurable) this will load the chunk it's placed in, while the owner is online.
Activate potion filters by applying a potion effect to yourself,
and then right clicking with the filter in hand to extract it.
By default (configurable) the minimum duration that can be extracted is 60 seconds,
and the filter requires 1 hour of duration to activate.
Duplicate potion filters can be combined by placing one in each hand and right-clicking.
Can be toggled automatically with redstone.
""");

add(jei(Constants.EXPULSION_PYLON), """
This block allows you to expel other players from the selected chunk range (1x1 to 5x5 chunks).
You can whitelist players with a Player Filter.
Can be toggled automatically with redstone.
""");

add(jei(Constants.INTERDICTION_PYLON), """
Prevents natural and forced spawns of specified mobs within the selected chunk range (1x1 to 5x5 chunks).
Add Mob Filters to specify which mobs to block.
Using the lifeless filter will instead block all mobs, but only natural spawns, with a much larger range.
Can be toggled automatically with redstone.
""");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
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.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.material.MapColor;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
Expand All @@ -37,13 +40,21 @@
import javax.annotation.Nullable;

public abstract class AbstractPylonBlock extends Block implements EntityBlock {
public static final BooleanProperty ENABLED = BlockStateProperties.ENABLED;
private static final VoxelShape SHAPE = Shapes.or(
Block.box(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D),
Block.box(1.0D, 3.0D, 1.0D, 15.0D, 16.0D, 15.0D)
);

protected AbstractPylonBlock() {
super(Properties.of().mapColor(MapColor.METAL).strength(INDESTRUCTIBLE, 1200F));
this.registerDefaultState(this.defaultBlockState()
.setValue(ENABLED, Boolean.TRUE));
}

@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(ENABLED);
}

@Override
Expand Down Expand Up @@ -120,6 +131,29 @@ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState new
}
}

@Override
@SuppressWarnings("java:S1874") // deprecated method from super class
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
if (!newState.is(state.getBlock())) {
this.checkPoweredState(level, pos, state);
}
}

@Override
@SuppressWarnings("java:S1874") // deprecated method from super class
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos neighborPos, boolean isMoving) {
this.checkPoweredState(level, pos, state);
}

//TODO avoid chunk loading?
private void checkPoweredState(Level level, BlockPos pos, BlockState state) {
boolean flag = !level.hasNeighborSignal(pos);
if (!Boolean.valueOf(flag).equals((state.getValue(ENABLED)))) {
level.setBlock(pos, state.setValue(ENABLED, flag), Block.UPDATE_ALL);
}

}

@Override
protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult blockRayTraceResult) {
if (!world.isClientSide) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,15 @@ public abstract class AbstractPylonContainer extends AbstractContainerMenu {
protected final DataHolder dataHolder;
protected final String ownerName;
protected final BlockPos blockPos;
protected final boolean usesEnergy;

protected AbstractPylonContainer(@Nullable MenuType<?> containerType, int windowId, Inventory playerInventory, FriendlyByteBuf packetBuffer) {
this(containerType, windowId, playerInventory, packetBuffer, false);
}

protected AbstractPylonContainer(@Nullable MenuType<?> containerType, int windowId, Inventory playerInventory, FriendlyByteBuf packetBuffer, boolean usesEnergy) {
super(containerType, windowId);
this.usesEnergy = usesEnergy;

blockPos = packetBuffer.readBlockPos();
Level level = playerInventory.player.getCommandSenderWorld();
Expand Down Expand Up @@ -134,6 +140,7 @@ public ItemStack quickMoveStack(Player playerIn, int index) {
}

public void registerHandlerSlots(IItemHandler inventory) {
if (usesEnergy) return;
for (int slot = 0; slot < AbstractPylonTile.SLOTS; slot++) {
addSlot(new SlotItemHandler(inventory, slot, 8 + slot * 18, 54));
}
Expand All @@ -154,6 +161,28 @@ public void registerPlayerSlots(IItemHandler wrappedInventory) {
public void registerDataSlots() {
addDataSlot(dataHolder::getRange, dataHolder::setRange);
addDataSlot(dataHolder::getEnabled, dataHolder::setEnabled);

// split max energy
addDataSlot(() -> dataHolder.getMaxEnergy() & 0xffff, value -> {
int energyStored = dataHolder.getMaxEnergy() & 0xffff0000;
dataHolder.setMaxEnergy(energyStored + (value & 0xffff));
});

addDataSlot(() -> (dataHolder.getMaxEnergy() >> 16) & 0xffff, value -> {
int energyStored = dataHolder.getMaxEnergy() & 0x0000ffff;
dataHolder.setMaxEnergy(energyStored | (value << 16));
});

// split current energy
addDataSlot(() -> dataHolder.getEnergy() & 0xffff, value -> {
int energyStored = dataHolder.getEnergy() & 0xffff0000;
dataHolder.setEnergy(energyStored + (value & 0xffff));
});

addDataSlot(() -> (dataHolder.getEnergy() >> 16) & 0xffff, value -> {
int energyStored = dataHolder.getEnergy() & 0x0000ffff;
dataHolder.setEnergy(energyStored | (value << 16));
});
}

private void addDataSlot(IntSupplier getter, IntConsumer setter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,28 @@
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.permutated.pylons.ConfigManager;
import net.permutated.pylons.util.Constants;
import net.permutated.pylons.util.ResourceUtil;
import net.permutated.pylons.util.TextureHolder;
import net.permutated.pylons.util.TranslationKey;

import java.util.List;

public abstract class AbstractPylonScreen<T extends AbstractPylonContainer> extends AbstractContainerScreen<T> {
protected final ResourceLocation gui;
protected final boolean usesEnergy;
protected Button workButton;
protected Button rangeButton;

protected AbstractPylonScreen(T container, Inventory inv, Component name) {
protected AbstractPylonScreen(T container, Inventory inventory, Component title) {
this(container, inventory, title, false);
}

protected AbstractPylonScreen(T container, Inventory inv, Component name, boolean usesEnergy) {
super(container, inv, name);
this.gui = ResourceUtil.gui("pylon");
this.usesEnergy = ConfigManager.SERVER.harvesterRequiresPower.getAsBoolean();
this.gui = usesEnergy ? ResourceUtil.gui("pylon_energy") : ResourceUtil.gui("pylon");
this.imageWidth = 176;
this.imageHeight = 172;
this.inventoryLabelY = this.imageHeight - 94;
Expand Down Expand Up @@ -81,6 +91,19 @@ protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, in
int relX = (this.width - this.imageWidth) / 2;
int relY = (this.height - this.imageHeight) / 2;
graphics.blit(gui, relX, relY, 0, 0, this.imageWidth, this.imageHeight);

if (usesEnergy) {
float energyFraction = this.menu.dataHolder.getEnergyFraction();
var energyHolder = new TextureHolder(8, 54, 0, 172, 160, 16);
graphics.blit(gui,
relX + energyHolder.progressOffsetX(),
relY + energyHolder.progressOffsetY(),
energyHolder.textureOffsetX(),
energyHolder.textureOffsetY(),
energyHolder.getWidthFraction(energyFraction),
energyHolder.textureHeight()
);
}
}

@Override
Expand All @@ -97,6 +120,17 @@ protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
drawText(graphics, component, 30);
}

@Override
protected void renderTooltip(GuiGraphics guiGraphics, int x, int y) {
super.renderTooltip(guiGraphics, x, y);
if (usesEnergy && this.isHovering(8, 54, 160, 16, x, y)) {
guiGraphics.renderComponentTooltip(this.font, List.of(
translate("fluxBar"),
translate("fluxData", this.menu.dataHolder.getEnergy(), this.menu.dataHolder.getMaxEnergy())
), x, y);
}
}

protected void drawText(GuiGraphics graphics, Component component, int yPos) {
graphics.drawString(this.font, component, 8, yPos, 4210752, false);
}
Expand Down
Loading

0 comments on commit f61c74b

Please sign in to comment.