Update to 1.20.x

This commit is contained in:
Zontreck 2024-02-28 15:59:48 -07:00
parent 27a3496310
commit 10af6a66f9
43 changed files with 10836 additions and 10572 deletions

View file

@ -11,29 +11,45 @@ package dev.zontreck.engineerdecor;
import dev.zontreck.engineerdecor.blocks.*;
import dev.zontreck.engineerdecor.detail.TreeCutting;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.OptionalRecipeCondition;
import dev.zontreck.engineerdecor.libmc.SlabSliceBlock;
import dev.zontreck.engineerdecor.libmc.VariantSlabBlock;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.OptionalRecipeCondition;
import dev.zontreck.libzontreck.edlibmc.SlabSliceBlock;
import dev.zontreck.libzontreck.edlibmc.VariantSlabBlock;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.ForgeConfigSpec;
import org.apache.commons.lang3.tuple.Pair;
import wile.engineersdecor.blocks.*;
import javax.annotation.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class ModConfig
{
//--------------------------------------------------------------------------------------------------------------------
private static final String MODID = ModEngineersDecor.MODID;
public class ModConfig {
public static final CommonConfig COMMON;
public static final ServerConfig SERVER;
public static final ForgeConfigSpec COMMON_CONFIG_SPEC;
public static final ForgeConfigSpec SERVER_CONFIG_SPEC;
//--------------------------------------------------------------------------------------------------------------------
private static final String MODID = ModEngineersDecor.MODID;
private static final CompoundTag server_config_ = new CompoundTag();
//--------------------------------------------------------------------------------------------------------------------
public static boolean immersiveengineering_installed = false;
//--------------------------------------------------------------------------------------------------------------------
public static boolean without_direct_slab_pickup = false;
//--------------------------------------------------------------------------------------------------------------------
// Optout checks
//--------------------------------------------------------------------------------------------------------------------
public static boolean with_creative_mode_device_drops = false;
private static HashSet<String> optouts_ = new HashSet<>();
private static boolean with_experimental_features_ = false;
private static boolean with_config_logging_ = false;
private static boolean with_debug_logs_ = false;
static {
final Pair<CommonConfig, ForgeConfigSpec> common_ = (new ForgeConfigSpec.Builder()).configure(CommonConfig::new);
@ -44,10 +60,161 @@ public class ModConfig
SERVER = server_.getLeft();
}
//--------------------------------------------------------------------------------------------------------------------
// Cache
//--------------------------------------------------------------------------------------------------------------------
public static class CommonConfig
public static boolean isOptedOut(final @Nullable Block block) {
return (block == null) || isOptedOut(block.asItem());
}
public static boolean isOptedOut(final @Nullable Item item) {
return (item != null) && optouts_.contains(Auxiliaries.getResourceLocation(item).getPath());
}
public static boolean withExperimental() {
return with_experimental_features_;
}
public static boolean withoutRecipes() {
return false;
}
public static boolean withDebug() {
return with_debug_logs_;
}
public static boolean withDebugLogging() {
return with_experimental_features_ && with_config_logging_;
}
public static CompoundTag getServerConfig() // config that may be synchronized from server to client via net pkg.
{
return server_config_;
}
private static void updateOptouts() {
final ArrayList<String> includes = new ArrayList<>();
final ArrayList<String> excludes = new ArrayList<>();
{
String inc = COMMON.pattern_includes.get().toLowerCase().replaceAll(MODID + ":", "").replaceAll("[^*_,a-z\\d]", "");
if (!COMMON.pattern_includes.get().equals(inc)) COMMON.pattern_includes.set(inc);
String[] incl = inc.split(",");
for (int i = 0; i < incl.length; ++i) {
incl[i] = incl[i].replaceAll("[*]", ".*?");
if (!incl[i].isEmpty()) includes.add(incl[i]);
}
}
{
String exc = COMMON.pattern_excludes.get().toLowerCase().replaceAll(MODID + ":", "").replaceAll("[^*_,a-z\\d]", "");
String[] excl = exc.split(",");
for (int i = 0; i < excl.length; ++i) {
excl[i] = excl[i].replaceAll("[*]", ".*?");
if (!excl[i].isEmpty()) excludes.add(excl[i]);
}
}
if (!excludes.isEmpty()) log("Config pattern excludes: '" + String.join(",", excludes) + "'");
if (!includes.isEmpty()) log("Config pattern includes: '" + String.join(",", includes) + "'");
try {
HashSet<String> optouts = new HashSet<>();
ModContent.getRegisteredBlocks().stream().filter((Block block) -> {
if (block == null) return true;
if (block == ModContent.getBlock("sign_decor")) return true;
try {
if (!with_experimental_features_) {
if (block instanceof Auxiliaries.IExperimentalFeature) return true;
}
// Force-include/exclude pattern matching
final String rn = Auxiliaries.getResourceLocation(block).getPath();
try {
for (String e : includes) {
if (rn.matches(e)) {
log("Optout force include: " + rn);
return false;
}
}
for (String e : excludes) {
if (rn.matches(e)) {
log("Optout force exclude: " + rn);
return true;
}
}
} catch (Throwable ex) {
Auxiliaries.logger().error("optout include pattern failed, disabling.");
includes.clear();
excludes.clear();
}
} catch (Exception ex) {
Auxiliaries.logger().error("Exception evaluating the optout config: '" + ex.getMessage() + "'");
}
return false;
}).forEach(
e -> optouts.add(Auxiliaries.getResourceLocation(e).getPath())
);
optouts_ = optouts;
OptionalRecipeCondition.on_config(withExperimental(), withoutRecipes(), ModConfig::isOptedOut, ModConfig::isOptedOut);
} catch (Throwable ex) {
Auxiliaries.logger().error("Exception evaluating the optout config: '" + ex.getMessage() + "'"); // Compat issue: config-apply may be called before the registries are all loaded.
}
}
public static void apply() {
with_config_logging_ = COMMON.with_config_logging.get();
with_experimental_features_ = COMMON.with_experimental.get();
with_debug_logs_ = COMMON.with_debug_logging.get();
if (with_experimental_features_) Auxiliaries.logger().info("Config: EXPERIMENTAL FEATURES ENABLED.");
if (with_debug_logs_)
Auxiliaries.logger().info("Config: DEBUG LOGGING ENABLED, WARNING, THIS MAY SPAM THE LOG.");
immersiveengineering_installed = Auxiliaries.isModLoaded("immersiveengineering");
updateOptouts();
if (!SERVER_CONFIG_SPEC.isLoaded()) return;
without_direct_slab_pickup = SERVER.without_direct_slab_pickup.get();
// -----------------------------------------------------------------------------------------------------------------
EdChair.on_config(SERVER.without_chair_sitting.get(), SERVER.without_mob_chair_sitting.get(), SERVER.chair_mob_sitting_probability_percent.get(), SERVER.chair_mob_standup_probability_percent.get());
EdLadderBlock.on_config(SERVER.without_ladder_speed_boost.get());
VariantSlabBlock.on_config(!SERVER.without_direct_slab_pickup.get());
SlabSliceBlock.on_config(!SERVER.without_direct_slab_pickup.get());
EdFluidBarrel.on_config(12000, 1000);
EdFluidFunnel.on_config(with_experimental_features_);
EdPipeValve.on_config(SERVER.pipevalve_max_flowrate.get(), SERVER.pipevalve_redstone_gain.get());
EdHopper.on_config();
EdDropper.on_config(true);
EdPlacer.on_config();
EdBreaker.on_config(SERVER.block_breaker_power_consumption.get(), SERVER.block_breaker_reluctance.get(), SERVER.block_breaker_min_breaking_time.get(), SERVER.block_breaker_requires_power.get());
EdTreeCutter.on_config(SERVER.tree_cutter_energy_consumption.get(), SERVER.tree_cutter_cutting_time_needed.get(), SERVER.tree_cutter_requires_power.get());
EdFurnace.on_config(SERVER.furnace_smelting_speed_percent.get(), SERVER.furnace_fuel_efficiency_percent.get(), SERVER.furnace_boost_energy_consumption.get(), SERVER.furnace_accepted_heaters.get());
EdElectricalFurnace.on_config(SERVER.e_furnace_speed_percent.get(), SERVER.e_furnace_power_consumption.get(), SERVER.e_furnace_automatic_pulling.get());
EdSolarPanel.on_config(SERVER.small_solar_panel_peak_production.get(), 64000, 1024);
EdMilker.on_config(SERVER.milking_machine_energy_consumption.get(), SERVER.milking_machine_milking_delay.get());
EdFreezer.on_config(144, 2);
EdMineralSmelter.on_config(144, 2);
EdWasteIncinerator.on_config(8);
// -----------------------------------------------------------------------------------------------------------------
{
final List<String> universal_logs = new ArrayList<>(SERVER.tree_cutter_universal_logs.get());
// Fixed known blocks. @todo, also check AE/menril, etc.
universal_logs.add("myrtrees:filled_rubberwood_log");
TreeCutting.on_config(universal_logs);
}
// -----------------------------------------------------------------------------------------------------------------
{
// Check if the config is already synchronized or has to be synchronised.
server_config_.putBoolean("tree_cutter_requires_power", SERVER.tree_cutter_requires_power.get());
server_config_.putBoolean("block_breaker_requires_power", SERVER.block_breaker_requires_power.get());
{
String s = String.join(",", optouts_);
server_config_.putString("optout", s);
if (!s.isEmpty()) log("Opt-outs:" + s);
}
}
}
public static void log(String config_message) {
if (!with_config_logging_) return;
Auxiliaries.logger().info(config_message);
}
public static class CommonConfig {
// Optout
public final ForgeConfigSpec.ConfigValue<String> pattern_excludes;
public final ForgeConfigSpec.ConfigValue<String> pattern_includes;
@ -57,8 +224,7 @@ public class ModConfig
public final ForgeConfigSpec.BooleanValue with_config_logging;
public final ForgeConfigSpec.BooleanValue with_debug_logging;
CommonConfig(ForgeConfigSpec.Builder builder)
{
CommonConfig(ForgeConfigSpec.Builder builder) {
builder.comment("Settings affecting the logical server side.")
.push("server");
// --- OPTOUTS ------------------------------------------------------------
@ -109,10 +275,7 @@ public class ModConfig
}
}
//--------------------------------------------------------------------------------------------------------------------
public static class ServerConfig
{
public static class ServerConfig {
// Optout
public final ForgeConfigSpec.BooleanValue without_chair_sitting;
public final ForgeConfigSpec.BooleanValue without_mob_chair_sitting;
@ -145,8 +308,7 @@ public class ModConfig
public final ForgeConfigSpec.IntValue milking_machine_energy_consumption;
public final ForgeConfigSpec.IntValue milking_machine_milking_delay;
ServerConfig(ForgeConfigSpec.Builder builder)
{
ServerConfig(ForgeConfigSpec.Builder builder) {
builder.comment("Settings affecting the logical server side.")
.push("server");
// --- OPTOUTS ------------------------------------------------------------
@ -315,172 +477,11 @@ public class ModConfig
.defineInRange("milking_machine_energy_consumption", EdMilker.DEFAULT_ENERGY_CONSUMPTION, 0, 1024);
milking_machine_milking_delay = builder
.translation(MODID + ".config.milking_machine_milking_delay")
.comment("Defines (for each individual cow) the minimum time between milking." )
.comment("Defines (for each individual cow) the minimum time between milking.")
.defineInRange("milking_machine_milking_delay", EdMilker.DEFAULT_MILKING_DELAY_PER_COW, 1000, 24000);
builder.pop();
}
}
}
//--------------------------------------------------------------------------------------------------------------------
// Optout checks
//--------------------------------------------------------------------------------------------------------------------
public static boolean isOptedOut(final @Nullable Block block)
{ return (block==null) || isOptedOut(block.asItem()); }
public static boolean isOptedOut(final @Nullable Item item)
{ return (item!=null) && optouts_.contains(Auxiliaries.getResourceLocation(item).getPath()); }
public static boolean withExperimental()
{ return with_experimental_features_; }
public static boolean withoutRecipes()
{ return false; }
public static boolean withDebug()
{ return with_debug_logs_; }
public static boolean withDebugLogging()
{ return with_experimental_features_ && with_config_logging_; }
//--------------------------------------------------------------------------------------------------------------------
// Cache
//--------------------------------------------------------------------------------------------------------------------
private static final CompoundTag server_config_ = new CompoundTag();
private static HashSet<String> optouts_ = new HashSet<>();
private static boolean with_experimental_features_ = false;
private static boolean with_config_logging_ = false;
private static boolean with_debug_logs_ = false;
public static boolean immersiveengineering_installed = false;
public static boolean without_direct_slab_pickup = false;
public static boolean with_creative_mode_device_drops = false;
public static CompoundTag getServerConfig() // config that may be synchronized from server to client via net pkg.
{ return server_config_; }
private static void updateOptouts()
{
final ArrayList<String> includes = new ArrayList<>();
final ArrayList<String> excludes = new ArrayList<>();
{
String inc = COMMON.pattern_includes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z\\d]", "");
if(!COMMON.pattern_includes.get().equals(inc)) COMMON.pattern_includes.set(inc);
String[] incl = inc.split(",");
for(int i=0; i< incl.length; ++i) {
incl[i] = incl[i].replaceAll("[*]", ".*?");
if(!incl[i].isEmpty()) includes.add(incl[i]);
}
}
{
String exc = COMMON.pattern_excludes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z\\d]", "");
String[] excl = exc.split(",");
for(int i=0; i< excl.length; ++i) {
excl[i] = excl[i].replaceAll("[*]", ".*?");
if(!excl[i].isEmpty()) excludes.add(excl[i]);
}
}
if(!excludes.isEmpty()) log("Config pattern excludes: '" + String.join(",", excludes) + "'");
if(!includes.isEmpty()) log("Config pattern includes: '" + String.join(",", includes) + "'");
try {
HashSet<String> optouts = new HashSet<>();
ModContent.getRegisteredBlocks().stream().filter((Block block) -> {
if(block==null) return true;
if(block==ModContent.getBlock("sign_decor")) return true;
try {
if(!with_experimental_features_) {
if(block instanceof Auxiliaries.IExperimentalFeature) return true;
}
// Force-include/exclude pattern matching
final String rn = Auxiliaries.getResourceLocation(block).getPath();
try {
for(String e : includes) {
if(rn.matches(e)) {
log("Optout force include: "+rn);
return false;
}
}
for(String e : excludes) {
if(rn.matches(e)) {
log("Optout force exclude: "+rn);
return true;
}
}
} catch(Throwable ex) {
Auxiliaries.logger().error("optout include pattern failed, disabling.");
includes.clear();
excludes.clear();
}
} catch(Exception ex) {
Auxiliaries.logger().error("Exception evaluating the optout config: '"+ex.getMessage()+"'");
}
return false;
}).forEach(
e -> optouts.add(Auxiliaries.getResourceLocation(e).getPath())
);
optouts_ = optouts;
OptionalRecipeCondition.on_config(withExperimental(), withoutRecipes(), ModConfig::isOptedOut, ModConfig::isOptedOut);
} catch(Throwable ex) {
Auxiliaries.logger().error("Exception evaluating the optout config: '"+ex.getMessage()+"'"); // Compat issue: config-apply may be called before the registries are all loaded.
}
}
public static void apply()
{
with_config_logging_ = COMMON.with_config_logging.get();
with_experimental_features_ = COMMON.with_experimental.get();
with_debug_logs_ = COMMON.with_debug_logging.get();
if(with_experimental_features_) Auxiliaries.logger().info("Config: EXPERIMENTAL FEATURES ENABLED.");
if(with_debug_logs_) Auxiliaries.logger().info("Config: DEBUG LOGGING ENABLED, WARNING, THIS MAY SPAM THE LOG.");
immersiveengineering_installed = Auxiliaries.isModLoaded("immersiveengineering");
updateOptouts();
if(!SERVER_CONFIG_SPEC.isLoaded()) return;
without_direct_slab_pickup = SERVER.without_direct_slab_pickup.get();
// -----------------------------------------------------------------------------------------------------------------
EdChair.on_config(SERVER.without_chair_sitting.get(), SERVER.without_mob_chair_sitting.get(), SERVER.chair_mob_sitting_probability_percent.get(), SERVER.chair_mob_standup_probability_percent.get());
EdLadderBlock.on_config(SERVER.without_ladder_speed_boost.get());
VariantSlabBlock.on_config(!SERVER.without_direct_slab_pickup.get());
SlabSliceBlock.on_config(!SERVER.without_direct_slab_pickup.get());
EdFluidBarrel.on_config(12000, 1000);
EdFluidFunnel.on_config(with_experimental_features_);
EdPipeValve.on_config(SERVER.pipevalve_max_flowrate.get(), SERVER.pipevalve_redstone_gain.get());
EdHopper.on_config();
EdDropper.on_config(true);
EdPlacer.on_config();
EdBreaker.on_config(SERVER.block_breaker_power_consumption.get(), SERVER.block_breaker_reluctance.get(), SERVER.block_breaker_min_breaking_time.get(), SERVER.block_breaker_requires_power.get());
EdTreeCutter.on_config(SERVER.tree_cutter_energy_consumption.get(), SERVER.tree_cutter_cutting_time_needed.get(), SERVER.tree_cutter_requires_power.get());
EdFurnace.on_config(SERVER.furnace_smelting_speed_percent.get(), SERVER.furnace_fuel_efficiency_percent.get(), SERVER.furnace_boost_energy_consumption.get(), SERVER.furnace_accepted_heaters.get());
EdElectricalFurnace.on_config(SERVER.e_furnace_speed_percent.get(), SERVER.e_furnace_power_consumption.get(), SERVER.e_furnace_automatic_pulling.get());
EdSolarPanel.on_config(SERVER.small_solar_panel_peak_production.get(), 64000, 1024);
EdMilker.on_config(SERVER.milking_machine_energy_consumption.get(), SERVER.milking_machine_milking_delay.get());
EdFreezer.on_config(144, 2);
EdMineralSmelter.on_config(144, 2);
EdWasteIncinerator.on_config(8);
// -----------------------------------------------------------------------------------------------------------------
{
final List<String> universal_logs = new ArrayList<>(SERVER.tree_cutter_universal_logs.get());
// Fixed known blocks. @todo, also check AE/menril, etc.
universal_logs.add("myrtrees:filled_rubberwood_log");
TreeCutting.on_config(universal_logs);
}
// -----------------------------------------------------------------------------------------------------------------
{
// Check if the config is already synchronized or has to be synchronised.
server_config_.putBoolean("tree_cutter_requires_power", SERVER.tree_cutter_requires_power.get());
server_config_.putBoolean("block_breaker_requires_power", SERVER.block_breaker_requires_power.get());
{
String s = String.join(",", optouts_);
server_config_.putString("optout", s);
if(!s.isEmpty()) log("Opt-outs:" + s);
}
}
}
public static void log(String config_message)
{
if(!with_config_logging_) return;
Auxiliaries.logger().info(config_message);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
package dev.zontreck.engineerdecor;
import dev.zontreck.engineerdecor.blocks.EdLadderBlock;
import dev.zontreck.engineerdecor.libmc.*;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -16,25 +16,19 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.OptionalRecipeCondition;
import dev.zontreck.engineerdecor.libmc.Overlay;
import dev.zontreck.engineerdecor.libmc.Registries;
@Mod("engineersdecor")
public class ModEngineersDecor
{
public class ModEngineersDecor {
public static final String MODID = "engineersdecor";
public static final String MODNAME = "Engineer's Decor";
public static final int VERSION_DATAFIXER = 0;
private static final Logger LOGGER = com.mojang.logging.LogUtils.getLogger();
public ModEngineersDecor()
{
public ModEngineersDecor() {
Auxiliaries.init(MODID, LOGGER, ModConfig::getServerConfig);
Auxiliaries.logGitVersion(MODNAME);
Registries.init(MODID, "sign_decor", (reg)->reg.register(FMLJavaModLoadingContext.get().getModEventBus()));
Registries.init(MODID, "sign_decor", FMLJavaModLoadingContext.get().getModEventBus());
ModContent.init(MODID);
OptionalRecipeCondition.init(MODID, LOGGER);
ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.SERVER, ModConfig.SERVER_CONFIG_SPEC);
@ -44,14 +38,12 @@ public class ModEngineersDecor
MinecraftForge.EVENT_BUS.register(this);
}
private void onSetup(final FMLCommonSetupEvent event)
{
private void onSetup(final FMLCommonSetupEvent event) {
CraftingHelper.register(OptionalRecipeCondition.Serializer.INSTANCE);
Networking.init(MODID);
}
private void onClientSetup(final FMLClientSetupEvent event)
{
private void onClientSetup(final FMLClientSetupEvent event) {
Overlay.TextOverlayGui.on_config(0.75, 0x00ffaa00, 0x55333333, 0x55333333, 0x55444444);
Networking.OverlayTextMessage.setHandler(Overlay.TextOverlayGui::show);
ModContent.registerMenuGuis(event);
@ -59,45 +51,42 @@ public class ModEngineersDecor
ModContent.processContentClientSide(event);
}
@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
public static class ForgeEvents
{
@SubscribeEvent
public static void onConfigLoad(final ModConfigEvent.Loading event)
{ ModConfig.apply(); }
public void onPlayerEvent(final LivingEvent.LivingTickEvent event) {
if (!(event.getEntity() instanceof final Player player)) return;
if (player.onClimbable()) EdLadderBlock.onPlayerUpdateEvent(player);
}
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public static class ForgeEvents {
@SubscribeEvent
public static void onConfigLoad(final ModConfigEvent.Loading event) {
ModConfig.apply();
}
@SubscribeEvent
public static void onConfigReload(final ModConfigEvent.Reloading event)
{
public static void onConfigReload(final ModConfigEvent.Reloading event) {
try {
Auxiliaries.logger().info("Config file changed {}", event.getConfig().getFileName());
ModConfig.apply();
} catch(Throwable e) {
} catch (Throwable e) {
Auxiliaries.logger().error("Failed to load changed config: " + e.getMessage());
}
}
}
@SubscribeEvent
public void onPlayerEvent(final LivingEvent.LivingTickEvent event)
{
if(!(event.getEntity() instanceof final Player player)) return;
if(player.onClimbable()) EdLadderBlock.onPlayerUpdateEvent(player);
}
@OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(Dist.CLIENT)
public static class ForgeClientEvents
{
public static class ForgeClientEvents {
@SubscribeEvent
public static void onRenderGui(net.minecraftforge.client.event.RenderGuiOverlayEvent.Post event)
{ Overlay.TextOverlayGui.INSTANCE.onRenderGui(event.getPoseStack()); }
public static void onRenderGui(net.minecraftforge.client.event.RenderGuiOverlayEvent.Post event) {
Overlay.TextOverlayGui.INSTANCE.onRenderGui(event.getGuiGraphics());
}
@SubscribeEvent
@OnlyIn(Dist.CLIENT)
public static void onRenderWorldOverlay(net.minecraftforge.client.event.RenderLevelStageEvent event)
{
if(event.getStage() == net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_WEATHER) {
public static void onRenderWorldOverlay(net.minecraftforge.client.event.RenderLevelStageEvent event) {
if (event.getStage() == net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_WEATHER) {
Overlay.TextOverlayGui.INSTANCE.onRenderWorldOverlay(event.getPoseStack(), event.getPartialTick());
}
}

View file

@ -8,6 +8,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
@ -28,6 +31,7 @@ import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -41,14 +45,6 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Inventories;
import dev.zontreck.engineerdecor.libmc.Overlay;
import dev.zontreck.engineerdecor.libmc.RfEnergy;
import javax.annotation.Nullable;
import java.util.HashSet;
@ -56,8 +52,7 @@ import java.util.List;
import java.util.Random;
public class EdBreaker
{
public class EdBreaker {
public static final int BOOST_FACTOR = 8;
public static final int DEFAULT_BOOST_ENERGY = 64;
public static final int DEFAULT_BREAKING_RELUCTANCE = 17;
@ -70,54 +65,56 @@ public class EdBreaker
private static int min_breaking_time = DEFAULT_MIN_BREAKING_TIME;
private static boolean requires_power = false;
public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required)
{
public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required) {
final int interval = BreakerTileEntity.TICK_INTERVAL;
boost_energy_consumption = interval * Mth.clamp(boost_energy_per_tick, 4, 4096);
energy_max = Math.max(boost_energy_consumption * 10, 100000);
breaking_reluctance = Mth.clamp(breaking_time_per_hardness, 5, 50);
min_breaking_time = Mth.clamp(min_breaking_time_ticks, 10, 100);
requires_power = power_required;
ModConfig.log("Config block breaker: Boost energy consumption:" + (boost_energy_consumption/interval) + "rf/t, reluctance=" + breaking_reluctance + "t/hrdn, break time offset=" + min_breaking_time + "t.");
ModConfig.log("Config block breaker: Boost energy consumption:" + (boost_energy_consumption / interval) + "rf/t, reluctance=" + breaking_reluctance + "t/hrdn, break time offset=" + min_breaking_time + "t.");
}
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class BreakerBlock extends StandardBlocks.HorizontalWaterLoggable implements StandardEntityBlocks.IStandardEntityBlock<BreakerTileEntity>
{
public static class BreakerBlock extends StandardBlocks.HorizontalWaterLoggable implements StandardEntityBlocks.IStandardEntityBlock<BreakerTileEntity> {
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BreakerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs)
{ super(config, builder, unrotatedAABBs); }
public BreakerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs) {
super(config, builder, unrotatedAABBs);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(ACTIVE); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(ACTIVE);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(ACTIVE, false); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(ACTIVE, false);
}
@OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation")
public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.getValue(ACTIVE))) return;
public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) {
if ((state.getBlock() != this) || (!state.getValue(ACTIVE))) return;
// Sound
{
SoundEvent sound = SoundEvents.WOOD_HIT;
BlockState target_state = world.getBlockState(pos.relative(state.getValue(BreakerBlock.HORIZONTAL_FACING)));
SoundType stype = target_state.getBlock().getSoundType(target_state);
if((stype == SoundType.WOOL) || (stype == SoundType.GRASS) || (stype == SoundType.SNOW)) {
if ((stype == SoundType.WOOL) || (stype == SoundType.GRASS) || (stype == SoundType.SNOW)) {
sound = SoundEvents.WOOL_HIT;
} else if((stype == SoundType.GRAVEL) || (stype == SoundType.SAND)) {
} else if ((stype == SoundType.GRAVEL) || (stype == SoundType.SAND)) {
sound = SoundEvents.GRAVEL_HIT;
}
world.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), sound, SoundSource.BLOCKS, 0.1f, 1.2f, false);
@ -125,9 +122,9 @@ public class EdBreaker
// Particles
{
final double rv = rnd.nextDouble();
if(rv < 0.8) {
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
if (rv < 0.8) {
final double x = 0.5 + pos.getX(), y = 0.5 + pos.getY(), z = 0.5 + pos.getZ();
final double xc = 0.52, xr = rnd.nextDouble() * 0.4 - 0.2, yr = (y - 0.3 + rnd.nextDouble() * 0.2);
switch (state.getValue(HORIZONTAL_FACING)) {
case WEST -> world.addParticle(ParticleTypes.SMOKE, x - xc, yr, z + xr, 0.0, 0.0, 0.0);
case EAST -> world.addParticle(ParticleTypes.SMOKE, x + xc, yr, z + xr, 0.0, 0.0, 0.0);
@ -140,36 +137,37 @@ public class EdBreaker
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof Level) || (world.isClientSide)) return;
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) {
if (!(world instanceof Level) || (world.isClientSide)) return;
BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof BreakerTileEntity)) return;
((BreakerTileEntity)te).block_updated();
if (!(te instanceof BreakerTileEntity)) return;
((BreakerTileEntity) te).block_updated();
}
@Override
@SuppressWarnings("deprecation")
public boolean isSignalSource(BlockState state)
{ return true; }
public boolean isSignalSource(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side)
{ return 0; }
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
return 0;
}
@Override
@SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side)
{ return 0; }
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
return 0;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (world.isClientSide()) return InteractionResult.SUCCESS;
BlockEntity te = world.getBlockEntity(pos);
if(te instanceof BreakerTileEntity) ((BreakerTileEntity)te).state_message(player);
if (te instanceof BreakerTileEntity) ((BreakerTileEntity) te).state_message(player);
return InteractionResult.CONSUME;
}
}
@ -178,67 +176,11 @@ public class EdBreaker
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BreakerTileEntity extends StandardEntityBlocks.StandardBlockEntity
{
public static class BreakerTileEntity extends StandardEntityBlocks.StandardBlockEntity {
public static final int IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5;
private int tick_timer_;
private int active_timer_;
private int proc_time_elapsed_;
private int time_needed_;
private final RfEnergy.Battery battery_ = new RfEnergy.Battery(energy_max, boost_energy_consumption, 0);
private final LazyOptional<IEnergyStorage> energy_handler_ = battery_.createEnergyHandler();
public BreakerTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); }
public void block_updated()
{ if(tick_timer_ > 2) tick_timer_ = 2; }
public void readnbt(CompoundTag nbt)
{ battery_.load(nbt); }
private void writenbt(CompoundTag nbt)
{ battery_.save(nbt); }
public void state_message(Player player)
{
String progress = "0";
if((proc_time_elapsed_ > 0) && (time_needed_ > 0)) {
progress = Integer.toString((int)Mth.clamp((((double)proc_time_elapsed_) / ((double)time_needed_) * 100), 0, 100));
}
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_block_breaker.status", battery_.getSOC(), energy_max, progress));
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt); }
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt); }
@Override
public void setRemoved()
{
super.setRemoved();
energy_handler_.invalidate();
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
private static final HashSet<Block> blacklist = new HashSet<>();
static {
blacklist.add(Blocks.AIR);
blacklist.add(Blocks.BEDROCK);
@ -250,96 +192,157 @@ public class EdBreaker
blacklist.add(Blocks.BARRIER);
}
private static boolean isBreakable(BlockState state, BlockPos pos, Level world)
{
private final RfEnergy.Battery battery_ = new RfEnergy.Battery(energy_max, boost_energy_consumption, 0);
private final LazyOptional<IEnergyStorage> energy_handler_ = battery_.createEnergyHandler();
private int tick_timer_;
private int active_timer_;
private int proc_time_elapsed_;
private int time_needed_;
public BreakerTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
private static boolean isBreakable(BlockState state, BlockPos pos, Level world) {
final Block block = state.getBlock();
if(blacklist.contains(block)) return false;
if(state.isAir()) return false;
if(state.getMaterial().isLiquid()) return false;
if (blacklist.contains(block)) return false;
if (state.isAir()) return false;
if (state.getBlock() instanceof LiquidBlock) return false;
float bh = state.getDestroySpeed(world, pos);
return !((bh<0) || (bh>55));
return !((bh < 0) || (bh > 55));
}
private static void spawnBlockAsEntity(Level world, BlockPos pos, ItemStack stack) {
if(world.isClientSide || stack.isEmpty() || (!world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) || world.restoringBlockSnapshots) return;
if (world.isClientSide || stack.isEmpty() || (!world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) || world.restoringBlockSnapshots)
return;
ItemEntity e = new ItemEntity(world,
((world.random.nextFloat()*0.1)+0.5) + pos.getX(),
((world.random.nextFloat()*0.1)+0.5) + pos.getY(),
((world.random.nextFloat()*0.1)+0.5) + pos.getZ(),
((world.random.nextFloat() * 0.1) + 0.5) + pos.getX(),
((world.random.nextFloat() * 0.1) + 0.5) + pos.getY(),
((world.random.nextFloat() * 0.1) + 0.5) + pos.getZ(),
stack
);
e.setDefaultPickUpDelay();
e.setDeltaMovement((world.random.nextFloat()*0.1-0.05), (world.random.nextFloat()*0.1-0.03), (world.random.nextFloat()*0.1-0.05));
e.setDeltaMovement((world.random.nextFloat() * 0.1 - 0.05), (world.random.nextFloat() * 0.1 - 0.03), (world.random.nextFloat() * 0.1 - 0.05));
world.addFreshEntity(e);
}
private static boolean canInsertInto(Level world, BlockPos pos)
{
// BlockEntity ------------------------------------------------------------------------------
private static boolean canInsertInto(Level world, BlockPos pos) {
// Maybe make a tag for that. The question is if it is actually worth it, or if that would be only
// tag spamming the game. So for now only FH and VH.
final BlockState state = world.getBlockState(pos);
return (state.getBlock() == ModContent.getBlock("factory_hopper")) || (state.getBlock() == Blocks.HOPPER);
}
private boolean breakBlock(BlockState state, BlockPos pos, Level world)
{
if(world.isClientSide || (!(world instanceof ServerLevel)) || world.restoringBlockSnapshots) return false; // retry next cycle
public void block_updated() {
if (tick_timer_ > 2) tick_timer_ = 2;
}
public void readnbt(CompoundTag nbt) {
battery_.load(nbt);
}
// Capability export ----------------------------------------------------------------------------
private void writenbt(CompoundTag nbt) {
battery_.save(nbt);
}
// ITickable ------------------------------------------------------------------------------------
public void state_message(Player player) {
String progress = "0";
if ((proc_time_elapsed_ > 0) && (time_needed_ > 0)) {
progress = Integer.toString((int) Mth.clamp((((double) proc_time_elapsed_) / ((double) time_needed_) * 100), 0, 100));
}
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_block_breaker.status", battery_.getSOC(), energy_max, progress));
}
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt);
}
@Override
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt);
}
@Override
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
}
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
private boolean breakBlock(BlockState state, BlockPos pos, Level world) {
if (world.isClientSide || (!(world instanceof ServerLevel)) || world.restoringBlockSnapshots)
return false; // retry next cycle
List<ItemStack> drops;
final Block block = state.getBlock();
final boolean insert = canInsertInto(world, getBlockPos().below());
drops = Block.getDrops(state, (ServerLevel)world, pos, world.getBlockEntity(pos));
drops = Block.getDrops(state, (ServerLevel) world, pos, world.getBlockEntity(pos));
world.removeBlock(pos, false);
for(ItemStack drop:drops) {
if(!insert) {
for (ItemStack drop : drops) {
if (!insert) {
spawnBlockAsEntity(world, pos, drop);
} else {
final ItemStack remaining = Inventories.insert(world, getBlockPos().below(), Direction.UP, drop, false);
if(!remaining.isEmpty()) spawnBlockAsEntity(world, pos, remaining);
if (!remaining.isEmpty()) spawnBlockAsEntity(world, pos, remaining);
}
}
SoundType stype = state.getBlock().getSoundType(state, world, pos, null);
if(stype != null) world.playSound(null, pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
if (stype != null)
world.playSound(null, pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume() * 0.6f, stype.getPitch());
return true;
}
@Override
@SuppressWarnings("deprecation")
public void tick()
{
if(--tick_timer_ > 0) return;
public void tick() {
if (--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final BlockState device_state = level.getBlockState(worldPosition);
if(!(device_state.getBlock() instanceof BreakerBlock)) return;
if (!(device_state.getBlock() instanceof BreakerBlock)) return;
final BlockPos target_pos = worldPosition.relative(device_state.getValue(BreakerBlock.HORIZONTAL_FACING));
final BlockState target_state = level.getBlockState(target_pos);
if((level.hasNeighborSignal(worldPosition)) || (!isBreakable(target_state, target_pos, level))) {
if(device_state.getValue(BreakerBlock.ACTIVE)) level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, false), 1|2);
if ((level.hasNeighborSignal(worldPosition)) || (!isBreakable(target_state, target_pos, level))) {
if (device_state.getValue(BreakerBlock.ACTIVE))
level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, false), 1 | 2);
proc_time_elapsed_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL;
return;
}
time_needed_ = Mth.clamp((int)(target_state.getDestroySpeed(level, worldPosition) * breaking_reluctance) + min_breaking_time, min_breaking_time, MAX_BREAKING_TIME);
if(battery_.draw(boost_energy_consumption)) {
proc_time_elapsed_ += TICK_INTERVAL * (1+BOOST_FACTOR);
time_needed_ += min_breaking_time * (3*BOOST_FACTOR/5);
time_needed_ = Mth.clamp((int) (target_state.getDestroySpeed(level, worldPosition) * breaking_reluctance) + min_breaking_time, min_breaking_time, MAX_BREAKING_TIME);
if (battery_.draw(boost_energy_consumption)) {
proc_time_elapsed_ += TICK_INTERVAL * (1 + BOOST_FACTOR);
time_needed_ += min_breaking_time * (3 * BOOST_FACTOR / 5);
active_timer_ = 2;
} else if(!requires_power) {
} else if (!requires_power) {
proc_time_elapsed_ += TICK_INTERVAL;
active_timer_ = 1024;
} else if(active_timer_ > 0) {
} else if (active_timer_ > 0) {
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL);
if (requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2 * TICK_INTERVAL);
}
if(proc_time_elapsed_ >= time_needed_) {
if (proc_time_elapsed_ >= time_needed_) {
proc_time_elapsed_ = 0;
breakBlock(target_state, target_pos, level);
active = false;
}
if(device_state.getValue(BreakerBlock.ACTIVE) != active) {
level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, active), 1|2);
if (device_state.getValue(BreakerBlock.ACTIVE) != active) {
level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, active), 1 | 2);
}
}

View file

@ -8,6 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Inventories;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
@ -31,8 +33,6 @@ import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Inventories;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -41,32 +41,24 @@ import java.util.Collections;
import java.util.List;
public class EdCatwalkBlock extends StandardBlocks.HorizontalFourWayWaterLoggable
{
public class EdCatwalkBlock extends StandardBlocks.HorizontalFourWayWaterLoggable {
final Block railing_block;
final AABB base_aabb;
public EdCatwalkBlock(long config, BlockBehaviour.Properties properties, final AABB base_aabb, final AABB railing_aabb, final Block railing_block)
{ super(config, properties, base_aabb, railing_aabb, 0); this.railing_block = railing_block; this.base_aabb=base_aabb; }
public EdCatwalkBlock(long config, BlockBehaviour.Properties properties, final AABB base_aabb, final AABB railing_aabb, final Block railing_block) {
super(config, properties, base_aabb, railing_aabb, 0);
this.railing_block = railing_block;
this.base_aabb = base_aabb;
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos)
{ return true; }
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false); }
public static boolean place_consume(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, int shrink)
{
if(!world.setBlock(pos, state, Block.UPDATE_ALL)) return false;
public static boolean place_consume(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, int shrink) {
if (!world.setBlock(pos, state, Block.UPDATE_ALL)) return false;
world.playSound(player, pos, SoundEvents.METAL_PLACE, SoundSource.BLOCKS, 1f, 1f);
if((!player.isCreative()) && (!world.isClientSide())) {
if ((!player.isCreative()) && (!world.isClientSide())) {
ItemStack stack = player.getItemInHand(hand);
if(shrink >= 0) {
if (shrink >= 0) {
stack.shrink(shrink);
} else if(stack.getCount() < stack.getMaxStackSize()) {
} else if (stack.getCount() < stack.getMaxStackSize()) {
stack.grow(Math.abs(shrink));
} else {
Inventories.give(player, new ItemStack(stack.getItem(), Math.abs(shrink)));
@ -76,39 +68,51 @@ public class EdCatwalkBlock extends StandardBlocks.HorizontalFourWayWaterLoggabl
return true;
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return true;
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
final Item item = player.getItemInHand(hand).getItem();
if((!(item instanceof BlockItem))) return InteractionResult.PASS;
final Block block = ((BlockItem)item).getBlock();
if(block == this) {
if(hit.getDirection().getAxis().isHorizontal()) return InteractionResult.PASS; // place new block on the clicked side.
if ((!(item instanceof BlockItem))) return InteractionResult.PASS;
final Block block = ((BlockItem) item).getBlock();
if (block == this) {
if (hit.getDirection().getAxis().isHorizontal())
return InteractionResult.PASS; // place new block on the clicked side.
BlockPos adjacent_pos = pos.relative(player.getDirection());
BlockState adjacent_state = world.getBlockState(adjacent_pos);
if(adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) {
if (adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) {
BlockState place_state = defaultBlockState();
place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER);
place_state = place_state.setValue(WATERLOGGED, adjacent_state.getFluidState().getType() == Fluids.WATER);
place_consume(place_state, world, adjacent_pos, player, hand, 1);
}
return InteractionResult.sidedSuccess(world.isClientSide());
}
if(block == railing_block) {
if (block == railing_block) {
Direction face = hit.getDirection();
final Vec3 rhv = hit.getLocation().subtract(Vec3.atCenterOf(hit.getBlockPos()));
if(face.getAxis().isHorizontal()) {
if (face.getAxis().isHorizontal()) {
// Side or railing clicked
if(rhv.multiply(Vec3.atLowerCornerOf(face.getNormal())).scale(2).lengthSqr() < 0.99) face = face.getOpposite(); // click on railing, not the outer side.
} else if(player.distanceToSqr(Vec3.atCenterOf(pos)) < 3) {
if (rhv.multiply(Vec3.atLowerCornerOf(face.getNormal())).scale(2).lengthSqr() < 0.99)
face = face.getOpposite(); // click on railing, not the outer side.
} else if (player.distanceToSqr(Vec3.atCenterOf(pos)) < 3) {
// near accurate placement
face = Direction.getNearest(rhv.x, 0, rhv.z);
} else {
// far automatic placement
face = Direction.getNearest(player.getLookAngle().x, 0, player.getLookAngle().z);
List<Direction> free_sides = Arrays.stream(Direction.values()).filter(d -> d.getAxis().isHorizontal() && (world.getBlockState(pos.relative(d)).getBlock() != this)).toList();
if(free_sides.isEmpty()) return InteractionResult.sidedSuccess(world.isClientSide());
if(!free_sides.contains(face)) face = free_sides.get(0);
if (free_sides.isEmpty()) return InteractionResult.sidedSuccess(world.isClientSide());
if (!free_sides.contains(face)) face = free_sides.get(0);
}
BooleanProperty railing = getDirectionProperty(face);
boolean add = (!state.getValue(railing));
@ -119,17 +123,17 @@ public class EdCatwalkBlock extends StandardBlocks.HorizontalFourWayWaterLoggabl
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion)
{
if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) {
if (world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
List<ItemStack> drops = new ArrayList<>();
drops.add(new ItemStack(state.getBlock().asItem()));
int n = (state.getValue(NORTH)?1:0)+(state.getValue(EAST)?1:0)+(state.getValue(SOUTH)?1:0)+(state.getValue(WEST)?1:0);
if(n > 0) drops.add(new ItemStack(railing_block, n));
int n = (state.getValue(NORTH) ? 1 : 0) + (state.getValue(EAST) ? 1 : 0) + (state.getValue(SOUTH) ? 1 : 0) + (state.getValue(WEST) ? 1 : 0);
if (n > 0) drops.add(new ItemStack(railing_block, n));
return drops;
}

View file

@ -8,6 +8,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
@ -34,35 +37,30 @@ 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 dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable;
import java.util.*;
public class EdCatwalkStairsBlock extends StandardBlocks.HorizontalWaterLoggable
{
public class EdCatwalkStairsBlock extends StandardBlocks.HorizontalWaterLoggable {
public static final BooleanProperty RIGHT_RAILING = BooleanProperty.create("right_railing");
public static final BooleanProperty LEFT_RAILING = BooleanProperty.create("left_railing");
protected final Map<BlockState, VoxelShape> shapes;
protected final Map<BlockState, VoxelShape> collision_shapes;
protected final Map<Direction, Integer> y_rotations;
public EdCatwalkStairsBlock(long config, BlockBehaviour.Properties properties, final AABB[] base_aabb, final AABB[] railing_aabbs)
{
public EdCatwalkStairsBlock(long config, BlockBehaviour.Properties properties, final AABB[] base_aabb, final AABB[] railing_aabbs) {
super(config, properties, base_aabb);
Map<BlockState, VoxelShape> sh = new HashMap<>();
Map<BlockState, VoxelShape> csh = new HashMap<>();
getStateDefinition().getPossibleStates().forEach(state->{
getStateDefinition().getPossibleStates().forEach(state -> {
Direction facing = state.getValue(HORIZONTAL_FACING);
VoxelShape base_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(base_aabb, facing, true));
if(state.getValue(RIGHT_RAILING)) {
if (state.getValue(RIGHT_RAILING)) {
VoxelShape right_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(Auxiliaries.getMirroredAABB(railing_aabbs, Direction.Axis.X), facing, true));
base_shape = Shapes.joinUnoptimized(base_shape, right_shape, BooleanOp.OR);
}
if(state.getValue(LEFT_RAILING)) {
if (state.getValue(LEFT_RAILING)) {
VoxelShape left_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(railing_aabbs, facing, true));
base_shape = Shapes.joinUnoptimized(base_shape, left_shape, BooleanOp.OR);
}
@ -82,79 +80,87 @@ public class EdCatwalkStairsBlock extends StandardBlocks.HorizontalWaterLoggable
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context)
{ return shapes.getOrDefault(state, Shapes.block()); }
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 VoxelShape getCollisionShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return collision_shapes.getOrDefault(state, Shapes.block());
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(RIGHT_RAILING, LEFT_RAILING); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(RIGHT_RAILING, LEFT_RAILING);
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos)
{ return true; }
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return true;
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
final Item item = player.getItemInHand(hand).getItem();
if((!(item instanceof BlockItem))) return InteractionResult.PASS;
final Block block = ((BlockItem)item).getBlock();
if ((!(item instanceof BlockItem))) return InteractionResult.PASS;
final Block block = ((BlockItem) item).getBlock();
final Direction facing = state.getValue(HORIZONTAL_FACING);
if(block == this) {
final Direction hlv = Arrays.stream(Direction.orderedByNearest(player)).filter(d->d.getAxis().isHorizontal()).findFirst().orElse(Direction.NORTH);
if (block == this) {
final Direction hlv = Arrays.stream(Direction.orderedByNearest(player)).filter(d -> d.getAxis().isHorizontal()).findFirst().orElse(Direction.NORTH);
BlockPos adjacent_pos;
if(hlv == facing) {
if (hlv == facing) {
adjacent_pos = pos.above().relative(hlv);
} else if(hlv == facing.getOpposite()) {
} else if (hlv == facing.getOpposite()) {
adjacent_pos = pos.below().relative(hlv);
} else {
return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME;
}
final BlockState adjacent_state = world.getBlockState(adjacent_pos);
if(adjacent_state == null) return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME;
if(!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) return InteractionResult.CONSUME;
if (adjacent_state == null)
return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME;
if (!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection())))
return InteractionResult.CONSUME;
BlockState place_state = defaultBlockState().setValue(HORIZONTAL_FACING, facing);
place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER);
place_state = place_state.setValue(WATERLOGGED, adjacent_state.getFluidState().getType() == Fluids.WATER);
EdCatwalkBlock.place_consume(place_state, world, adjacent_pos, player, hand, 1);
return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME;
} else if((block == ModContent.getBlock("steel_catwalk")) || (block == ModContent.getBlock("steel_catwalk_ta"))) {
} else if ((block == ModContent.getBlock("steel_catwalk")) || (block == ModContent.getBlock("steel_catwalk_ta"))) {
BlockPos adjacent_pos;
adjacent_pos = pos.relative(facing);
final BlockState adjacent_state = world.getBlockState(adjacent_pos);
if(adjacent_state == null) return InteractionResult.CONSUME;
if(!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) return InteractionResult.CONSUME;
if (adjacent_state == null) return InteractionResult.CONSUME;
if (!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection())))
return InteractionResult.CONSUME;
BlockState place_state = ModContent.getBlock("steel_catwalk_ta").defaultBlockState(); // ModContent.STEEL_CATWALK_TOP_ALIGNED
place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER);
place_state = place_state.setValue(WATERLOGGED, adjacent_state.getFluidState().getType() == Fluids.WATER);
EdCatwalkBlock.place_consume(place_state, world, adjacent_pos, player, hand, 1);
return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME;
} else if(block == ModContent.getBlock("steel_railing")) {
} else if (block == ModContent.getBlock("steel_railing")) {
Direction face = hit.getDirection();
int shrink = 0;
BlockState place_state = state;
if(face == Direction.UP) {
Vec3 rhv = hit.getLocation().subtract(Vec3.atCenterOf(hit.getBlockPos())).multiply(new Vec3(1,0,1)).cross(Vec3.atLowerCornerOf(facing.getNormal()));
if (face == Direction.UP) {
Vec3 rhv = hit.getLocation().subtract(Vec3.atCenterOf(hit.getBlockPos())).multiply(new Vec3(1, 0, 1)).cross(Vec3.atLowerCornerOf(facing.getNormal()));
face = (rhv.y > 0) ? (facing.getClockWise()) : (facing.getCounterClockWise());
}
if(face == facing.getClockWise()) {
if(state.getValue(RIGHT_RAILING)) {
if (face == facing.getClockWise()) {
if (state.getValue(RIGHT_RAILING)) {
place_state = state.setValue(RIGHT_RAILING, false);
shrink = -1;
} else {
place_state = state.setValue(RIGHT_RAILING, true);
shrink = 1;
}
} else if(face == facing.getCounterClockWise()) {
if(state.getValue(LEFT_RAILING)) {
} else if (face == facing.getCounterClockWise()) {
if (state.getValue(LEFT_RAILING)) {
place_state = state.setValue(LEFT_RAILING, false);
shrink = -1;
} else {
@ -162,24 +168,24 @@ public class EdCatwalkStairsBlock extends StandardBlocks.HorizontalWaterLoggable
shrink = 1;
}
}
if(shrink != 0) EdCatwalkBlock.place_consume(place_state, world, pos, player, hand, shrink);
if (shrink != 0) EdCatwalkBlock.place_consume(place_state, world, pos, player, hand, shrink);
return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME;
}
return InteractionResult.PASS;
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion)
{
if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) {
if (world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
List<ItemStack> drops = new ArrayList<>();
drops.add(new ItemStack(state.getBlock().asItem()));
int n = (state.getValue(LEFT_RAILING)?1:0)+(state.getValue(RIGHT_RAILING)?1:0);
if(n > 0) drops.add(new ItemStack(ModContent.getBlock("steel_railing"), n));
int n = (state.getValue(LEFT_RAILING) ? 1 : 0) + (state.getValue(RIGHT_RAILING) ? 1 : 0);
if (n > 0) drops.add(new ItemStack(ModContent.getBlock("steel_railing"), n));
return drops;
}

View file

@ -8,6 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
@ -32,8 +34,6 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -42,55 +42,57 @@ import java.util.List;
import java.util.stream.Collectors;
public class EdCatwalkTopAlignedBlock extends StandardBlocks.WaterLoggable
{
public class EdCatwalkTopAlignedBlock extends StandardBlocks.WaterLoggable {
public static final IntegerProperty VARIANT = IntegerProperty.create("variant", 0, 4);
protected final List<VoxelShape> variant_shapes;
protected final Block inset_light_block;
public EdCatwalkTopAlignedBlock(long config, BlockBehaviour.Properties properties, final VoxelShape[] variant_shapes, final Block inset_light_block)
{
public EdCatwalkTopAlignedBlock(long config, BlockBehaviour.Properties properties, final VoxelShape[] variant_shapes, final Block inset_light_block) {
super(config, properties, variant_shapes[0]);
registerDefaultState(super.defaultBlockState().setValue(VARIANT, 0));
this.variant_shapes = VARIANT.getPossibleValues().stream().map(i->(i<variant_shapes.length) ? (variant_shapes[i]) : (Shapes.block())).collect(Collectors.toList());
this.variant_shapes = VARIANT.getPossibleValues().stream().map(i -> (i < variant_shapes.length) ? (variant_shapes[i]) : (Shapes.block())).collect(Collectors.toList());
this.inset_light_block = inset_light_block;
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos)
{ return true; }
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return true;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return variant_shapes.get(state.getValue(VARIANT)); }
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return variant_shapes.get(state.getValue(VARIANT));
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
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(VARIANT); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(VARIANT);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState state = adapted_state(super.getStateForPlacement(context), context.getLevel(), context.getClickedPos());
if(context.getClickedFace() != Direction.UP) return state;
if (context.getClickedFace() != Direction.UP) return state;
BlockState below = context.getLevel().getBlockState(context.getClickedPos().below());
if((state.getValue(VARIANT)==0) && (below.isFaceSturdy(context.getLevel(), context.getClickedPos().below(), Direction.UP))) return state.setValue(VARIANT, 3);
if ((state.getValue(VARIANT) == 0) && (below.isFaceSturdy(context.getLevel(), context.getClickedPos().below(), Direction.UP)))
return state.setValue(VARIANT, 3);
return state;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
final Item item = player.getItemInHand(hand).getItem();
if((!(item instanceof BlockItem))) return InteractionResult.PASS;
final Block block = ((BlockItem)item).getBlock();
if(block == this) {
if ((!(item instanceof BlockItem))) return InteractionResult.PASS;
final Block block = ((BlockItem) item).getBlock();
if (block == this) {
if (hit.getDirection().getAxis().isHorizontal()) return InteractionResult.PASS;
BlockPos adjacent_pos = pos.relative(player.getDirection());
BlockState adjacent_state = world.getBlockState(adjacent_pos);
@ -101,7 +103,7 @@ public class EdCatwalkTopAlignedBlock extends StandardBlocks.WaterLoggable
}
return InteractionResult.sidedSuccess(world.isClientSide());
}
if(block == inset_light_block && hit.getDirection() == Direction.DOWN) {
if (block == inset_light_block && hit.getDirection() == Direction.DOWN) {
int currentVariant = state.getValue(VARIANT);
if (!(currentVariant == 0 || currentVariant == 4)) return InteractionResult.PASS;
boolean add = currentVariant == 0;
@ -112,17 +114,19 @@ public class EdCatwalkTopAlignedBlock extends StandardBlocks.WaterLoggable
}
@Override
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos)
{ return adapted_state(super.updateShape(state, facing, facingState, world, pos, facingPos), world, pos); }
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
return adapted_state(super.updateShape(state, facing, facingState, world, pos, facingPos), world, pos);
}
// ---
private BlockState adapted_state(BlockState state, LevelAccessor world, BlockPos pos)
{
private BlockState adapted_state(BlockState state, LevelAccessor world, BlockPos pos) {
BlockState below = world.getBlockState(pos.below());
if (state == null || state.getValue(VARIANT) == 4) return state;
if((below.getBlock() == ModContent.getBlock("thick_steel_pole")) || (below.getBlock() == ModContent.getBlock("thick_steel_pole_head"))) return state.setValue(VARIANT, 1);
if((below.getBlock() == ModContent.getBlock("thin_steel_pole")) || (below.getBlock() == ModContent.getBlock("thin_steel_pole_head"))) return state.setValue(VARIANT, 2);
if ((below.getBlock() == ModContent.getBlock("thick_steel_pole")) || (below.getBlock() == ModContent.getBlock("thick_steel_pole_head")))
return state.setValue(VARIANT, 1);
if ((below.getBlock() == ModContent.getBlock("thin_steel_pole")) || (below.getBlock() == ModContent.getBlock("thin_steel_pole_head")))
return state.setValue(VARIANT, 2);
return state;
}
@ -134,13 +138,13 @@ public class EdCatwalkTopAlignedBlock extends StandardBlocks.WaterLoggable
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion)
{
if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) {
if (world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
List<ItemStack> drops = new ArrayList<>();
drops.add(new ItemStack(state.getBlock().asItem()));
if (state.getValue(VARIANT) == 4) drops.add(new ItemStack(inset_light_block, 1));

View file

@ -8,9 +8,13 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
@ -29,64 +33,57 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.PlayMessages;
import net.minecraftforge.network.NetworkHooks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import net.minecraftforge.network.PlayMessages;
import java.util.List;
public class EdChair
{
public class EdChair {
private static boolean sitting_enabled = true;
private static double sitting_probability = 0.1;
private static double standup_probability = 0.01;
public static void on_config(boolean without_sitting, boolean without_mob_sitting, double sitting_probability_percent, double standup_probability_percent)
{
public static void on_config(boolean without_sitting, boolean without_mob_sitting, double sitting_probability_percent, double standup_probability_percent) {
sitting_enabled = (!without_sitting);
sitting_probability = (without_sitting||without_mob_sitting) ? 0.0 : Mth.clamp(sitting_probability_percent/100, 0, 0.9);
standup_probability = (without_sitting||without_mob_sitting) ? 1.0 : Mth.clamp(standup_probability_percent/100, 1e-6, 1e-2);
ModConfig.log("Config chairs: sit:" + sitting_enabled + ", mob-sit: " + (sitting_probability*100) + "%, standup: " + (standup_probability) + "%.");
sitting_probability = (without_sitting || without_mob_sitting) ? 0.0 : Mth.clamp(sitting_probability_percent / 100, 0, 0.9);
standup_probability = (without_sitting || without_mob_sitting) ? 1.0 : Mth.clamp(standup_probability_percent / 100, 1e-6, 1e-2);
ModConfig.log("Config chairs: sit:" + sitting_enabled + ", mob-sit: " + (sitting_probability * 100) + "%, standup: " + (standup_probability) + "%.");
}
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class ChairBlock extends StandardBlocks.HorizontalWaterLoggable
{
public ChairBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs)
{ super(config, builder.randomTicks(), unrotatedAABBs); }
public static class ChairBlock extends StandardBlocks.HorizontalWaterLoggable {
public ChairBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs) {
super(config, builder.randomTicks(), unrotatedAABBs);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{
if(!sitting_enabled) return InteractionResult.PASS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
if (!sitting_enabled) return InteractionResult.PASS;
if (world.isClientSide()) return InteractionResult.SUCCESS;
EntityChair.sit(world, player, pos);
return InteractionResult.CONSUME;
}
@Override
@SuppressWarnings("deprecation")
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity)
{
if(sitting_enabled && (Math.random() < sitting_probability) && (entity instanceof Mob)) EntityChair.sit(world, (LivingEntity)entity, pos);
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
if (sitting_enabled && (Math.random() < sitting_probability) && (entity instanceof Mob))
EntityChair.sit(world, (LivingEntity) entity, pos);
}
@Override
@SuppressWarnings("deprecation")
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rnd)
{
if((!sitting_enabled) || (sitting_probability < 1e-6)) return;
final List<Mob> entities = world.getEntitiesOfClass(Mob.class, new AABB(pos).inflate(2,1,2).expandTowards(0,1,0), e->true);
if(entities.isEmpty()) return;
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rnd) {
if ((!sitting_enabled) || (sitting_probability < 1e-6)) return;
final List<Mob> entities = world.getEntitiesOfClass(Mob.class, new AABB(pos).inflate(2, 1, 2).expandTowards(0, 1, 0), e -> true);
if (entities.isEmpty()) return;
int index = rnd.nextInt(entities.size());
if((index < 0) || (index >= entities.size())) return;
if ((index < 0) || (index >= entities.size())) return;
EntityChair.sit(world, entities.get(index), pos);
}
}
@ -95,55 +92,51 @@ public class EdChair
// Entity
//--------------------------------------------------------------------------------------------------------------------
public static class EntityChair extends Entity
{
public static class EntityChair extends Entity {
public static final double x_offset = 0.5d;
public static final double y_offset = 0.4d;
public static final double z_offset = 0.5d;
public BlockPos chair_pos = new BlockPos(0, 0, 0);
private int t_sit = 0;
public BlockPos chair_pos = new BlockPos(0,0,0);
public EntityChair(EntityType<? extends Entity> entityType, Level world)
{
public EntityChair(EntityType<? extends Entity> entityType, Level world) {
super(entityType, world);
blocksBuilding=true;
blocksBuilding = true;
setDeltaMovement(Vec3.ZERO);
canUpdate(true);
noPhysics=true;
noPhysics = true;
}
public EntityChair(Level world)
{ this(ModContent.getEntityType("et_chair"), world); }
public EntityChair(Level world) {
this(ModContent.getEntityType("et_chair"), world);
}
public static EntityChair customClientFactory(PlayMessages.SpawnEntity spkt, Level world)
{ return new EntityChair(world); }
public static EntityChair customClientFactory(PlayMessages.SpawnEntity spkt, Level world) {
return new EntityChair(world);
}
public Packet<?> getAddEntityPacket()
{ return NetworkHooks.getEntitySpawningPacket(this); }
public static boolean accepts_mob(LivingEntity entity)
{
if(!(entity instanceof Monster)) return false;
if((entity.getType().getDimensions().height > 2.5) || (entity.getType().getDimensions().height > 2.0)) return false;
if(entity instanceof Zombie) return true;
if(entity instanceof ZombieVillager) return true;
if(entity instanceof ZombifiedPiglin) return true;
if(entity instanceof Piglin) return true;
if(entity instanceof Husk) return true;
if(entity instanceof Stray) return true;
if(entity instanceof Skeleton) return true;
if(entity instanceof WitherSkeleton) return true;
public static boolean accepts_mob(LivingEntity entity) {
if (!(entity instanceof Monster)) return false;
if ((entity.getType().getDimensions().height > 2.5) || (entity.getType().getDimensions().height > 2.0))
return false;
if (entity instanceof Zombie) return true;
if (entity instanceof ZombieVillager) return true;
if (entity instanceof ZombifiedPiglin) return true;
if (entity instanceof Piglin) return true;
if (entity instanceof Husk) return true;
if (entity instanceof Stray) return true;
if (entity instanceof Skeleton) return true;
if (entity instanceof WitherSkeleton) return true;
return false;
}
public static void sit(Level world, LivingEntity sitter, BlockPos pos)
{
if(!sitting_enabled) return;
if((world==null) || (world.isClientSide) || (sitter==null) || (pos==null)) return;
if((!(sitter instanceof Player)) && (!accepts_mob(sitter))) return;
if(!world.getEntitiesOfClass(EntityChair.class, new AABB(pos)).isEmpty()) return;
if(sitter.isVehicle() || (!sitter.isAlive()) || (sitter.isPassenger()) ) return;
if((!world.isEmptyBlock(pos.above())) || (!world.isEmptyBlock(pos.above(2)))) return;
public static void sit(Level world, LivingEntity sitter, BlockPos pos) {
if (!sitting_enabled) return;
if ((world == null) || (world.isClientSide) || (sitter == null) || (pos == null)) return;
if ((!(sitter instanceof Player)) && (!accepts_mob(sitter))) return;
if (!world.getEntitiesOfClass(EntityChair.class, new AABB(pos)).isEmpty()) return;
if (sitter.isVehicle() || (!sitter.isAlive()) || (sitter.isPassenger())) return;
if ((!world.isEmptyBlock(pos.above())) || (!world.isEmptyBlock(pos.above(2)))) return;
boolean on_top_of_block_position = true;
boolean use_next_negative_y_position = false;
EntityChair chair = new EntityChair(world);
@ -153,47 +146,55 @@ public class EdChair
chair.xo = chair_pos.getX();
chair.yo = chair_pos.getY();
chair.zo = chair_pos.getZ();
chair.setPos(pos.getX()+x_offset,pos.getY()+y_offset,pos.getZ()+z_offset);
chair.setPos(pos.getX() + x_offset, pos.getY() + y_offset, pos.getZ() + z_offset);
world.addFreshEntity(chair);
sitter.startRiding(chair, true);
}
@Override
protected void defineSynchedData() {}
public Packet<ClientGamePacketListener> getAddEntityPacket() {
return NetworkHooks.getEntitySpawningPacket(this);
}
@Override
protected void readAdditionalSaveData(CompoundTag compound) {}
protected void defineSynchedData() {
}
@Override
protected void addAdditionalSaveData(CompoundTag compound) {}
protected void readAdditionalSaveData(CompoundTag compound) {
}
@Override
public boolean isPushable()
{ return false; }
protected void addAdditionalSaveData(CompoundTag compound) {
}
@Override
public double getPassengersRidingOffset()
{ return 0.0; }
public boolean isPushable() {
return false;
}
@Override
public void tick()
{
if(level.isClientSide) return;
public double getPassengersRidingOffset() {
return 0.0;
}
@Override
public void tick() {
if (level().isClientSide) return;
super.tick();
if(--t_sit > 0) return;
if (--t_sit > 0) return;
Entity sitter = getPassengers().isEmpty() ? null : getPassengers().get(0);
if((sitter==null) || (!sitter.isAlive())) {
if ((sitter == null) || (!sitter.isAlive())) {
this.remove(RemovalReason.DISCARDED);
return;
}
boolean abort = (!sitting_enabled);
final BlockState state = level.getBlockState(chair_pos);
if((state==null) || (!(state.getBlock() instanceof ChairBlock))) abort = true;
if(!level.isEmptyBlock(chair_pos.above())) abort = true;
if((!(sitter instanceof Player)) && (Math.random() < standup_probability)) abort = true;
if(abort) {
for(Entity e:getPassengers()) {
if(e.isAlive()) e.stopRiding();
final BlockState state = level().getBlockState(chair_pos);
if ((state == null) || (!(state.getBlock() instanceof ChairBlock))) abort = true;
if (!level().isEmptyBlock(chair_pos.above())) abort = true;
if ((!(sitter instanceof Player)) && (Math.random() < standup_probability)) abort = true;
if (abort) {
for (Entity e : getPassengers()) {
if (e.isAlive()) e.stopRiding();
}
this.remove(RemovalReason.DISCARDED);
}

View file

@ -8,6 +8,7 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
@ -17,7 +18,7 @@ import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
@ -28,72 +29,72 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import javax.annotation.Nullable;
public class EdChimneyBlock extends StandardBlocks.Cutout
{
public class EdChimneyBlock extends StandardBlocks.Cutout {
public static final IntegerProperty POWER = BlockStateProperties.POWER;
public EdChimneyBlock(long config, BlockBehaviour.Properties properties, AABB aabb)
{ super(config, properties, aabb); }
public EdChimneyBlock(long config, BlockBehaviour.Properties properties, AABB aabb) {
super(config, properties, aabb);
}
public EdChimneyBlock(long config, BlockBehaviour.Properties builder)
{
this(config, builder, new AABB(0,0,0,1,1,1));
public EdChimneyBlock(long config, BlockBehaviour.Properties builder) {
this(config, builder, new AABB(0, 0, 0, 1, 1, 1));
registerDefaultState(super.defaultBlockState().setValue(POWER, 0)); // no smoke in JEI
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(POWER); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(POWER);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState state = super.getStateForPlacement(context);
if(state==null) return state;
if (state == null) return state;
int p = context.getLevel().getBestNeighborSignal(context.getClickedPos());
return state.setValue(POWER, p==0 ? 5 : p);
return state.setValue(POWER, p == 0 ? 5 : p);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{ world.setBlock(pos, state.setValue(POWER, (state.getValue(POWER)+1) & 0xf), 1|2); return InteractionResult.sidedSuccess(world.isClientSide()); }
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
world.setBlock(pos, state.setValue(POWER, (state.getValue(POWER) + 1) & 0xf), 1 | 2);
return InteractionResult.sidedSuccess(world.isClientSide());
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) {
int p = world.getBestNeighborSignal(pos);
if(p != state.getValue(POWER)) world.setBlock(pos, state.setValue(POWER, p), 2);
if (p != state.getValue(POWER)) world.setBlock(pos, state.setValue(POWER, p), 2);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd)
{
if(state.getBlock() != this) return;
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd) {
if (state.getBlock() != this) return;
final int p = state.getValue(POWER);
if(p==0) return;
int end = 1+rnd.nextInt(10) * p / 15;
for(int i=0; i<end; ++i) {
if (p == 0) return;
int end = 1 + rnd.nextInt(10) * p / 15;
for (int i = 0; i < end; ++i) {
double rv = rnd.nextDouble() * p / 5;
world.addParticle(
(rv > 0.7 ? ParticleTypes.LARGE_SMOKE : (rv>0.4 ? ParticleTypes.SMOKE : ParticleTypes.CAMPFIRE_COSY_SMOKE)),
0.5+pos.getX()+(rnd.nextDouble()*0.2),
0.9+pos.getY()+(rnd.nextDouble()*0.1),
0.5+pos.getZ()+(rnd.nextDouble()*0.2),
-0.02 + rnd.nextDouble()*0.04,
+0.05 + rnd.nextDouble()*0.1,
-0.02 + rnd.nextDouble()*0.04
(rv > 0.7 ? ParticleTypes.LARGE_SMOKE : (rv > 0.4 ? ParticleTypes.SMOKE : ParticleTypes.CAMPFIRE_COSY_SMOKE)),
0.5 + pos.getX() + (rnd.nextDouble() * 0.2),
0.9 + pos.getY() + (rnd.nextDouble() * 0.1),
0.5 + pos.getZ() + (rnd.nextDouble() * 0.2),
-0.02 + rnd.nextDouble() * 0.04,
+0.05 + rnd.nextDouble() * 0.1,
-0.02 + rnd.nextDouble() * 0.04
);
}
}

View file

@ -19,19 +19,19 @@ import net.minecraft.world.phys.shapes.VoxelShape;
import javax.annotation.Nullable;
public class EdChimneyTrunkBlock extends EdRoofBlock
{
public EdChimneyTrunkBlock(long config, BlockBehaviour.Properties properties)
{ super(config, properties.dynamicShape(), Shapes.empty(), Shapes.empty()); }
public class EdChimneyTrunkBlock extends EdRoofBlock {
public EdChimneyTrunkBlock(long config, BlockBehaviour.Properties properties) {
super(config, properties.dynamicShape(), Shapes.empty(), Shapes.empty());
}
public EdChimneyTrunkBlock(long config, BlockBehaviour.Properties properties, VoxelShape add, VoxelShape cut)
{ super(config, properties, add, cut); }
public EdChimneyTrunkBlock(long config, BlockBehaviour.Properties properties, VoxelShape add, VoxelShape cut) {
super(config, properties, add, cut);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState state = super.getStateForPlacement(context);
return (state==null) ? (state) : (state.setValue(EdRoofBlock.SHAPE, StairsShape.STRAIGHT).setValue(EdRoofBlock.HALF, Half.BOTTOM));
return (state == null) ? (state) : (state.setValue(EdRoofBlock.SHAPE, StairsShape.STRAIGHT).setValue(EdRoofBlock.HALF, Half.BOTTOM));
}
}

View file

@ -8,6 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
@ -17,36 +19,31 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec2;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.HashSet;
public class EdCornerOrnamentedBlock extends StandardBlocks.Directed
{
public class EdCornerOrnamentedBlock extends StandardBlocks.Directed {
protected final HashSet<Block> compatible_blocks;
public EdCornerOrnamentedBlock(long config, BlockBehaviour.Properties properties, Block[] assigned_wall_blocks)
{
super(config, properties, Auxiliaries.getPixeledAABB(0,0,0,16,16,16));
public EdCornerOrnamentedBlock(long config, BlockBehaviour.Properties properties, Block[] assigned_wall_blocks) {
super(config, properties, Auxiliaries.getPixeledAABB(0, 0, 0, 16, 16, 16));
compatible_blocks = new HashSet<>(Arrays.asList(assigned_wall_blocks));
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
final Level world = context.getLevel();
final BlockPos pos = context.getClickedPos();
// 1. Placement as below/above for corners, or placement adjacent horizontally if up/down facing.
for(Direction adj: Direction.values()) {
for (Direction adj : Direction.values()) {
BlockState state = world.getBlockState(pos.relative(adj));
if(state.getBlock() != this) continue;
if (state.getBlock() != this) continue;
Direction facing = state.getValue(FACING);
if(facing.getAxis().isHorizontal() == (adj.getAxis().isVertical())) {
if (facing.getAxis().isHorizontal() == (adj.getAxis().isVertical())) {
return super.getStateForPlacement(context).setValue(FACING, state.getValue(FACING));
}
}
@ -55,15 +52,15 @@ public class EdCornerOrnamentedBlock extends StandardBlocks.Directed
Direction facing = Direction.WEST;
final Vec2 look = context.getPlayer().getRotationVector();
final Direction hit_face = context.getClickedFace();
if((context.getClickedFace()==Direction.DOWN) && (look.x <= -60)) {
if ((context.getClickedFace() == Direction.DOWN) && (look.x <= -60)) {
facing = Direction.DOWN;
} else if((context.getClickedFace()==Direction.UP) && (look.x >= 60)) {
} else if ((context.getClickedFace() == Direction.UP) && (look.x >= 60)) {
facing = Direction.UP;
} else if(Mth.degreesDifferenceAbs(look.y, 45) <= 45) {
} else if (Mth.degreesDifferenceAbs(look.y, 45) <= 45) {
facing = Direction.NORTH;
} else if(Mth.degreesDifferenceAbs(look.y, 45+90) <= 45) {
} else if (Mth.degreesDifferenceAbs(look.y, 45 + 90) <= 45) {
facing = Direction.EAST;
} else if(Mth.degreesDifferenceAbs(look.y, 45+180) <= 45) {
} else if (Mth.degreesDifferenceAbs(look.y, 45 + 180) <= 45) {
facing = Direction.SOUTH;
}
return super.getStateForPlacement(context).setValue(FACING, facing);

View file

@ -8,6 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
@ -32,30 +34,27 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
public class EdDoubleGateBlock extends StandardBlocks.HorizontalWaterLoggable
{
public class EdDoubleGateBlock extends StandardBlocks.HorizontalWaterLoggable {
public static final IntegerProperty SEGMENT = IntegerProperty.create("segment", 0, 1);
public static final BooleanProperty OPEN = FenceGateBlock.OPEN;
public static final int SEGMENT_LOWER = 0;
public static final int SEGMENT_UPPER = 1;
protected final ArrayList<VoxelShape> collision_shapes_;
public EdDoubleGateBlock(long config, BlockBehaviour.Properties properties, AABB aabb)
{ this(config, properties, new AABB[]{aabb}); }
public EdDoubleGateBlock(long config, BlockBehaviour.Properties properties, AABB aabb) {
this(config, properties, new AABB[]{aabb});
}
public EdDoubleGateBlock(long config, BlockBehaviour.Properties properties, AABB[] aabbs)
{
public EdDoubleGateBlock(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
super(config, properties, aabbs);
AABB[] caabbs = new AABB[aabbs.length];
for(int i=0; i<caabbs.length; ++i) caabbs[i] = aabbs[i].expandTowards(0, 0.5, 0);
for (int i = 0; i < caabbs.length; ++i) caabbs[i] = aabbs[i].expandTowards(0, 0.5, 0);
collision_shapes_ = new ArrayList<>(Arrays.asList(
Shapes.block(),
Shapes.block(),
@ -69,96 +68,102 @@ public class EdDoubleGateBlock extends StandardBlocks.HorizontalWaterLoggable
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return state.getValue(OPEN) ? Shapes.empty() : collision_shapes_.get(state.getValue(HORIZONTAL_FACING).get3DDataValue() & 0x7); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return state.getValue(OPEN) ? Shapes.empty() : collision_shapes_.get(state.getValue(HORIZONTAL_FACING).get3DDataValue() & 0x7);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(SEGMENT).add(OPEN); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(SEGMENT).add(OPEN);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return getInitialState(super.getStateForPlacement(context), context.getLevel(), context.getClickedPos()); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return getInitialState(super.getStateForPlacement(context), context.getLevel(), context.getClickedPos());
}
@Override
@SuppressWarnings("deprecation")
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos)
{ return getInitialState(super.updateShape(state, facing, facingState, world, pos, facingPos), world, pos); }
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
return getInitialState(super.updateShape(state, facing, facingState, world, pos, facingPos), world, pos);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{
if((rayTraceResult.getDirection()==Direction.UP) || (rayTraceResult.getDirection()==Direction.DOWN) && (player.getItemInHand(hand).getItem()==this.asItem())) return InteractionResult.PASS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
if ((rayTraceResult.getDirection() == Direction.UP) || (rayTraceResult.getDirection() == Direction.DOWN) && (player.getItemInHand(hand).getItem() == this.asItem()))
return InteractionResult.PASS;
if (world.isClientSide()) return InteractionResult.SUCCESS;
final boolean open = !state.getValue(OPEN);
world.setBlock(pos, state.setValue(OPEN, open),2|8|16);
if(state.getValue(SEGMENT) == SEGMENT_UPPER) {
world.setBlock(pos, state.setValue(OPEN, open), 2 | 8 | 16);
if (state.getValue(SEGMENT) == SEGMENT_UPPER) {
final BlockState adjacent = world.getBlockState(pos.below());
if(adjacent.getBlock()==this) world.setBlock(pos.below(), adjacent.setValue(OPEN, open), 2|8|16);
if (adjacent.getBlock() == this) world.setBlock(pos.below(), adjacent.setValue(OPEN, open), 2 | 8 | 16);
} else {
final BlockState adjacent = world.getBlockState(pos.above());
if(adjacent.getBlock()==this) world.setBlock(pos.above(), adjacent.setValue(OPEN, open), 2|8|16);
if (adjacent.getBlock() == this) world.setBlock(pos.above(), adjacent.setValue(OPEN, open), 2 | 8 | 16);
}
world.playSound(null, pos, open?SoundEvents.IRON_DOOR_OPEN:SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
world.playSound(null, pos, open ? SoundEvents.IRON_DOOR_OPEN : SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
return InteractionResult.CONSUME;
}
@Override
@SuppressWarnings("deprecation")
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type)
{ return state.getValue(OPEN); }
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) {
return state.getValue(OPEN);
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving)
{
if(world.isClientSide) return;
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) {
if (world.isClientSide) return;
boolean powered = false;
BlockState adjacent;
BlockPos adjacent_pos;
if(state.getValue(SEGMENT) == SEGMENT_UPPER) {
if (state.getValue(SEGMENT) == SEGMENT_UPPER) {
adjacent_pos = pos.below();
adjacent = world.getBlockState(adjacent_pos);
if(adjacent.getBlock()!=this) adjacent = null;
if(world.getSignal(pos.above(), Direction.UP) > 0) {
if (adjacent.getBlock() != this) adjacent = null;
if (world.getSignal(pos.above(), Direction.UP) > 0) {
powered = true;
} else if((adjacent!=null) && (world.hasNeighborSignal(pos.below(2)))) {
} else if ((adjacent != null) && (world.hasNeighborSignal(pos.below(2)))) {
powered = true;
}
} else {
adjacent_pos = pos.above();
adjacent = world.getBlockState(adjacent_pos);
if(adjacent.getBlock()!=this) adjacent = null;
if(world.hasNeighborSignal(pos)) {
if (adjacent.getBlock() != this) adjacent = null;
if (world.hasNeighborSignal(pos)) {
powered = true;
} else if((adjacent!=null) && (world.getSignal(pos.above(2), Direction.UP) > 0)) {
} else if ((adjacent != null) && (world.getSignal(pos.above(2), Direction.UP) > 0)) {
powered = true;
}
}
boolean sound = false;
if(powered != state.getValue(OPEN)) {
world.setBlock(pos, state.setValue(OPEN, powered), 2|8|16);
if (powered != state.getValue(OPEN)) {
world.setBlock(pos, state.setValue(OPEN, powered), 2 | 8 | 16);
sound = true;
}
if((adjacent != null) && (powered != adjacent.getValue(OPEN))) {
world.setBlock(adjacent_pos, adjacent.setValue(OPEN, powered), 2|8|16);
if ((adjacent != null) && (powered != adjacent.getValue(OPEN))) {
world.setBlock(adjacent_pos, adjacent.setValue(OPEN, powered), 2 | 8 | 16);
sound = true;
}
if(sound) {
world.playSound(null, pos, powered?SoundEvents.IRON_DOOR_OPEN:SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
if (sound) {
world.playSound(null, pos, powered ? SoundEvents.IRON_DOOR_OPEN : SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
}
}
// -------------------------------------------------------------------------------------------------------------------
private BlockState getInitialState(BlockState state, LevelAccessor world, BlockPos pos)
{
private BlockState getInitialState(BlockState state, LevelAccessor world, BlockPos pos) {
final BlockState down = world.getBlockState(pos.below());
if(down.getBlock() == this) return state.setValue(SEGMENT, SEGMENT_UPPER).setValue(OPEN, down.getValue(OPEN)).setValue(HORIZONTAL_FACING, down.getValue(HORIZONTAL_FACING));
if (down.getBlock() == this)
return state.setValue(SEGMENT, SEGMENT_UPPER).setValue(OPEN, down.getValue(OPEN)).setValue(HORIZONTAL_FACING, down.getValue(HORIZONTAL_FACING));
final BlockState up = world.getBlockState(pos.above());
if(up.getBlock() == this) return state.setValue(SEGMENT, SEGMENT_LOWER).setValue(OPEN, up.getValue(OPEN)).setValue(HORIZONTAL_FACING, up.getValue(HORIZONTAL_FACING));
if (up.getBlock() == this)
return state.setValue(SEGMENT, SEGMENT_LOWER).setValue(OPEN, up.getValue(OPEN)).setValue(HORIZONTAL_FACING, up.getValue(HORIZONTAL_FACING));
return state.setValue(SEGMENT, SEGMENT_LOWER).setValue(OPEN, false);
}

View file

@ -8,23 +8,25 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.StandardFenceBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import dev.zontreck.engineerdecor.libmc.StandardFenceBlock;
public class EdFenceBlock extends StandardFenceBlock
{
public EdFenceBlock(long config, BlockBehaviour.Properties properties)
{ super(config, properties); }
public class EdFenceBlock extends StandardFenceBlock {
public EdFenceBlock(long config, BlockBehaviour.Properties properties) {
super(config, properties);
}
public EdFenceBlock(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(config, properties, pole_width, pole_height, side_width, side_min_y, side_max_low_y, side_max_tall_y); }
public EdFenceBlock(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(config, properties, pole_width, pole_height, side_width, side_min_y, side_max_low_y, side_max_tall_y);
}
@Override
protected boolean attachesTo(BlockState facingState, LevelReader world, BlockPos facingPos, Direction side)
{ return ((facingState.getBlock()) instanceof EdDoubleGateBlock) || super.attachesTo(facingState, world, facingPos, side); }
protected boolean attachesTo(BlockState facingState, LevelReader world, BlockPos facingPos, Direction side) {
return ((facingState.getBlock()) instanceof EdDoubleGateBlock) || super.attachesTo(facingState, world, facingPos, side);
}
}

View file

@ -8,6 +8,7 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
@ -19,54 +20,55 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import javax.annotation.Nullable;
public class EdFloorGratingBlock extends StandardBlocks.WaterLoggable
{
public EdFloorGratingBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public class EdFloorGratingBlock extends StandardBlocks.WaterLoggable {
public EdFloorGratingBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
public RenderTypeHint getRenderTypeHint() {
return RenderTypeHint.CUTOUT;
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos)
{ return true; }
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return true;
}
@Override
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType)
{ return false; }
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
return false;
}
@Override
@SuppressWarnings("deprecation")
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity)
{
if(!(entity instanceof ItemEntity)) return;
final boolean colliding = ((entity.position().y-pos.getY()) > 0.7);
if(colliding || (entity.getDeltaMovement().y() > 0)) {
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
if (!(entity instanceof ItemEntity)) return;
final boolean colliding = ((entity.position().y - pos.getY()) > 0.7);
if (colliding || (entity.getDeltaMovement().y() > 0)) {
double x = pos.getX() + 0.5;
double y = Mth.clamp(entity.position().y-0.3, pos.getY(), pos.getY()+0.6);
double y = Mth.clamp(entity.position().y - 0.3, pos.getY(), pos.getY() + 0.6);
double z = pos.getZ() + 0.5;
double vx = entity.getDeltaMovement().x();
double vy = entity.getDeltaMovement().y();
double vz = entity.getDeltaMovement().z();
if(colliding) {
if (colliding) {
vx = 0;
vy = -0.3;
vz = 0;
if((entity.position().y-pos.getY()) > 0.8) y = pos.getY() + 0.6;
entity.xo = x+0.1;
entity.yo = y+0.1;
entity.zo = z+0.1;
if ((entity.position().y - pos.getY()) > 0.8) y = pos.getY() + 0.6;
entity.xo = x + 0.1;
entity.yo = y + 0.1;
entity.zo = z + 0.1;
}
vy = Mth.clamp(vy, -0.3, 0);
entity.setDeltaMovement(vx, vy, vz);
entity.fallDistance = 0;
entity.teleportTo(x,y,z);
entity.teleportTo(x, y, z);
}
}

View file

@ -8,6 +8,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -29,7 +32,7 @@ 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.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -50,21 +53,13 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Fluidics;
import dev.zontreck.engineerdecor.libmc.Overlay;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class EdFluidBarrel
{
public class EdFluidBarrel {
//--------------------------------------------------------------------------------------------------------------------
// Config
//--------------------------------------------------------------------------------------------------------------------
@ -73,8 +68,7 @@ public class EdFluidBarrel
private static int item_fluid_handler_transfer_rate_ = 1000;
private static int tile_fluid_handler_transfer_rate_ = 1000;
public static void on_config(int tank_capacity, int transfer_rate)
{
public static void on_config(int tank_capacity, int transfer_rate) {
capacity_ = Mth.clamp(tank_capacity, 2000, 64000);
tile_fluid_handler_transfer_rate_ = Mth.clamp(tank_capacity, 50, 4096);
item_fluid_handler_transfer_rate_ = tile_fluid_handler_transfer_rate_;
@ -85,34 +79,33 @@ public class EdFluidBarrel
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class FluidBarrelBlock extends StandardBlocks.DirectedWaterLoggable implements StandardEntityBlocks.IStandardEntityBlock<FluidBarrelTileEntity>
{
public static class FluidBarrelBlock extends StandardBlocks.DirectedWaterLoggable implements StandardEntityBlocks.IStandardEntityBlock<FluidBarrelTileEntity> {
public static final int FILL_LEVEL_MAX = 4;
public static final IntegerProperty FILL_LEVEL = IntegerProperty.create("level", 0, FILL_LEVEL_MAX);
public FluidBarrelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB)
{
public FluidBarrelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
super(config, builder, unrotatedAABB);
registerDefaultState(super.defaultBlockState().setValue(FACING, Direction.UP).setValue(FILL_LEVEL, 0));
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion)
{
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks;
if(!(te instanceof FluidBarrelTileEntity)) return stacks;
if (world.isClientSide) return stacks;
if (!(te instanceof FluidBarrelTileEntity)) return stacks;
ItemStack stack = new ItemStack(this, 1);
CompoundTag te_nbt = ((FluidBarrelTileEntity) te).clear_getnbt();
if(!te_nbt.isEmpty()) {
if (!te_nbt.isEmpty()) {
CompoundTag nbt = new CompoundTag();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
@ -123,82 +116,84 @@ public class EdFluidBarrel
@Override
@OnlyIn(Dist.CLIENT)
public void appendHoverText(final ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag)
{
if((!(stack.getItem() instanceof FluidBarrelItem)) || (Auxiliaries.Tooltip.helpCondition())) {
super.appendHoverText(stack, world, tooltip, flag); return;
public void appendHoverText(final ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
if ((!(stack.getItem() instanceof FluidBarrelItem)) || (Auxiliaries.Tooltip.helpCondition())) {
super.appendHoverText(stack, world, tooltip, flag);
return;
}
FluidStack fs = FluidBarrelItem.getFluid(stack);
if(!fs.isEmpty()) {
tooltip.add(Auxiliaries.localizable(getDescriptionId()+".status.tip", Integer.toString(fs.getAmount()), Integer.toString(capacity_), Component.translatable(fs.getTranslationKey())));
if (!fs.isEmpty()) {
tooltip.add(Auxiliaries.localizable(getDescriptionId() + ".status.tip", Integer.toString(fs.getAmount()), Integer.toString(capacity_), Component.translatable(fs.getTranslationKey())));
} else {
tooltip.add(Auxiliaries.localizable(getDescriptionId()+".status.tip.empty", "0", Integer.toString(capacity_)));
tooltip.add(Auxiliaries.localizable(getDescriptionId() + ".status.tip.empty", "0", Integer.toString(capacity_)));
}
if(!Auxiliaries.Tooltip.extendedTipCondition()) {
if (!Auxiliaries.Tooltip.extendedTipCondition()) {
super.appendHoverText(stack, world, tooltip, flag);
}
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return Shapes.block(); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return Shapes.block();
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(FILL_LEVEL); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(FILL_LEVEL);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState state = super.getStateForPlacement(context);
if(!context.getPlayer().isShiftKeyDown()) state = state.setValue(FACING, Direction.UP);
if (!context.getPlayer().isShiftKeyDown()) state = state.setValue(FACING, Direction.UP);
return state;
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isClientSide) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
if (world.isClientSide) return;
if ((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundTag te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
if (te_nbt.isEmpty()) return;
final BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof FluidBarrelTileEntity)) return;
((FluidBarrelTileEntity)te).readnbt(te_nbt);
if (!(te instanceof FluidBarrelTileEntity)) return;
((FluidBarrelTileEntity) te).readnbt(te_nbt);
te.setChanged();
world.scheduleTick(pos, this, 4);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{
if(player.getItemInHand(hand).getItem() == asItem()) return InteractionResult.PASS; // Pass that to block placement.
if(world.isClientSide()) return InteractionResult.SUCCESS;
if(!(world.getBlockEntity(pos) instanceof final FluidBarrelTileEntity te)) return InteractionResult.FAIL;
if(!te.handlePlayerInteraction(state, world, pos, player, hand)) return InteractionResult.PASS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
if (player.getItemInHand(hand).getItem() == asItem())
return InteractionResult.PASS; // Pass that to block placement.
if (world.isClientSide()) return InteractionResult.SUCCESS;
if (!(world.getBlockEntity(pos) instanceof final FluidBarrelTileEntity te)) return InteractionResult.FAIL;
if (!te.handlePlayerInteraction(state, world, pos, player, hand)) return InteractionResult.PASS;
world.scheduleTick(pos, this, 4);
return InteractionResult.CONSUME;
}
@Override
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos)
{
BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof FluidBarrelTileEntity)) return 0;
return (int)Mth.clamp(((FluidBarrelTileEntity)te).getNormalizedFillLevel() * 15, 0, 15);
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
BlockEntity te = world.getBlockEntity(pos);
if (!(te instanceof FluidBarrelTileEntity)) return 0;
return (int) Mth.clamp(((FluidBarrelTileEntity) te).getNormalizedFillLevel() * 15, 0, 15);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
}
@ -206,34 +201,36 @@ public class EdFluidBarrel
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class FluidBarrelTileEntity extends StandardEntityBlocks.StandardBlockEntity implements ICapabilityProvider
{
public static class FluidBarrelTileEntity extends StandardEntityBlocks.StandardBlockEntity implements ICapabilityProvider {
private final int TICK_INTERVAL = 10;
private int tick_timer_ = 0;
private final Fluidics.Tank tank_ = (new Fluidics.Tank(capacity_)).setInteractionNotifier((t,d)->on_tank_changed());
private final Fluidics.Tank tank_ = (new Fluidics.Tank(capacity_)).setInteractionNotifier((t, d) -> on_tank_changed());
private final LazyOptional<IFluidHandler> fluid_handler_ = tank_.createFluidHandler();
public FluidBarrelTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); }
public FluidBarrelTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
public void readnbt(CompoundTag nbt)
{ tank_.load(nbt); }
public void readnbt(CompoundTag nbt) {
tank_.load(nbt);
}
public CompoundTag writenbt(CompoundTag nbt)
{ tank_.save(nbt); return nbt; }
public CompoundTag writenbt(CompoundTag nbt) {
tank_.save(nbt);
return nbt;
}
public boolean handlePlayerInteraction(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand)
public boolean handlePlayerInteraction(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand) {
if (world.isClientSide()) return false;
{
if(world.isClientSide()) return false;
{
Tuple<Fluid,Integer> transferred = Fluidics.manualTrackedFluidHandlerInteraction(world, pos, null, player, hand);
if(transferred==null) {
Tuple<Fluid, Integer> transferred = Fluidics.manualTrackedFluidHandlerInteraction(world, pos, null, player, hand);
if (transferred == null) {
world.playSound(null, pos, SoundEvents.IRON_TRAPDOOR_OPEN, SoundSource.BLOCKS, 0.2f, 0.02f);
} else if(transferred.getB() > 0) {
SoundEvent se = (transferred.getA()==Fluids.LAVA) ? SoundEvents.BUCKET_EMPTY_LAVA: SoundEvents.BUCKET_EMPTY;
} else if (transferred.getB() > 0) {
SoundEvent se = (transferred.getA() == Fluids.LAVA) ? SoundEvents.BUCKET_EMPTY_LAVA : SoundEvents.BUCKET_EMPTY;
world.playSound(null, pos, se, SoundSource.BLOCKS, 1f, 1f);
} else {
SoundEvent se = (transferred.getA()==Fluids.LAVA) ? SoundEvents.BUCKET_FILL_LAVA : SoundEvents.BUCKET_FILL;
SoundEvent se = (transferred.getA() == Fluids.LAVA) ? SoundEvents.BUCKET_FILL_LAVA : SoundEvents.BUCKET_FILL;
world.playSound(null, pos, se, SoundSource.BLOCKS, 1f, 1f);
}
}
@ -241,7 +238,7 @@ public class EdFluidBarrel
int vol = tank_.getFluidAmount();
int cap = tank_.getCapacity();
String name = (Component.translatable(tank_.getFluid().getTranslationKey())).getString();
if((vol>0) && (cap>0)) {
if ((vol > 0) && (cap > 0)) {
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.fluid_barrel.status", Integer.toString(vol), Integer.toString(cap), name));
} else {
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.fluid_barrel.status.empty", Integer.toString(vol), Integer.toString(cap)));
@ -250,64 +247,71 @@ public class EdFluidBarrel
return true;
}
public double getNormalizedFillLevel()
{ return (tank_.isEmpty()) ? (0) : ((double)tank_.getFluidAmount()/(double)tank_.getCapacity()); }
public double getNormalizedFillLevel() {
return (tank_.isEmpty()) ? (0) : ((double) tank_.getFluidAmount() / (double) tank_.getCapacity());
}
protected void on_tank_changed()
{ if(tick_timer_ > 2) tick_timer_ = 2; }
protected void on_tank_changed() {
if (tick_timer_ > 2) tick_timer_ = 2;
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt); }
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt);
}
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt); }
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt);
}
@Override
public void setRemoved()
{ super.setRemoved(); fluid_handler_.invalidate(); }
public void setRemoved() {
super.setRemoved();
fluid_handler_.invalidate();
}
public CompoundTag clear_getnbt()
{ return tank_.save(new CompoundTag()); }
public CompoundTag clear_getnbt() {
return tank_.save(new CompoundTag());
}
// ICapabilityProvider --------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
return super.getCapability(capability, facing);
}
// Tick --------------------------------------------------------------------
private boolean transfer_down()
{
if(tank_.isEmpty()) return false;
private boolean transfer_down() {
if (tank_.isEmpty()) return false;
final IFluidHandler fh = Fluidics.handler(level, worldPosition.below(), Direction.UP);
if(fh==null) return false;
if (fh == null) return false;
final FluidStack fs = tank_.getFluid().copy();
if(fs.getAmount() > tile_fluid_handler_transfer_rate_) fs.setAmount(tile_fluid_handler_transfer_rate_);
if (fs.getAmount() > tile_fluid_handler_transfer_rate_) fs.setAmount(tile_fluid_handler_transfer_rate_);
final int nfilled = fh.fill(fs, IFluidHandler.FluidAction.EXECUTE);
if(nfilled <= 0) return false;
if (nfilled <= 0) return false;
tank_.drain(nfilled, IFluidHandler.FluidAction.EXECUTE);
return true;
}
public void tick()
{
if((level.isClientSide()) || (--tick_timer_>=0)) return;
public void tick() {
if ((level.isClientSide()) || (--tick_timer_ >= 0)) return;
tick_timer_ = TICK_INTERVAL;
final BlockState state = getBlockState();
final Block block = state.getBlock();
if(!(block instanceof FluidBarrelBlock)) return;
if(state.getValue(FluidBarrelBlock.FACING).getAxis().isVertical()) transfer_down(); // tick_timer_ ==> 1 if something was transferred, otherwise no need to waste CPU
if (!(block instanceof FluidBarrelBlock)) return;
if (state.getValue(FluidBarrelBlock.FACING).getAxis().isVertical())
transfer_down(); // tick_timer_ ==> 1 if something was transferred, otherwise no need to waste CPU
double norm_level = getNormalizedFillLevel();
int fill_level = (norm_level <= 0) ? 0 : ((int)Mth.clamp((norm_level * FluidBarrelBlock.FILL_LEVEL_MAX)+0.5, 1, FluidBarrelBlock.FILL_LEVEL_MAX));
if(fill_level != state.getValue(FluidBarrelBlock.FILL_LEVEL)) {
int fill_level = (norm_level <= 0) ? 0 : ((int) Mth.clamp((norm_level * FluidBarrelBlock.FILL_LEVEL_MAX) + 0.5, 1, FluidBarrelBlock.FILL_LEVEL_MAX));
if (fill_level != state.getValue(FluidBarrelBlock.FILL_LEVEL)) {
level.setBlock(worldPosition, state.setValue(FluidBarrelBlock.FILL_LEVEL, fill_level), 2);
level.updateNeighborsAt(worldPosition, block);
}
@ -319,78 +323,83 @@ public class EdFluidBarrel
// Block item
//--------------------------------------------------------------------------------------------------------------------
public static class FluidBarrelItem extends BlockItem
{
public FluidBarrelItem(Block block, Item.Properties builder)
{ super(block, builder); }
public static class FluidBarrelItem extends BlockItem {
public FluidBarrelItem(Block block, Item.Properties builder) {
super(block, builder);
}
private static CompoundTag read_fluid_nbt(ItemStack stack)
{
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return new CompoundTag();
private static CompoundTag read_fluid_nbt(ItemStack stack) {
if ((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return new CompoundTag();
final CompoundTag nbt = stack.getTag().getCompound("tedata");
if(!nbt.contains("tank", Tag.TAG_COMPOUND)) return new CompoundTag();
if (!nbt.contains("tank", Tag.TAG_COMPOUND)) return new CompoundTag();
return nbt.getCompound("tank");
}
private static void write_fluid_nbt(ItemStack stack, CompoundTag fluid_nbt)
{
if((fluid_nbt==null) || (fluid_nbt.isEmpty())) {
if((!stack.hasTag()) || (!stack.getTag().contains("tedata", Tag.TAG_COMPOUND))) return;
private static void write_fluid_nbt(ItemStack stack, CompoundTag fluid_nbt) {
if ((fluid_nbt == null) || (fluid_nbt.isEmpty())) {
if ((!stack.hasTag()) || (!stack.getTag().contains("tedata", Tag.TAG_COMPOUND))) return;
final CompoundTag tag = stack.getTag();
final CompoundTag tedata = tag.getCompound("tedata");
if(tedata.contains("tank")) tedata.remove("tank");
if(tedata.isEmpty()) tag.remove("tedata");
if (tedata.contains("tank")) tedata.remove("tank");
if (tedata.isEmpty()) tag.remove("tedata");
stack.setTag(tag.isEmpty() ? null : tag);
} else {
CompoundTag tag = stack.getTag();
if(tag==null) tag = new CompoundTag();
if (tag == null) tag = new CompoundTag();
CompoundTag tedata = tag.getCompound("tedata");
if(tedata==null) tedata = new CompoundTag();
if (tedata == null) tedata = new CompoundTag();
tedata.put("tank", fluid_nbt);
tag.put("tedata", tedata);
stack.setTag(tag);
}
}
public static FluidStack getFluid(ItemStack stack)
{
public static FluidStack getFluid(ItemStack stack) {
final CompoundTag nbt = read_fluid_nbt(stack);
return (nbt.isEmpty()) ? (FluidStack.EMPTY) : (FluidStack.loadFluidStackFromNBT(nbt));
}
public static ItemStack setFluid(ItemStack stack, FluidStack fs)
{ write_fluid_nbt(stack, fs.writeToNBT(new CompoundTag())); return stack; }
public static ItemStack setFluid(ItemStack stack, FluidStack fs) {
write_fluid_nbt(stack, fs.writeToNBT(new CompoundTag()));
return stack;
}
@Override
public int getMaxStackSize(ItemStack stack)
{ return (!getFluid(stack).isEmpty()) ? 1 : super.getMaxStackSize(stack); }
public int getMaxStackSize(ItemStack stack) {
return (!getFluid(stack).isEmpty()) ? 1 : super.getMaxStackSize(stack);
}
@Override
public boolean isBarVisible(ItemStack stack)
{ return (!getFluid(stack).isEmpty()); }
public boolean isBarVisible(ItemStack stack) {
return (!getFluid(stack).isEmpty());
}
@Override
public int getBarWidth(ItemStack stack)
{ return (int)Math.round(13f * Mth.clamp(((double)(getFluid(stack).getAmount()))/((double)capacity_), 0.0, 1.0)); }
public int getBarWidth(ItemStack stack) {
return (int) Math.round(13f * Mth.clamp(((double) (getFluid(stack).getAmount())) / ((double) capacity_), 0.0, 1.0));
}
@Override
public int getBarColor(ItemStack stack)
{ return 0x336633; }
public int getBarColor(ItemStack stack) {
return 0x336633;
}
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt)
{ return new Fluidics.FluidContainerItemCapabilityWrapper(stack, capacity_, item_fluid_handler_transfer_rate_, FluidBarrelItem::read_fluid_nbt, FluidBarrelItem::write_fluid_nbt, e->true); }
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) {
return new Fluidics.FluidContainerItemCapabilityWrapper(stack, capacity_, item_fluid_handler_transfer_rate_, FluidBarrelItem::read_fluid_nbt, FluidBarrelItem::write_fluid_nbt, e -> true);
}
@Override
public boolean hasCraftingRemainingItem(ItemStack stack)
{ return (stack.getCount()==1) && (!getFluid(stack).isEmpty()); }
public boolean hasCraftingRemainingItem(ItemStack stack) {
return (stack.getCount() == 1) && (!getFluid(stack).isEmpty());
}
@Override
public ItemStack getCraftingRemainingItem(ItemStack stack)
{
if(stack.getCount()!=1) return ItemStack.EMPTY;
public ItemStack getCraftingRemainingItem(ItemStack stack) {
if (stack.getCount() != 1) return ItemStack.EMPTY;
FluidStack fs = getFluid(stack);
if(fs.getAmount() > 1000) fs.shrink(1000); else fs = FluidStack.EMPTY;
if (fs.getAmount() > 1000) fs.shrink(1000);
else fs = FluidStack.EMPTY;
return setFluid(stack, fs);
}
}

View file

@ -10,6 +10,11 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.Fluidics;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import dev.zontreck.libzontreck.edlibmc.StandardEntityBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
@ -23,7 +28,7 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -43,23 +48,16 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Fluidics;
import javax.annotation.Nullable;
import java.util.*;
public class EdFluidFunnel
{
public class EdFluidFunnel {
private static boolean with_device_fluid_handler_collection = false;
public static void on_config(boolean with_tank_fluid_collection)
{
public static void on_config(boolean with_tank_fluid_collection) {
with_device_fluid_handler_collection = with_tank_fluid_collection;
ModConfig.log("Config fluid funnel: tank-fluid-collection:" + with_device_fluid_handler_collection + ".");
}
@ -68,74 +66,81 @@ public class EdFluidFunnel
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class FluidFunnelBlock extends StandardBlocks.Cutout implements StandardEntityBlocks.IStandardEntityBlock<FluidFunnelTileEntity>
{
public static class FluidFunnelBlock extends StandardBlocks.Cutout implements StandardEntityBlocks.IStandardEntityBlock<FluidFunnelTileEntity> {
public static final int FILL_LEVEL_MAX = 3;
public static final IntegerProperty FILL_LEVEL = IntegerProperty.create("level", 0, FILL_LEVEL_MAX);
public FluidFunnelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public FluidFunnelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
public RenderTypeHint getRenderTypeHint() {
return RenderTypeHint.CUTOUT;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return Shapes.block(); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return Shapes.block();
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(FILL_LEVEL); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(FILL_LEVEL);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(FILL_LEVEL, 0); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(FILL_LEVEL, 0);
}
@Override
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state)
{ return true; }
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos)
{ return Mth.clamp((state.getValue(FILL_LEVEL)*5), 0, 15); }
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
return Mth.clamp((state.getValue(FILL_LEVEL) * 5), 0, 15);
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isClientSide) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
if (world.isClientSide) return;
if ((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundTag te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
if (te_nbt.isEmpty()) return;
final BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof FluidFunnelTileEntity)) return;
((FluidFunnelTileEntity)te).readnbt(te_nbt);
if (!(te instanceof FluidFunnelTileEntity)) return;
((FluidFunnelTileEntity) te).readnbt(te_nbt);
te.setChanged();
world.setBlockAndUpdate(pos, state.setValue(FILL_LEVEL, 0));
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion)
{
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks;
if(!(te instanceof FluidFunnelTileEntity)) return stacks;
if(!explosion) {
if (world.isClientSide) return stacks;
if (!(te instanceof FluidFunnelTileEntity)) return stacks;
if (!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundTag te_nbt = new CompoundTag();
((FluidFunnelTileEntity)te).writenbt(te_nbt);
if(!te_nbt.isEmpty()) {
((FluidFunnelTileEntity) te).writenbt(te_nbt);
if (!te_nbt.isEmpty()) {
CompoundTag nbt = new CompoundTag();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
@ -149,36 +154,40 @@ public class EdFluidFunnel
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{
if(world.isClientSide) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
if (world.isClientSide) return InteractionResult.SUCCESS;
return (world.getBlockEntity(pos) instanceof FluidFunnelTileEntity) && Fluidics.manualFluidHandlerInteraction(player, hand, world, pos, rayTraceResult.getDirection()) ? InteractionResult.CONSUME : InteractionResult.FAIL;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{ BlockEntity te = world.getBlockEntity(pos); if(te instanceof FluidFunnelTileEntity) ((FluidFunnelTileEntity)te).block_changed(); }
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) {
BlockEntity te = world.getBlockEntity(pos);
if (te instanceof FluidFunnelTileEntity) ((FluidFunnelTileEntity) te).block_changed();
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class FluidFunnelTileEntity extends StandardEntityBlocks.StandardBlockEntity
{
public static class FluidFunnelTileEntity extends StandardEntityBlocks.StandardBlockEntity {
public static final int TANK_CAPACITY = 3000;
public static final int TICK_INTERVAL = 10; // ca 500ms
public static final int COLLECTION_INTERVAL = 40; // ca 2000ms, simulates suction delay and saves CPU when not drained.
public static final int MAX_TRACK_RADIUS = 16;
public static final int MAX_TRACKING_STEPS_PER_CYCLE = 72;
public static final int MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE = 1024;
public static final int MAX_TRACK_RADIUS_SQ = MAX_TRACK_RADIUS*MAX_TRACK_RADIUS;
public static final int MAX_TRACK_RADIUS_SQ = MAX_TRACK_RADIUS * MAX_TRACK_RADIUS;
public static final int INTENSIVE_SEARCH_TRIGGER_THRESHOLD = 16;
private final Fluidics.Tank tank_ = new Fluidics.Tank(TANK_CAPACITY, 0, TANK_CAPACITY);
private final LazyOptional<IFluidHandler> fluid_handler_ = tank_.createOutputFluidHandler();
private int tick_timer_ = 0;
private int collection_timer_ = 0;
private int no_fluid_found_counter_ = 0;
@ -186,38 +195,39 @@ public class EdFluidFunnel
private int total_pick_counter_ = 0;
private BlockPos last_pick_pos_ = BlockPos.ZERO;
private ArrayList<Vec3i> search_offsets_ = null;
private final Fluidics.Tank tank_ = new Fluidics.Tank(TANK_CAPACITY, 0, TANK_CAPACITY);
private final LazyOptional<IFluidHandler> fluid_handler_ = tank_.createOutputFluidHandler();
public FluidFunnelTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); }
public FluidFunnelTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
public void readnbt(CompoundTag nbt)
{
public void readnbt(CompoundTag nbt) {
tank_.load(nbt);
}
public void writenbt(CompoundTag nbt)
{
public void writenbt(CompoundTag nbt) {
tank_.save(nbt);
}
public void block_changed()
{ tick_timer_ = TICK_INTERVAL; }
public void block_changed() {
tick_timer_ = TICK_INTERVAL;
}
// BlockEntity -----------------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt); }
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt);
}
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt); }
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt);
}
@Override
public void setRemoved()
{
public void setRemoved() {
super.setRemoved();
fluid_handler_.invalidate();
}
@ -225,39 +235,37 @@ public class EdFluidFunnel
// ICapabilityProvider / Output flow handler ----------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
return super.getCapability(capability, facing);
}
// -----------------------------------------------------------------------------------------------------------------
private FluidState get_fluidstate(BlockPos pos)
{
private FluidState get_fluidstate(BlockPos pos) {
return level.getFluidState(pos);
}
private boolean try_pick(BlockPos pos, FluidState fluidstate)
{
if(!fluidstate.isSource()) return false;
private boolean try_pick(BlockPos pos, FluidState fluidstate) {
if (!fluidstate.isSource()) return false;
IFluidHandler hnd = Fluidics.handler(level, pos, null);
FluidStack fs;
if(hnd != null) {
if (hnd != null) {
fs = hnd.drain(TANK_CAPACITY, IFluidHandler.FluidAction.EXECUTE); // IFluidBlock
} else {
fs = new FluidStack(fluidstate.getType(), 1000);
BlockState state = level.getBlockState(pos);
if(state.hasProperty(BlockStateProperties.WATERLOGGED)) {
level.setBlock(pos, state.setValue(BlockStateProperties.WATERLOGGED, false), 1|2);
if (state.hasProperty(BlockStateProperties.WATERLOGGED)) {
level.setBlock(pos, state.setValue(BlockStateProperties.WATERLOGGED, false), 1 | 2);
} else {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), 1|2); // ok we can't leave the block, that would be an infinite source of an unknown fluid.
level.setBlock(pos, Blocks.AIR.defaultBlockState(), 1 | 2); // ok we can't leave the block, that would be an infinite source of an unknown fluid.
}
}
if((fs==null) || (fs.isEmpty())) return false; // it's marked nonnull but I don't trust every modder - including meself ...
if(tank_.isEmpty()) {
if ((fs == null) || (fs.isEmpty()))
return false; // it's marked nonnull but I don't trust every modder - including meself ...
if (tank_.isEmpty()) {
tank_.setFluid(fs.copy());
} else if(tank_.isFluidEqual(fs)) {
} else if (tank_.isFluidEqual(fs)) {
tank_.fill(fs, IFluidHandler.FluidAction.EXECUTE);
} else {
return false;
@ -265,132 +273,138 @@ public class EdFluidFunnel
return true;
}
private boolean can_pick(BlockPos pos, FluidState fluidstate)
{
if(fluidstate.isSource()) return true;
private boolean can_pick(BlockPos pos, FluidState fluidstate) {
if (fluidstate.isSource()) return true;
final IFluidHandler hnd = Fluidics.handler(level, pos, null);
if(hnd == null) return false;
if (hnd == null) return false;
final FluidStack fs = hnd.drain(TANK_CAPACITY, IFluidHandler.FluidAction.SIMULATE); // don't trust that everyone returns nonnull
return ((fs!=null) && (!fs.isEmpty())) && (fluidstate.getType().isSame(fs.getFluid()));
return ((fs != null) && (!fs.isEmpty())) && (fluidstate.getType().isSame(fs.getFluid()));
}
private void rebuild_search_offsets(boolean intensive)
{
private void rebuild_search_offsets(boolean intensive) {
search_offsets_ = new ArrayList<>(9);
search_offsets_.add(new Vec3i(0, 1, 0)); // up first
{
ArrayList<Vec3i> ofs = new ArrayList<>(Arrays.asList(new Vec3i(-1, 0, 0), new Vec3i( 1, 0, 0), new Vec3i( 0, 0,-1), new Vec3i( 0, 0, 1)));
if(intensive || (total_pick_counter_ > 50)) Collections.shuffle(ofs);
ArrayList<Vec3i> ofs = new ArrayList<>(Arrays.asList(new Vec3i(-1, 0, 0), new Vec3i(1, 0, 0), new Vec3i(0, 0, -1), new Vec3i(0, 0, 1)));
if (intensive || (total_pick_counter_ > 50)) Collections.shuffle(ofs);
search_offsets_.addAll(ofs);
}
if(intensive) {
ArrayList<Vec3i> ofs = new ArrayList<>(Arrays.asList(new Vec3i(-1, 1, 0), new Vec3i( 1, 1, 0), new Vec3i( 0, 1,-1), new Vec3i( 0, 1, 1)));
if (intensive) {
ArrayList<Vec3i> ofs = new ArrayList<>(Arrays.asList(new Vec3i(-1, 1, 0), new Vec3i(1, 1, 0), new Vec3i(0, 1, -1), new Vec3i(0, 1, 1)));
Collections.shuffle(ofs);
search_offsets_.addAll(ofs);
}
}
private boolean try_collect(final BlockPos collection_pos)
{
private boolean try_collect(final BlockPos collection_pos) {
FluidState collection_fluidstate = get_fluidstate(collection_pos);
if(collection_fluidstate.isEmpty()) return false;
if (collection_fluidstate.isEmpty()) return false;
Fluid fluid_to_collect = collection_fluidstate.getType();
if((!tank_.isEmpty()) && (!tank_.getFluid().getFluid().isSame(fluid_to_collect))) return false;
if(try_pick(collection_pos, collection_fluidstate)) { last_pick_pos_ = collection_pos; return true; } // Blocks directly always first. Allows water source blocks to recover/reflow to source blocks.
if((last_pick_pos_==null) || (last_pick_pos_.distSqr(collection_pos) > MAX_TRACK_RADIUS_SQ)) { last_pick_pos_ = collection_pos; search_offsets_ = null; }
if ((!tank_.isEmpty()) && (!tank_.getFluid().getFluid().isSame(fluid_to_collect))) return false;
if (try_pick(collection_pos, collection_fluidstate)) {
last_pick_pos_ = collection_pos;
return true;
} // Blocks directly always first. Allows water source blocks to recover/reflow to source blocks.
if ((last_pick_pos_ == null) || (last_pick_pos_.distSqr(collection_pos) > MAX_TRACK_RADIUS_SQ)) {
last_pick_pos_ = collection_pos;
search_offsets_ = null;
}
BlockPos pos = last_pick_pos_;
HashSet<BlockPos> checked = new HashSet<>();
Stack<BlockPos> trail = new Stack<>();
trail.add(pos);
checked.add(pos);
int steps=0;
int steps = 0;
boolean intensive = (no_fluid_found_counter_ >= INTENSIVE_SEARCH_TRIGGER_THRESHOLD);
if(intensive) { no_fluid_found_counter_ = 0; ++intensive_search_counter_; }
if(search_offsets_ == null) rebuild_search_offsets(intensive);
if (intensive) {
no_fluid_found_counter_ = 0;
++intensive_search_counter_;
}
if (search_offsets_ == null) rebuild_search_offsets(intensive);
int max = intensive ? MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE : MAX_TRACKING_STEPS_PER_CYCLE;
while(++steps <= max) {
while (++steps <= max) {
int num_adjacent = 0;
for(int i=0; i<search_offsets_.size(); ++i) {
for (int i = 0; i < search_offsets_.size(); ++i) {
BlockPos p = pos.offset(search_offsets_.get(i));
if(checked.contains(p)) continue;
if (checked.contains(p)) continue;
checked.add(p);
++steps;
FluidState fluidstate = get_fluidstate(p);
if(fluidstate.getType().isSame(fluid_to_collect)) {
if (fluidstate.getType().isSame(fluid_to_collect)) {
++num_adjacent;
pos = p;
trail.push(pos);
if(steps < MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2) {
if (steps < MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE / 2) {
// check for same fluid above (only source blocks)
final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2)-steps;
for(int k=0; k<max_surface_search; ++k) {
final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE / 2) - steps;
for (int k = 0; k < max_surface_search; ++k) {
FluidState fs = get_fluidstate(pos.above());
if(!can_pick(pos.above(), fs)) break;
if (!can_pick(pos.above(), fs)) break;
fluidstate = fs;
pos = pos.above();
trail.push(pos);
}
}
if(try_pick(pos, fluidstate)) {
if (try_pick(pos, fluidstate)) {
last_pick_pos_ = pos;
no_fluid_found_counter_ = 0;
search_offsets_ = null;
// probability reset, so it's not turteling too far away, mainly for large nether lava seas, not desert lakes.
if((++total_pick_counter_ > 50) && level.random.nextInt(10)==0) last_pick_pos_ = collection_pos;
if ((++total_pick_counter_ > 50) && level.random.nextInt(10) == 0)
last_pick_pos_ = collection_pos;
//println("PASS " + steps + " - " + (pos.subtract(collection_pos)));
return true;
}
}
}
if(trail.isEmpty()) break; // reset search
if(num_adjacent==0) pos = trail.pop();
if (trail.isEmpty()) break; // reset search
if (num_adjacent == 0) pos = trail.pop();
}
//println("FAIL=" + steps + " - " + (pos.subtract(collection_pos)));
//String s = new String(); for(BlockPos p:checked) s += "\n" + p; println(s);
if(intensive_search_counter_ > 2) level.removeBlock(pos, false);
if (intensive_search_counter_ > 2) level.removeBlock(pos, false);
last_pick_pos_ = collection_pos;
search_offsets_ = null; // try other search order
++no_fluid_found_counter_;
return false;
}
public void tick()
{
if((level.isClientSide) || (--tick_timer_ > 0)) return;
public void tick() {
if ((level.isClientSide) || (--tick_timer_ > 0)) return;
tick_timer_ = TICK_INTERVAL;
collection_timer_ += TICK_INTERVAL;
final BlockState funnel_state = level.getBlockState(worldPosition);
if(!(funnel_state.getBlock() instanceof FluidFunnelBlock)) return;
if (!(funnel_state.getBlock() instanceof FluidFunnelBlock)) return;
boolean dirty = false;
// Collection
if((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_==null) || (tank_.getFluidAmount() <= (TANK_CAPACITY-1000)))) {
if ((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_ == null) || (tank_.getFluidAmount() <= (TANK_CAPACITY - 1000)))) {
collection_timer_ = 0;
if(!level.hasNeighborSignal(worldPosition)) { // redstone disable feature
if(last_pick_pos_==null) last_pick_pos_ = worldPosition.above();
if (!level.hasNeighborSignal(worldPosition)) { // redstone disable feature
if (last_pick_pos_ == null) last_pick_pos_ = worldPosition.above();
BlockEntity te = with_device_fluid_handler_collection ? (level.getBlockEntity(worldPosition.above())) : (null);
if(te != null) {
if (te != null) {
IFluidHandler fh = te.getCapability(ForgeCapabilities.FLUID_HANDLER, Direction.DOWN).orElse(null);
if(fh == null) {
if (fh == null) {
te = null;
} else if(tank_.isEmpty()) {
} else if (tank_.isEmpty()) {
FluidStack fs = fh.drain(1000, IFluidHandler.FluidAction.EXECUTE);
if((fs!=null) && (!fs.isEmpty())) tank_.setFluid(fs.copy());
if ((fs != null) && (!fs.isEmpty())) tank_.setFluid(fs.copy());
dirty = true;
} else if (!tank_.isFull()) {
FluidStack todrain = new FluidStack(tank_.getFluid(), Math.min(tank_.getCapacity()-tank_.getFluidAmount(), 1000));
FluidStack todrain = new FluidStack(tank_.getFluid(), Math.min(tank_.getCapacity() - tank_.getFluidAmount(), 1000));
tank_.fill(fh.drain(todrain, IFluidHandler.FluidAction.EXECUTE), IFluidHandler.FluidAction.EXECUTE);
dirty = true;
}
}
if(te==null) {
if(try_collect(worldPosition.above())) dirty = true;
if (te == null) {
if (try_collect(worldPosition.above())) dirty = true;
}
}
}
// Gravity fluid transfer
if((tank_.getFluidAmount() >= 1000)) {
if ((tank_.getFluidAmount() >= 1000)) {
final IFluidHandler fh = Fluidics.handler(level, worldPosition.below(), Direction.UP);
if(fh != null) {
if (fh != null) {
FluidStack fs = new FluidStack(tank_.getFluid().getFluid(), 1000);
int nfilled = Mth.clamp(fh.fill(fs, IFluidHandler.FluidAction.EXECUTE), 0, 1000);
tank_.drain(nfilled);
@ -398,9 +412,10 @@ public class EdFluidFunnel
}
}
// Block state
int fill_level = (tank_==null) ? 0 : (Mth.clamp(tank_.getFluidAmount()/1000,0, FluidFunnelBlock.FILL_LEVEL_MAX));
if(funnel_state.getValue(FluidFunnelBlock.FILL_LEVEL) != fill_level) level.setBlock(worldPosition, funnel_state.setValue(FluidFunnelBlock.FILL_LEVEL, fill_level), 2|16);
if(dirty) setChanged();
int fill_level = (tank_ == null) ? 0 : (Mth.clamp(tank_.getFluidAmount() / 1000, 0, FluidFunnelBlock.FILL_LEVEL_MAX));
if (funnel_state.getValue(FluidFunnelBlock.FILL_LEVEL) != fill_level)
level.setBlock(worldPosition, funnel_state.setValue(FluidFunnelBlock.FILL_LEVEL, fill_level), 2 | 16);
if (dirty) setChanged();
}
}
}

View file

@ -9,6 +9,11 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.Fluidics;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import dev.zontreck.libzontreck.edlibmc.StandardEntityBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -25,7 +30,7 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -45,99 +50,100 @@ import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Fluidics;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class EdFreezer
{
public static void on_config(int consumption, int cooldown_per_second)
{ FreezerTileEntity.on_config(consumption, cooldown_per_second); }
public class EdFreezer {
public static void on_config(int consumption, int cooldown_per_second) {
FreezerTileEntity.on_config(consumption, cooldown_per_second);
}
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class FreezerBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<FreezerTileEntity>
{
public static class FreezerBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<FreezerTileEntity> {
public static final int PHASE_MAX = 4;
public static final IntegerProperty PHASE = IntegerProperty.create("phase", 0, PHASE_MAX);
public FreezerBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public FreezerBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return Shapes.block(); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return Shapes.block();
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(PHASE); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(PHASE);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(PHASE, 0); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(PHASE, 0);
}
@Override
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state)
{ return true; }
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos)
{ return Mth.clamp((state.getValue(PHASE)*4), 0, 15); }
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
return Mth.clamp((state.getValue(PHASE) * 4), 0, 15);
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{}
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion)
{
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks;
if(!(te instanceof FreezerTileEntity)) return stacks;
((FreezerTileEntity)te).reset_process();
if (world.isClientSide) return stacks;
if (!(te instanceof FreezerTileEntity)) return stacks;
((FreezerTileEntity) te).reset_process();
stacks.add(new ItemStack(this, 1));
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{
if(player.isShiftKeyDown()) return InteractionResult.PASS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
if (player.isShiftKeyDown()) return InteractionResult.PASS;
if (world.isClientSide()) return InteractionResult.SUCCESS;
FreezerTileEntity te = getTe(world, pos);
if(te==null) return InteractionResult.FAIL;
if (te == null) return InteractionResult.FAIL;
final ItemStack stack = player.getItemInHand(hand);
boolean dirty = false;
if(Fluidics.manualFluidHandlerInteraction(world, pos, null, player, hand)) {
if (Fluidics.manualFluidHandlerInteraction(world, pos, null, player, hand)) {
world.playSound(null, pos, SoundEvents.BUCKET_EMPTY, SoundSource.BLOCKS, 0.5f, 1.4f);
return InteractionResult.CONSUME;
}
if(stack.getItem()==Items.WATER_BUCKET) {
if (stack.getItem() == Items.WATER_BUCKET) {
return InteractionResult.CONSUME; // would be already handled
} else if(stack.isEmpty()) {
} else if (stack.isEmpty()) {
ItemStack ice = te.getIceItem(true);
if(!ice.isEmpty()) {
if (!ice.isEmpty()) {
player.addItem(ice);
world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 0.3f, 1.1f);
} else {
@ -150,25 +156,27 @@ public class EdFreezer
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd)
{}
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd) {
}
@Nullable
private FreezerTileEntity getTe(Level world, BlockPos pos)
{ final BlockEntity te=world.getBlockEntity(pos); return (!(te instanceof FreezerTileEntity)) ? (null) : ((FreezerTileEntity)te); }
private FreezerTileEntity getTe(Level world, BlockPos pos) {
final BlockEntity te = world.getBlockEntity(pos);
return (!(te instanceof FreezerTileEntity)) ? (null) : ((FreezerTileEntity) te);
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class FreezerTileEntity extends StandardEntityBlocks.StandardBlockEntity implements IEnergyStorage
{
public static class FreezerTileEntity extends StandardEntityBlocks.StandardBlockEntity implements IEnergyStorage {
public static final int TICK_INTERVAL = 20;
public static final int MAX_FLUID_LEVEL = 2000;
public static final int MAX_ENERGY_BUFFER = 32000;
@ -185,217 +193,232 @@ public class EdFreezer
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static int cooldown_rate = DEFAULT_COOLDOWN_RATE;
private static int reheat_rate = 1;
private final Fluidics.Tank tank_ = new Fluidics.Tank(TANK_CAPACITY, TANK_CAPACITY, TANK_CAPACITY, fs->fs.getFluid()==Fluids.WATER);
private final Fluidics.Tank tank_ = new Fluidics.Tank(TANK_CAPACITY, TANK_CAPACITY, TANK_CAPACITY, fs -> fs.getFluid() == Fluids.WATER);
private final LazyOptional<IItemHandler> item_handler_ = LazyOptional.of(() -> new FreezerItemHandler(this));
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new Fluidics.SingleTankFluidHandler(tank_));
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> this);
private int tick_timer_;
private int energy_stored_;
private int progress_;
private boolean force_block_update_;
public static void on_config(int consumption, int cooldown_per_second)
{
public FreezerTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
public static void on_config(int consumption, int cooldown_per_second) {
energy_consumption = Mth.clamp(consumption, 8, 4096);
cooldown_rate = Mth.clamp(cooldown_per_second, 1, 5);
reheat_rate = Mth.clamp(cooldown_per_second/2, 1, 5);
reheat_rate = Mth.clamp(cooldown_per_second / 2, 1, 5);
ModConfig.log("Config freezer energy consumption:" + energy_consumption + "rf/t, cooldown-rate: " + cooldown_rate + "%/s.");
}
public FreezerTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); }
public int progress() {
return progress_;
}
public int progress()
{ return progress_; }
public int phase()
{
if(tank_.getFluidAmount() < 1000) return PHASE_EMPTY;
if(progress_ >= 100) return PHASE_BLUEICE;
if(progress_ >= 70) return PHASE_PACKEDICE;
if(progress_ >= 30) return PHASE_ICE;
public int phase() {
if (tank_.getFluidAmount() < 1000) return PHASE_EMPTY;
if (progress_ >= 100) return PHASE_BLUEICE;
if (progress_ >= 70) return PHASE_PACKEDICE;
if (progress_ >= 30) return PHASE_ICE;
return PHASE_WATER;
}
public ItemStack getIceItem(boolean extract)
{
public ItemStack getIceItem(boolean extract) {
ItemStack stack;
switch(phase()) {
case PHASE_ICE: stack = new ItemStack(Items.ICE); break;
case PHASE_PACKEDICE: stack = new ItemStack(Items.PACKED_ICE); break;
case PHASE_BLUEICE: stack = new ItemStack(Items.BLUE_ICE); break;
default: return ItemStack.EMPTY;
switch (phase()) {
case PHASE_ICE:
stack = new ItemStack(Items.ICE);
break;
case PHASE_PACKEDICE:
stack = new ItemStack(Items.PACKED_ICE);
break;
case PHASE_BLUEICE:
stack = new ItemStack(Items.BLUE_ICE);
break;
default:
return ItemStack.EMPTY;
}
if(extract) reset_process();
if (extract) reset_process();
return stack;
}
public int comparator_signal()
{ return phase() * 4; }
public int comparator_signal() {
return phase() * 4;
}
protected void reset_process()
{
// BlockEntity ------------------------------------------------------------------------------
protected void reset_process() {
force_block_update_ = true;
tank_.drain(1000);
tick_timer_ = 0;
progress_ = 0;
}
public void readnbt(CompoundTag nbt)
{
public void readnbt(CompoundTag nbt) {
energy_stored_ = nbt.getInt("energy");
progress_ = nbt.getInt("progress");
tank_.load(nbt);
}
protected void writenbt(CompoundTag nbt)
{
nbt.putInt("energy", Mth.clamp(energy_stored_,0 , MAX_ENERGY_BUFFER));
nbt.putInt("progress", Mth.clamp(progress_,0 , 100));
protected void writenbt(CompoundTag nbt) {
nbt.putInt("energy", Mth.clamp(energy_stored_, 0, MAX_ENERGY_BUFFER));
nbt.putInt("progress", Mth.clamp(progress_, 0, 100));
tank_.save(nbt);
}
// BlockEntity ------------------------------------------------------------------------------
// IItemHandler --------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt); }
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt);
}
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt); }
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt);
}
// IFluidHandler --------------------------------------------------------------------------------
@Override
public void setRemoved()
{
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
fluid_handler_.invalidate();
item_handler_.invalidate();
}
// IItemHandler --------------------------------------------------------------------------------
private final LazyOptional<IItemHandler> item_handler_ = LazyOptional.of(() -> new FreezerItemHandler(this));
protected static class FreezerItemHandler implements IItemHandler
{
private final FreezerTileEntity te;
FreezerItemHandler(FreezerTileEntity te)
{ this.te = te; }
@Override
public int getSlots()
{ return 1; }
@Override
public int getSlotLimit(int index)
{ return 1; }
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack)
{ return false; }
@Override
@Nonnull
public ItemStack getStackInSlot(int index)
{ return (index!=0) ? ItemStack.EMPTY : te.getIceItem(false); }
@Override
@Nonnull
public ItemStack insertItem(int index, @Nonnull ItemStack stack, boolean simulate)
{ return ItemStack.EMPTY; }
@Override
@Nonnull
public ItemStack extractItem(int index, int amount, boolean simulate)
{ return te.getIceItem(!simulate); }
}
// IFluidHandler --------------------------------------------------------------------------------
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new Fluidics.SingleTankFluidHandler(tank_));
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> this);
@Override
public boolean canExtract() {
return false;
}
@Override
public boolean canExtract()
{ return false; }
public boolean canReceive() {
return true;
}
@Override
public boolean canReceive()
{ return true; }
public int getMaxEnergyStored() {
return MAX_ENERGY_BUFFER;
}
@Override
public int getMaxEnergyStored()
{ return MAX_ENERGY_BUFFER; }
public int getEnergyStored() {
return energy_stored_;
}
@Override
public int getEnergyStored()
{ return energy_stored_; }
public int extractEnergy(int maxExtract, boolean simulate) {
return 0;
}
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
if(energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
public int receiveEnergy(int maxReceive, boolean simulate) {
if (energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; setChanged(); }
if (n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if (!simulate) {
energy_stored_ += n;
setChanged();
}
return n;
}
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
if (capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
public void tick() {
if (level.isClientSide) return;
if (--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
BlockState state = level.getBlockState(worldPosition);
if (!(state.getBlock() instanceof FreezerBlock)) return;
boolean dirty = false;
final int last_phase = phase();
if (tank_.getFluidAmount() < 1000) {
progress_ = 0;
} else if ((energy_stored_ <= 0) || (level.hasNeighborSignal(worldPosition))) {
progress_ = Mth.clamp(progress_ - reheat_rate, 0, 100);
} else if (progress_ >= 100) {
progress_ = 100;
energy_stored_ = Mth.clamp(energy_stored_ - ((energy_consumption * TICK_INTERVAL) / 20), 0, MAX_ENERGY_BUFFER);
} else {
energy_stored_ = Mth.clamp(energy_stored_ - (energy_consumption * TICK_INTERVAL), 0, MAX_ENERGY_BUFFER);
progress_ = Mth.clamp(progress_ + cooldown_rate, 0, 100);
}
int new_phase = phase();
if (new_phase > last_phase) {
level.playSound(null, worldPosition, SoundEvents.SAND_FALL, SoundSource.BLOCKS, 0.2f, 0.7f);
} else if (new_phase < last_phase) {
level.playSound(null, worldPosition, SoundEvents.SAND_FALL, SoundSource.BLOCKS, 0.2f, 0.7f);
}
// Block state
if ((force_block_update_ || (state.getValue(FreezerBlock.PHASE) != new_phase))) {
state = state.setValue(FreezerBlock.PHASE, new_phase);
level.setBlock(worldPosition, state, 3 | 16);
level.updateNeighborsAt(getBlockPos(), state.getBlock());
force_block_update_ = false;
}
if (dirty) setChanged();
}
// ITickable ------------------------------------------------------------------------------------
protected static class FreezerItemHandler implements IItemHandler {
private final FreezerTileEntity te;
FreezerItemHandler(FreezerTileEntity te) {
this.te = te;
}
@Override
public void tick()
{
if(level.isClientSide) return;
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
BlockState state = level.getBlockState(worldPosition);
if(!(state.getBlock() instanceof FreezerBlock)) return;
boolean dirty = false;
final int last_phase = phase();
if(tank_.getFluidAmount() < 1000) {
progress_ = 0;
} else if((energy_stored_ <= 0) || (level.hasNeighborSignal(worldPosition))) {
progress_ = Mth.clamp(progress_-reheat_rate, 0,100);
} else if(progress_ >= 100) {
progress_ = 100;
energy_stored_ = Mth.clamp(energy_stored_-((energy_consumption*TICK_INTERVAL)/20), 0, MAX_ENERGY_BUFFER);
} else {
energy_stored_ = Mth.clamp(energy_stored_-(energy_consumption*TICK_INTERVAL), 0, MAX_ENERGY_BUFFER);
progress_ = Mth.clamp(progress_+cooldown_rate, 0, 100);
public int getSlots() {
return 1;
}
int new_phase = phase();
if(new_phase > last_phase) {
level.playSound(null, worldPosition, SoundEvents.SAND_FALL, SoundSource.BLOCKS, 0.2f, 0.7f);
} else if(new_phase < last_phase) {
level.playSound(null, worldPosition, SoundEvents.SAND_FALL, SoundSource.BLOCKS, 0.2f, 0.7f);
@Override
public int getSlotLimit(int index) {
return 1;
}
// Block state
if((force_block_update_ || (state.getValue(FreezerBlock.PHASE) != new_phase))) {
state = state.setValue(FreezerBlock.PHASE, new_phase);
level.setBlock(worldPosition, state,3|16);
level.updateNeighborsAt(getBlockPos(), state.getBlock());
force_block_update_ = false;
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
return false;
}
@Override
@Nonnull
public ItemStack getStackInSlot(int index) {
return (index != 0) ? ItemStack.EMPTY : te.getIceItem(false);
}
@Override
@Nonnull
public ItemStack insertItem(int index, @Nonnull ItemStack stack, boolean simulate) {
return ItemStack.EMPTY;
}
@Override
@Nonnull
public ItemStack extractItem(int index, int amount, boolean simulate) {
return te.getIceItem(!simulate);
}
if(dirty) setChanged();
}
}
}

View file

@ -9,6 +9,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.DyeColor;
@ -20,35 +22,37 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable;
import java.util.List;
public class EdGlassBlock extends StainedGlassBlock implements StandardBlocks.IStandardBlock
{
public EdGlassBlock(long config, BlockBehaviour.Properties properties)
{ super(DyeColor.BLACK, properties); }
public class EdGlassBlock extends StainedGlassBlock implements StandardBlocks.IStandardBlock {
public EdGlassBlock(long config, BlockBehaviour.Properties properties) {
super(DyeColor.BLACK, properties);
}
@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); }
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
}
@Override
public StandardBlocks.IStandardBlock.RenderTypeHint getRenderTypeHint()
{ return StandardBlocks.IStandardBlock.RenderTypeHint.TRANSLUCENT; }
public StandardBlocks.IStandardBlock.RenderTypeHint getRenderTypeHint() {
return StandardBlocks.IStandardBlock.RenderTypeHint.TRANSLUCENT;
}
@Override
@OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation")
public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side)
{ return (adjacentBlockState.getBlock()==this) || (super.skipRendering(state, adjacentBlockState, side)); }
public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) {
return (adjacentBlockState.getBlock() == this) || (super.skipRendering(state, adjacentBlockState, side));
}
@Override
public boolean isPossibleToRespawnInThis()
{ return false; }
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
return false;
}
}

View file

@ -8,6 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
@ -22,6 +24,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
@ -35,30 +38,28 @@ 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 dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable;
import java.util.List;
public class EdHatchBlock extends StandardBlocks.HorizontalWaterLoggable
{
public class EdHatchBlock extends StandardBlocks.HorizontalWaterLoggable {
public static final BooleanProperty OPEN = BlockStateProperties.OPEN;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
protected final List<VoxelShape> vshapes_open;
public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABBClosed, final AABB unrotatedAABBOpen)
{
super(config, builder, unrotatedAABBClosed); vshapes_open = makeHorizontalShapeLookup(new AABB[]{unrotatedAABBOpen});
public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABBClosed, final AABB unrotatedAABBOpen) {
super(config, builder, unrotatedAABBClosed);
vshapes_open = makeHorizontalShapeLookup(new AABB[]{unrotatedAABBOpen});
registerDefaultState(super.defaultBlockState().setValue(OPEN, false).setValue(POWERED, false));
}
public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBsClosed, final AABB[] unrotatedAABBsOpen)
{ super(config, builder, unrotatedAABBsClosed); vshapes_open = makeHorizontalShapeLookup(unrotatedAABBsOpen); }
public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBsClosed, final AABB[] unrotatedAABBsOpen) {
super(config, builder, unrotatedAABBsClosed);
vshapes_open = makeHorizontalShapeLookup(unrotatedAABBsOpen);
}
protected static List<VoxelShape> makeHorizontalShapeLookup(final AABB[] unrotatedAABBs)
{
protected static List<VoxelShape> makeHorizontalShapeLookup(final AABB[] unrotatedAABBs) {
return List.of(
Shapes.block(),
Shapes.block(),
@ -70,71 +71,77 @@ public class EdHatchBlock extends StandardBlocks.HorizontalWaterLoggable
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
public RenderTypeHint getRenderTypeHint() {
return RenderTypeHint.CUTOUT;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext)
{ return state.getValue(OPEN) ? vshapes_open.get((state.getValue(HORIZONTAL_FACING)).get3DDataValue()) : super.getShape(state, source, pos, selectionContext); }
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
return state.getValue(OPEN) ? vshapes_open.get((state.getValue(HORIZONTAL_FACING)).get3DDataValue()) : super.getShape(state, source, pos, selectionContext);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext)
{ return getShape(state, source, pos, selectionContext); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
return getShape(state, source, pos, selectionContext);
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos)
{ return state.getValue(OPEN); }
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return state.getValue(OPEN);
}
@Override
@SuppressWarnings("deprecation")
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type)
{ return !state.getValue(OPEN); }
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) {
return !state.getValue(OPEN);
}
@Override
public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity)
{
if(!state.getValue(OPEN)) return false;
public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity) {
if (!state.getValue(OPEN)) return false;
{
final BlockState up_state = world.getBlockState(pos.above());
if(up_state.is(this) && (up_state.getValue(OPEN))) return true;
if(up_state.isLadder(world, pos.above(), entity)) return true;
if (up_state.is(this) && (up_state.getValue(OPEN))) return true;
if (up_state.isLadder(world, pos.above(), entity)) return true;
}
{
final BlockState down_state = world.getBlockState(pos.below());
if(down_state.is(this) && (down_state.getValue(OPEN))) return true;
if(down_state.isLadder(world, pos.below(), entity)) return true;
if (down_state.is(this) && (down_state.getValue(OPEN))) return true;
if (down_state.isLadder(world, pos.below(), entity)) return true;
}
return false;
}
@Override
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType)
{ return false; }
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
return false;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(OPEN, POWERED); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(OPEN, POWERED);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
if (world.isClientSide()) return InteractionResult.SUCCESS;
boolean open = !state.getValue(OPEN);
world.setBlock(pos, state.setValue(OPEN, open), 1|2);
world.playSound(null, pos, open?SoundEvents.IRON_DOOR_OPEN:SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
world.setBlock(pos, state.setValue(OPEN, open), 1 | 2);
world.playSound(null, pos, open ? SoundEvents.IRON_DOOR_OPEN : SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
return InteractionResult.CONSUME;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving)
{
if((world.isClientSide) || (!(state.getBlock() instanceof EdHatchBlock))) return;
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) {
if ((world.isClientSide) || (!(state.getBlock() instanceof EdHatchBlock))) return;
boolean powered = world.hasNeighborSignal(pos);
if(powered == state.getValue(POWERED)) return;
if(powered != state.getValue(OPEN)) world.playSound(null, pos, powered?SoundEvents.IRON_DOOR_OPEN:SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
world.setBlock(pos, state.setValue(OPEN, powered).setValue(POWERED, powered), 1|2);
if (powered == state.getValue(POWERED)) return;
if (powered != state.getValue(OPEN))
world.playSound(null, pos, powered ? SoundEvents.IRON_DOOR_OPEN : SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
world.setBlock(pos, state.setValue(OPEN, powered).setValue(POWERED, powered), 1 | 2);
}
@Override
@ -150,21 +157,21 @@ public class EdHatchBlock extends StandardBlocks.HorizontalWaterLoggable
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
@SuppressWarnings("deprecation")
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity)
{
if((!state.getValue(OPEN)) || (!(entity instanceof final Player player))) return;
if(player.isSteppingCarefully()) return;
if(entity.getLookAngle().y() > -0.75) return;
if(player.getDirection() != state.getValue(HORIZONTAL_FACING)) return;
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
if ((!state.getValue(OPEN)) || (!(entity instanceof final Player player))) return;
if (player.isSteppingCarefully()) return;
if (entity.getLookAngle().y() > -0.75) return;
if (player.getDirection() != state.getValue(HORIZONTAL_FACING)) return;
Vec3 ppos = player.position();
Vec3 centre = Vec3.atBottomCenterOf(pos);
Vec3 v = centre.subtract(ppos);
if(ppos.y() < (centre.y()-0.1) || (v.lengthSqr() > 0.3)) return;
if (ppos.y() < (centre.y() - 0.1) || (v.lengthSqr() > 0.3)) return;
v = v.scale(0.2);
player.push(v.x, -0.1, v.z);
}

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.Inventories;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
@ -39,9 +42,6 @@ import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Inventories;
import javax.annotation.Nullable;
import java.util.HashMap;
@ -85,8 +85,9 @@ public class EdHorizontalSupportBlock extends StandardBlocks.WaterLoggable
{ return RenderTypeHint.CUTOUT; }
@Override
public boolean isPossibleToRespawnInThis()
{ return false; }
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
return false;
}
@Override
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType)

View file

@ -12,6 +12,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
@ -34,16 +37,12 @@ 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 dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable;
import java.util.List;
public class EdLadderBlock extends LadderBlock implements StandardBlocks.IStandardBlock
{
public class EdLadderBlock extends LadderBlock implements StandardBlocks.IStandardBlock {
protected static final AABB EDLADDER_UNROTATED_AABB = Auxiliaries.getPixeledAABB(3, 0, 0, 13, 16, 3);
protected static final VoxelShape EDLADDER_SOUTH_AABB = Shapes.create(Auxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.SOUTH, false));
protected static final VoxelShape EDLADDER_EAST_AABB = Shapes.create(Auxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.EAST, false));
@ -51,27 +50,53 @@ public class EdLadderBlock extends LadderBlock implements StandardBlocks.IStanda
protected static final VoxelShape EDLADDER_NORTH_AABB = Shapes.create(Auxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.NORTH, false));
private static boolean without_speed_boost_ = false;
public static void on_config(boolean without_speed_boost)
{
public EdLadderBlock(long config, BlockBehaviour.Properties builder) {
super(builder);
}
public static void on_config(boolean without_speed_boost) {
without_speed_boost_ = without_speed_boost;
ModConfig.log("Config ladder: without-speed-boost:" + without_speed_boost_);
}
public EdLadderBlock(long config, BlockBehaviour.Properties builder)
{ super(builder); }
// Player update event, forwarded from the main mod instance.
public static void onPlayerUpdateEvent(final Player player) {
if ((without_speed_boost_) || (player.onGround()) || (!player.onClimbable()) || (player.isSteppingCarefully()) || (player.isSpectator()))
return;
double lvy = player.getLookAngle().y;
if (Math.abs(lvy) < 0.92) return;
final BlockPos pos = player.blockPosition();
final BlockState state = player.level().getBlockState(pos);
final Block block = state.getBlock();
if (!(block instanceof EdLadderBlock || block instanceof EdHatchBlock && state.getValue(EdHatchBlock.OPEN)))
return;
player.resetFallDistance();
if ((player.getDeltaMovement().y() < 0) == (player.getLookAngle().y < 0)) {
player.makeStuckInBlock(state, new Vec3(0.2, (lvy > 0) ? (3) : (6), 0.2));
if (Math.abs(player.getDeltaMovement().y()) > 0.1) {
Vec3 vdiff = Vec3.atBottomCenterOf(pos).subtract(player.position()).scale(1);
vdiff.add(Vec3.atBottomCenterOf(state.getValue(FACING).getNormal()).scale(0.5));
vdiff = new Vec3(vdiff.x, player.getDeltaMovement().y, vdiff.z);
player.setDeltaMovement(vdiff);
}
} else if (player.getLookAngle().y > 0) {
player.makeStuckInBlock(state, new Vec3(1, 0.05, 1));
}
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
public RenderTypeHint getRenderTypeHint() {
return RenderTypeHint.CUTOUT;
}
@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); }
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
}
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos)
{
return switch(state.getValue(FACING)) {
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos) {
return switch (state.getValue(FACING)) {
case NORTH -> EDLADDER_NORTH_AABB;
case SOUTH -> EDLADDER_SOUTH_AABB;
case WEST -> EDLADDER_WEST_AABB;
@ -80,44 +105,24 @@ public class EdLadderBlock extends LadderBlock implements StandardBlocks.IStanda
}
@Override
public boolean isPossibleToRespawnInThis()
{ return false; }
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; }
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; }
public PushReaction getPistonPushReaction(BlockState state) {
return PushReaction.NORMAL;
}
@Override
public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity)
{ return true; }
// Player update event, forwarded from the main mod instance.
public static void onPlayerUpdateEvent(final Player player)
{
if((without_speed_boost_) || (player.isOnGround()) || (!player.onClimbable()) || (player.isSteppingCarefully()) || (player.isSpectator())) return;
double lvy = player.getLookAngle().y;
if(Math.abs(lvy) < 0.92) return;
final BlockPos pos = player.blockPosition();
final BlockState state = player.getLevel().getBlockState(pos);
final Block block = state.getBlock();
if(!(block instanceof EdLadderBlock || block instanceof EdHatchBlock && state.getValue(EdHatchBlock.OPEN))) return;
player.resetFallDistance();
if((player.getDeltaMovement().y() < 0) == (player.getLookAngle().y < 0)) {
player.makeStuckInBlock(state, new Vec3(0.2, (lvy>0)?(3):(6), 0.2));
if(Math.abs(player.getDeltaMovement().y()) > 0.1) {
Vec3 vdiff = Vec3.atBottomCenterOf(pos).subtract(player.position()).scale(1);
vdiff.add(Vec3.atBottomCenterOf(state.getValue(FACING).getNormal()).scale(0.5));
vdiff = new Vec3(vdiff.x, player.getDeltaMovement().y, vdiff.z);
player.setDeltaMovement(vdiff);
}
} else if(player.getLookAngle().y > 0) {
player.makeStuckInBlock(state, new Vec3(1, 0.05, 1));
}
public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity) {
return true;
}
}

View file

@ -8,7 +8,10 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.libmc.*;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -30,6 +33,7 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -50,9 +54,6 @@ import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.registries.ForgeRegistries;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import wile.engineersdecor.libmc.*;
import javax.annotation.Nullable;
import java.util.HashMap;
@ -62,34 +63,31 @@ import java.util.Map.Entry;
import java.util.UUID;
public class EdMilker
{
public class EdMilker {
public static final int BUCKET_SIZE = 1000;
public static final int TICK_INTERVAL = 80;
public static final int PROCESSING_TICK_INTERVAL = 20;
public static final int TANK_CAPACITY = BUCKET_SIZE * 12;
public static final int MAX_MILKING_TANK_LEVEL = TANK_CAPACITY-500;
public static final int MAX_MILKING_TANK_LEVEL = TANK_CAPACITY - 500;
public static final int FILLED_INDICATION_THRESHOLD = BUCKET_SIZE;
public static final int MAX_ENERGY_BUFFER = 16000;
public static final int MAX_ENERGY_TRANSFER = 512;
public static final int DEFAULT_ENERGY_CONSUMPTION = 0;
public static final int DEFAULT_MILKING_DELAY_PER_COW = 4000;
private static final FluidStack NO_MILK_FLUID = new FluidStack(Fluids.WATER, 1000);
private static FluidStack milk_fluid_ = NO_MILK_FLUID;
private static final HashMap<ItemStack, ItemStack> milk_containers_ = new HashMap<>();
private static FluidStack milk_fluid_ = NO_MILK_FLUID;
private static int energy_consumption_ = DEFAULT_ENERGY_CONSUMPTION;
private static long min_milking_delay_per_cow_ticks_ = DEFAULT_MILKING_DELAY_PER_COW;
public static void on_config(int energy_consumption_per_tick, int min_milking_delay_per_cow)
{
public static void on_config(int energy_consumption_per_tick, int min_milking_delay_per_cow) {
energy_consumption_ = Mth.clamp(energy_consumption_per_tick, 0, 1024);
min_milking_delay_per_cow_ticks_ = Mth.clamp(min_milking_delay_per_cow, 1000, 24000);
{
ResourceLocation milk_rl = ForgeRegistries.FLUIDS.getKeys().stream().filter(rl->rl.getPath().equals("milk")).findFirst().orElse(null);
if(milk_rl != null) {
ResourceLocation milk_rl = ForgeRegistries.FLUIDS.getKeys().stream().filter(rl -> rl.getPath().equals("milk")).findFirst().orElse(null);
if (milk_rl != null) {
Fluid milk = ForgeRegistries.FLUIDS.getValue(milk_rl);
if(milk != null) milk_fluid_ = new FluidStack(milk, BUCKET_SIZE);
if (milk != null) milk_fluid_ = new FluidStack(milk, BUCKET_SIZE);
}
}
{
@ -97,7 +95,7 @@ public class EdMilker
}
ModConfig.log(
"Config milker: energy consumption:" + energy_consumption_ + "rf/t"
+ ((milk_fluid_==NO_MILK_FLUID)?"[no milk fluid registered]":" [milk fluid available]")
+ ((milk_fluid_ == NO_MILK_FLUID) ? "[no milk fluid registered]" : " [milk fluid available]")
);
}
@ -105,80 +103,83 @@ public class EdMilker
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class MilkerBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<MilkerTileEntity>
{
public static class MilkerBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<MilkerTileEntity> {
public static final BooleanProperty FILLED = BooleanProperty.create("filled");
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public MilkerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs)
{
public MilkerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs) {
super(config, builder, unrotatedAABBs);
cshapes.replaceAll((state,shape)->Shapes.create(Auxiliaries.getPixeledAABB(0,0,0, 16,24,16)));
cshapes.replaceAll((state, shape) -> Shapes.create(Auxiliaries.getPixeledAABB(0, 0, 0, 16, 24, 16)));
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(ACTIVE); builder.add(FILLED); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(ACTIVE);
builder.add(FILLED);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(FILLED, false).setValue(ACTIVE, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos)
{
MilkerTileEntity te = getTe(world, pos);
return (te==null) ? 0 : Mth.clamp((16 * te.fluid_level())/TANK_CAPACITY, 0, 15);
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(FILLED, false).setValue(ACTIVE, false);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if(world.isClientSide()) return InteractionResult.SUCCESS;
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
MilkerTileEntity te = getTe(world, pos);
if(te==null) return InteractionResult.FAIL;
return (te == null) ? 0 : Mth.clamp((16 * te.fluid_level()) / TANK_CAPACITY, 0, 15);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (world.isClientSide()) return InteractionResult.SUCCESS;
MilkerTileEntity te = getTe(world, pos);
if (te == null) return InteractionResult.FAIL;
final ItemStack in_stack = player.getItemInHand(hand);
final ItemStack out_stack = MilkerTileEntity.milk_filled_container_item(in_stack);
if(in_stack.isEmpty()) {
if (in_stack.isEmpty()) {
te.state_message(player);
return InteractionResult.CONSUME;
} else if(out_stack.isEmpty() && (te.fluid_handler()!=null)) {
} else if (out_stack.isEmpty() && (te.fluid_handler() != null)) {
return Fluidics.manualFluidHandlerInteraction(player, hand, te.fluid_handler()) ? InteractionResult.CONSUME : InteractionResult.FAIL;
} else {
boolean drained = false;
IItemHandler player_inventory = Inventories.itemhandler(player);
if(te.fluid_level() >= BUCKET_SIZE) {
if (te.fluid_level() >= BUCKET_SIZE) {
final ItemStack insert_stack = out_stack.copy();
ItemStack remainder = ItemHandlerHelper.insertItemStacked(player_inventory, insert_stack, false);
if(remainder.getCount() < insert_stack.getCount()) {
if (remainder.getCount() < insert_stack.getCount()) {
te.drain(BUCKET_SIZE);
in_stack.shrink(1);
drained = true;
if(remainder.getCount() > 0) {
final ItemEntity ei = new ItemEntity(world, player.position().x(), player.position().y()+0.5, player.position().z(), remainder);
if (remainder.getCount() > 0) {
final ItemEntity ei = new ItemEntity(world, player.position().x(), player.position().y() + 0.5, player.position().z(), remainder);
ei.setPickUpDelay(40);
ei.setDeltaMovement(0,0,0);
ei.setDeltaMovement(0, 0, 0);
world.addFreshEntity(ei);
}
}
}
if(drained) {
if (drained) {
world.playSound(null, pos, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 0.8f, 1f);
}
}
@ -186,8 +187,10 @@ public class EdMilker
}
@Nullable
private MilkerTileEntity getTe(Level world, BlockPos pos)
{ final BlockEntity te=world.getBlockEntity(pos); return (!(te instanceof MilkerTileEntity)) ? (null) : ((MilkerTileEntity)te); }
private MilkerTileEntity getTe(Level world, BlockPos pos) {
final BlockEntity te = world.getBlockEntity(pos);
return (!(te instanceof MilkerTileEntity)) ? (null) : ((MilkerTileEntity) te);
}
}
//--------------------------------------------------------------------------------------------------------------------
@ -196,32 +199,33 @@ public class EdMilker
public static class MilkerTileEntity extends StandardEntityBlocks.StandardBlockEntity // implements IFluidTank
{
private static final Direction[] FLUID_TRANSFER_DIRECTRIONS = {Direction.DOWN,Direction.EAST,Direction.SOUTH,Direction.WEST,Direction.NORTH};
private enum MilkingState { IDLE, PICKED, COMING, POSITIONING, MILKING, LEAVING, WAITING }
private static final Direction[] FLUID_TRANSFER_DIRECTRIONS = {Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH};
private static final HashMap<Integer, Long> tracked_cows_ = new HashMap<>();
private final RfEnergy.Battery battery_;
private final LazyOptional<IEnergyStorage> energy_handler_;
private final Fluidics.Tank tank_;
private final LazyOptional<IFluidHandler> fluid_handler_;
private int tick_timer_;
private UUID tracked_cow_ = null;
private MilkingState state_ = MilkingState.IDLE;
private int state_timeout_ = 0;
private int state_timer_ = 0;
private BlockPos tracked_cow_original_position_ = null;
private final RfEnergy.Battery battery_;
private final LazyOptional<IEnergyStorage> energy_handler_;
private final Fluidics.Tank tank_;
private final LazyOptional<IFluidHandler> fluid_handler_;
public MilkerTileEntity(BlockPos pos, BlockState state)
{
public MilkerTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
tank_ = new Fluidics.Tank(TANK_CAPACITY, 0, BUCKET_SIZE, fs->fs.isFluidEqual(milk_fluid_));
tank_ = new Fluidics.Tank(TANK_CAPACITY, 0, BUCKET_SIZE, fs -> fs.isFluidEqual(milk_fluid_));
fluid_handler_ = tank_.createOutputFluidHandler();
battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0);
energy_handler_ = battery_.createEnergyHandler();
reset();
}
public void reset()
{
private static ItemStack milk_filled_container_item(ItemStack stack) {
return milk_containers_.entrySet().stream().filter(e -> Inventories.areItemStacksIdentical(e.getKey(), stack)).map(Map.Entry::getValue).findFirst().orElse(ItemStack.EMPTY);
}
public void reset() {
tank_.clear();
battery_.clear();
tick_timer_ = 0;
@ -230,115 +234,115 @@ public class EdMilker
state_timeout_ = 0;
}
public CompoundTag destroy_getnbt()
{
public CompoundTag destroy_getnbt() {
final UUID cowuid = tracked_cow_;
CompoundTag nbt = new CompoundTag();
writenbt(nbt, false); reset();
if(cowuid == null) return nbt;
level.getEntitiesOfClass(Cow.class, new AABB(worldPosition).inflate(16, 16, 16), e->e.getUUID().equals(cowuid)).forEach(e->e.setNoAi(false));
writenbt(nbt, false);
reset();
if (cowuid == null) return nbt;
level.getEntitiesOfClass(Cow.class, new AABB(worldPosition).inflate(16, 16, 16), e -> e.getUUID().equals(cowuid)).forEach(e -> e.setNoAi(false));
return nbt;
}
public void readnbt(CompoundTag nbt, boolean update_packet)
{
public void readnbt(CompoundTag nbt, boolean update_packet) {
battery_.load(nbt);
tank_.load(nbt);
}
protected void writenbt(CompoundTag nbt, boolean update_packet)
{
protected void writenbt(CompoundTag nbt, boolean update_packet) {
tank_.save(nbt);
if(!battery_.isEmpty()) battery_.save(nbt);
if (!battery_.isEmpty()) battery_.save(nbt);
}
private boolean has_milk_fluid()
{ return !(NO_MILK_FLUID.isFluidEqual(milk_fluid_)); }
private boolean has_milk_fluid() {
return !(NO_MILK_FLUID.isFluidEqual(milk_fluid_));
}
private IFluidHandler fluid_handler()
{ return fluid_handler_.orElse(null); }
private IFluidHandler fluid_handler() {
return fluid_handler_.orElse(null);
}
private int fluid_level()
{ return tank_.getFluidAmount(); }
private int fluid_level() {
return tank_.getFluidAmount();
}
private FluidStack drain(int amount)
{ return tank_.drain(amount); }
public void state_message(Player player)
{
Component rf = (energy_consumption_ <= 0) ? (Component.empty()) : (Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status.rf", battery_.getEnergyStored()));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status", tank_.getFluidAmount(), rf));
private FluidStack drain(int amount) {
return tank_.drain(amount);
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt, false); }
public void state_message(Player player) {
Component rf = (energy_consumption_ <= 0) ? (Component.empty()) : (Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status.rf", battery_.getEnergyStored()));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status", tank_.getFluidAmount(), rf));
}
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt, false); }
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt, false);
}
@Override
public void setRemoved()
{
super.setRemoved();
energy_handler_.invalidate();
fluid_handler_.invalidate();
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt, false);
}
// ICapabilityProvider ---------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if((capability == ForgeCapabilities.FLUID_HANDLER) && has_milk_fluid()) return fluid_handler_.cast();
if((capability == ForgeCapabilities.ENERGY) && (energy_consumption_>0)) return energy_handler_.cast();
return super.getCapability(capability, facing);
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
fluid_handler_.invalidate();
}
// ITickable ------------------------------------------------------------------------------------
private static final HashMap<Integer, Long> tracked_cows_ = new HashMap<>();
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if ((capability == ForgeCapabilities.FLUID_HANDLER) && has_milk_fluid()) return fluid_handler_.cast();
if ((capability == ForgeCapabilities.ENERGY) && (energy_consumption_ > 0)) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
private void log(String s)
{} // println("Milker|" + s); may be enabled with config, for dev was println
private void log(String s) {
} // println("Milker|" + s); may be enabled with config, for dev was println
private static ItemStack milk_filled_container_item(ItemStack stack)
{ return milk_containers_.entrySet().stream().filter(e-> Inventories.areItemStacksIdentical(e.getKey(), stack)).map(Map.Entry::getValue).findFirst().orElse(ItemStack.EMPTY); }
private boolean fill_adjacent_inventory_item_containers(Direction block_facing)
{
private boolean fill_adjacent_inventory_item_containers(Direction block_facing) {
// Check inventory existence, back to down is preferred, otherwise sort back into same inventory.
IItemHandler src = Inventories.itemhandler(level, worldPosition.relative(block_facing), block_facing.getOpposite());
IItemHandler dst = Inventories.itemhandler(level, worldPosition.below(), Direction.UP);
if(src==null) { src = dst; } else if(dst==null) { dst = src; }
if((src==null) || (dst==null)) return false;
if (src == null) {
src = dst;
} else if (dst == null) {
dst = src;
}
if ((src == null) || (dst == null)) return false;
boolean dirty = false;
while((tank_.getFluidAmount() >= BUCKET_SIZE)) {
while ((tank_.getFluidAmount() >= BUCKET_SIZE)) {
boolean inserted = false;
for(Entry<ItemStack,ItemStack> e:milk_containers_.entrySet()) {
if(Inventories.extract(src, e.getKey(), 1, true).isEmpty()) continue;
if(!Inventories.insert(dst, e.getValue().copy(), false).isEmpty()) continue;
for (Entry<ItemStack, ItemStack> e : milk_containers_.entrySet()) {
if (Inventories.extract(src, e.getKey(), 1, true).isEmpty()) continue;
if (!Inventories.insert(dst, e.getValue().copy(), false).isEmpty()) continue;
Inventories.extract(src, e.getKey(), 1, false);
tank_.drain(BUCKET_SIZE);
inserted = true;
dirty = true;
break;
}
if(!inserted) break;
if (!inserted) break;
}
return dirty;
}
private boolean fill_adjacent_tank()
{
if((fluid_level()<=0) || (!has_milk_fluid())) return false;
private boolean fill_adjacent_tank() {
if ((fluid_level() <= 0) || (!has_milk_fluid())) return false;
final FluidStack fs = new FluidStack(milk_fluid_, Math.max(fluid_level(), BUCKET_SIZE));
for(Direction dir:Direction.values()) {
for (Direction dir : Direction.values()) {
int amount = Fluidics.fill(getLevel(), getBlockPos().relative(dir), dir.getOpposite(), fs);
if(amount > 0) {
if (amount > 0) {
tank_.drain(amount);
return true;
}
@ -346,14 +350,13 @@ public class EdMilker
return false;
}
private void release_cow(Cow cow)
{
private void release_cow(Cow cow) {
log("release cow");
if(cow != null) {
if (cow != null) {
cow.setNoAi(false);
SingleMoveGoal.abortFor(cow);
tracked_cows_.remove(cow.getId());
for(int id: tracked_cows_.keySet().stream().filter(i->cow.getCommandSenderWorld().getEntity(i) == null).toList()) {
for (int id : tracked_cows_.keySet().stream().filter(i -> cow.getCommandSenderWorld().getEntity(i) == null).toList()) {
tracked_cows_.remove(id);
}
}
@ -362,44 +365,54 @@ public class EdMilker
tick_timer_ = TICK_INTERVAL;
}
private boolean milking_process()
{
if((tracked_cow_ == null) && (fluid_level() >= MAX_MILKING_TANK_LEVEL)) return false; // nothing to do
private boolean milking_process() {
if ((tracked_cow_ == null) && (fluid_level() >= MAX_MILKING_TANK_LEVEL)) return false; // nothing to do
final Direction facing = level.getBlockState(getBlockPos()).getValue(MilkerBlock.HORIZONTAL_FACING).getOpposite();
final Vec3 target_pos = Vec3.atLowerCornerOf(getBlockPos().relative(facing)).add(0.5,0,0.5);
final Vec3 target_pos = Vec3.atLowerCornerOf(getBlockPos().relative(facing)).add(0.5, 0, 0.5);
Cow cow = null;
{
AABB aabb = new AABB(worldPosition.relative(facing, 3)).inflate(4, 2, 4);
final long t = level.getGameTime();
final List<Cow> cows = level.getEntitiesOfClass(Cow.class, aabb,
e-> {
if(e.getUUID().equals(tracked_cow_)) return true;
if((tracked_cow_!=null) || e.isBaby() || e.isInLove() || e.isVehicle()) return false;
if(!e.getNavigation().isDone()) return false;
if(Math.abs(tracked_cows_.getOrDefault(e.getId(), 0L)-t) < min_milking_delay_per_cow_ticks_) return false;
e -> {
if (e.getUUID().equals(tracked_cow_)) return true;
if ((tracked_cow_ != null) || e.isBaby() || e.isInLove() || e.isVehicle()) return false;
if (!e.getNavigation().isDone()) return false;
if (Math.abs(tracked_cows_.getOrDefault(e.getId(), 0L) - t) < min_milking_delay_per_cow_ticks_)
return false;
return true;
}
);
if(cows.size() == 1) {
if (cows.size() == 1) {
cow = cows.get(0); // tracked or only one
} else if(cows.size() > 1) {
cow = cows.get(level.random.nextInt(cows.size()-1)); // pick one
} else if (cows.size() > 1) {
cow = cows.get(level.random.nextInt(cows.size() - 1)); // pick one
}
}
if((state_ != MilkingState.IDLE) && ((state_timeout_ -= PROCESSING_TICK_INTERVAL) <= 0)) { release_cow(cow); log("Cow motion timeout"); cow = null; }
if((cow == null) || (!cow.isAlive())) { release_cow(cow); cow = null; }
if(tracked_cow_ == null) state_ = MilkingState.IDLE;
if(cow == null) { log("Init: No cow"); return false; } // retry next cycle
if ((state_ != MilkingState.IDLE) && ((state_timeout_ -= PROCESSING_TICK_INTERVAL) <= 0)) {
release_cow(cow);
log("Cow motion timeout");
cow = null;
}
if ((cow == null) || (!cow.isAlive())) {
release_cow(cow);
cow = null;
}
if (tracked_cow_ == null) state_ = MilkingState.IDLE;
if (cow == null) {
log("Init: No cow");
return false;
} // retry next cycle
tick_timer_ = PROCESSING_TICK_INTERVAL;
state_timer_ -= PROCESSING_TICK_INTERVAL;
if(state_timer_ > 0) return false;
switch(state_) { // Let's do this the old school FSA sequencing way ...
if (state_timer_ > 0) return false;
switch (state_) { // Let's do this the old school FSA sequencing way ...
case IDLE -> {
final List<LivingEntity> blocking_entities = level.getEntitiesOfClass(LivingEntity.class, new AABB(worldPosition.relative(facing)).inflate(0.5, 0.5, 0.5));
if(blocking_entities.size() > 0) {
if (blocking_entities.size() > 0) {
tick_timer_ = TICK_INTERVAL;
log("Idle: Position blocked");
if(blocking_entities.get(0) instanceof final Cow blocker) {
if (blocking_entities.get(0) instanceof final Cow blocker) {
BlockPos p = getBlockPos().relative(facing, 2);
log("Idle: Shove off");
blocker.setNoAi(false);
@ -407,7 +420,7 @@ public class EdMilker
}
return false;
}
if(cow.isLeashed() || cow.isBaby() || cow.isInLove() || (!cow.isOnGround()) || cow.isVehicle() || cow.isSprinting())
if (cow.isLeashed() || cow.isBaby() || cow.isInLove() || (!cow.onGround()) || cow.isVehicle() || cow.isSprinting())
return false;
tracked_cows_.put(cow.getId(), cow.getCommandSenderWorld().getGameTime());
tracked_cow_ = cow.getUUID();
@ -433,11 +446,11 @@ public class EdMilker
return false;
}
case COMING -> {
if(target_pos.distanceToSqr(cow.position()) <= 1) {
if (target_pos.distanceToSqr(cow.position()) <= 1) {
log("Coming: position reached");
state_ = MilkingState.POSITIONING;
state_timeout_ = 100; // 5s
} else if((!SingleMoveGoal.isActiveFor(cow))) {
} else if ((!SingleMoveGoal.isActiveFor(cow))) {
release_cow(cow);
log("Coming: aborted");
} else {
@ -480,7 +493,7 @@ public class EdMilker
case WAITING -> {
// wait for the timeout to kick in until starting with the next.
tick_timer_ = TICK_INTERVAL;
if(state_timer_ < 40) {
if (state_timer_ < 40) {
tracked_cow_ = null;
release_cow(null);
}
@ -493,52 +506,49 @@ public class EdMilker
}
@Override
public void tick()
{
if((level.isClientSide) || ((--tick_timer_ > 0))) return;
public void tick() {
if ((level.isClientSide) || ((--tick_timer_ > 0))) return;
tick_timer_ = TICK_INTERVAL;
boolean dirty = false;
final BlockState block_state = level.getBlockState(worldPosition);
if(!(block_state.getBlock() instanceof MilkerBlock)) return;
if(!level.hasNeighborSignal(worldPosition) || (state_ != MilkingState.IDLE)) {
if((energy_consumption_ > 0) && (!battery_.draw(energy_consumption_))) return;
if (!(block_state.getBlock() instanceof MilkerBlock)) return;
if (!level.hasNeighborSignal(worldPosition) || (state_ != MilkingState.IDLE)) {
if ((energy_consumption_ > 0) && (!battery_.draw(energy_consumption_))) return;
// Track and milk cows
if(milking_process()) dirty = true;
if (milking_process()) dirty = true;
// Fluid transfer
if(has_milk_fluid() && (!tank_.isEmpty())) {
if (has_milk_fluid() && (!tank_.isEmpty())) {
log("Fluid transfer");
for(Direction facing: FLUID_TRANSFER_DIRECTRIONS) {
for (Direction facing : FLUID_TRANSFER_DIRECTRIONS) {
final IFluidHandler fh = Fluidics.handler(level, worldPosition.relative(facing), facing.getOpposite());
if(fh == null) continue;
if (fh == null) continue;
final FluidStack fs = tank_.drain(BUCKET_SIZE, IFluidHandler.FluidAction.SIMULATE);
int nfilled = fh.fill(fs, IFluidHandler.FluidAction.EXECUTE);
if(nfilled <= 0) continue;
if (nfilled <= 0) continue;
tank_.drain(nfilled, IFluidHandler.FluidAction.EXECUTE);
dirty = true;
break;
}
}
// Adjacent inventory update, only done just after milking to prevent waste of server cpu.
if((!dirty) && (fluid_level() > 0)) {
if ((!dirty) && (fluid_level() > 0)) {
log("Try item transfer");
if(fill_adjacent_tank() || ((fluid_level() >= BUCKET_SIZE) && fill_adjacent_inventory_item_containers(block_state.getValue(MilkerBlock.HORIZONTAL_FACING)))) dirty = true;
if (fill_adjacent_tank() || ((fluid_level() >= BUCKET_SIZE) && fill_adjacent_inventory_item_containers(block_state.getValue(MilkerBlock.HORIZONTAL_FACING))))
dirty = true;
}
}
// State update
BlockState new_state = block_state.setValue(MilkerBlock.FILLED, fluid_level()>=FILLED_INDICATION_THRESHOLD).setValue(MilkerBlock.ACTIVE, state_==MilkingState.MILKING);
if(block_state != new_state) level.setBlock(worldPosition, new_state,1|2|16);
if(dirty) setChanged();
}
BlockState new_state = block_state.setValue(MilkerBlock.FILLED, fluid_level() >= FILLED_INDICATION_THRESHOLD).setValue(MilkerBlock.ACTIVE, state_ == MilkingState.MILKING);
if (block_state != new_state) level.setBlock(worldPosition, new_state, 1 | 2 | 16);
if (dirty) setChanged();
}
public static class SingleMoveGoal extends MoveToBlockGoal
{
@FunctionalInterface public interface TargetPositionInValidCheck { boolean test(SingleMoveGoal goal, LevelReader world, BlockPos pos); }
@FunctionalInterface public interface StrollEvent { void apply(SingleMoveGoal goal, LevelReader world, Vec3 pos); }
private static void log(String s) {} // println("SingleMoveGoal: "+s);
private enum MilkingState {IDLE, PICKED, COMING, POSITIONING, MILKING, LEAVING, WAITING}
}
public static class SingleMoveGoal extends MoveToBlockGoal {
private static final HashMap<Integer, SingleMoveGoal> tracked_entities_ = new HashMap<>();
private static final int motion_timeout = 20*20;
private static final int motion_timeout = 20 * 20;
private boolean aborted_;
private boolean in_position_;
private boolean was_aborted_;
@ -546,9 +556,7 @@ public class EdMilker
private TargetPositionInValidCheck abort_condition_;
private StrollEvent on_target_position_reached_;
private StrollEvent on_aborted_;
public SingleMoveGoal(PathfinderMob creature, Vec3 pos, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted)
{
public SingleMoveGoal(PathfinderMob creature, Vec3 pos, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted) {
super(creature, speed, 32, 32);
abort_condition_ = abort_condition;
on_target_position_reached_ = on_position_reached;
@ -561,18 +569,21 @@ public class EdMilker
target_pos_ = pos;
}
public static void startFor(PathfinderMob entity, BlockPos target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition)
{ startFor(entity, new Vec3(target_pos.getX(),target_pos.getY(),target_pos.getZ()), priority, speed, abort_condition, null, null); }
private static void log(String s) {
} // println("SingleMoveGoal: "+s);
public static boolean startFor(PathfinderMob entity, Vec3 target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted)
{
synchronized(tracked_entities_) {
public static void startFor(PathfinderMob entity, BlockPos target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition) {
startFor(entity, new Vec3(target_pos.getX(), target_pos.getY(), target_pos.getZ()), priority, speed, abort_condition, null, null);
}
public static boolean startFor(PathfinderMob entity, Vec3 target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted) {
synchronized (tracked_entities_) {
SingleMoveGoal goal = tracked_entities_.getOrDefault(entity.getId(), null);
if(goal != null) {
if(!goal.aborted()) return false; // that is still running.
if (goal != null) {
if (!goal.aborted()) return false; // that is still running.
entity.goalSelector.removeGoal(goal);
}
log("::start("+entity.getId()+")");
log("::start(" + entity.getId() + ")");
goal = new SingleMoveGoal(entity, target_pos, speed, abort_condition, on_position_reached, on_aborted);
tracked_entities_.put(entity.getId(), goal);
entity.goalSelector.addGoal(priority, goal);
@ -580,39 +591,42 @@ public class EdMilker
}
}
public static boolean isActiveFor(PathfinderMob entity)
{ return (entity != null) && (entity.goalSelector.getRunningGoals().anyMatch(
g->((g.getGoal()) instanceof SingleMoveGoal) && (!((SingleMoveGoal)(g.getGoal())).aborted())
)); }
public static boolean isActiveFor(PathfinderMob entity) {
return (entity != null) && (entity.goalSelector.getRunningGoals().anyMatch(
g -> ((g.getGoal()) instanceof SingleMoveGoal) && (!((SingleMoveGoal) (g.getGoal())).aborted())
));
}
public static void abortFor(PathfinderMob entity)
{
log("::abort("+entity.getId()+")");
if(entity.isAlive()) {
entity.goalSelector.getRunningGoals().filter(g->(g.getGoal()) instanceof SingleMoveGoal).forEach(g->((SingleMoveGoal)g.getGoal()).abort());
public static void abortFor(PathfinderMob entity) {
log("::abort(" + entity.getId() + ")");
if (entity.isAlive()) {
entity.goalSelector.getRunningGoals().filter(g -> (g.getGoal()) instanceof SingleMoveGoal).forEach(g -> ((SingleMoveGoal) g.getGoal()).abort());
}
final Level world = entity.getCommandSenderWorld();
if(world != null) {
if (world != null) {
// @todo: check nicer way to filter a map.
List<Integer> to_remove = tracked_entities_.keySet().stream().filter(i->(world.getEntity(i) == null)).toList();
for(int id:to_remove)tracked_entities_.remove(id);
List<Integer> to_remove = tracked_entities_.keySet().stream().filter(i -> (world.getEntity(i) == null)).toList();
for (int id : to_remove) tracked_entities_.remove(id);
}
}
public Vec3 getTargetPosition()
{ return target_pos_; }
public Vec3 getTargetPosition() {
return target_pos_;
}
public PathfinderMob getCreature()
{ return mob; }
public PathfinderMob getCreature() {
return mob;
}
public synchronized void abort()
{ aborted_ = true; }
public synchronized void abort() {
aborted_ = true;
}
public synchronized boolean aborted()
{ return aborted_; }
public synchronized boolean aborted() {
return aborted_;
}
public synchronized void initialize(Vec3 target_pos, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted)
{
public synchronized void initialize(Vec3 target_pos, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted) {
abort_condition_ = abort_condition;
on_target_position_reached_ = on_position_reached;
on_aborted_ = on_aborted;
@ -626,28 +640,33 @@ public class EdMilker
}
@Override
public void stop()
{ nextStartTick = 0; tryTicks = 0; }
public void stop() {
nextStartTick = 0;
tryTicks = 0;
}
@Override
public double acceptedDistance()
{ return 0.7; }
public double acceptedDistance() {
return 0.7;
}
@Override
public boolean shouldRecalculatePath()
{ return (!aborted()) && (tryTicks & 0x7) == 0; }
public boolean shouldRecalculatePath() {
return (!aborted()) && (tryTicks & 0x7) == 0;
}
@Override
public boolean canUse()
{
if(aborted_) {
if((!was_aborted_) && (on_aborted_!=null)) on_aborted_.apply(this, mob.level, target_pos_);
public boolean canUse() {
if (aborted_) {
if ((!was_aborted_) && (on_aborted_ != null)) on_aborted_.apply(this, mob.level(), target_pos_);
was_aborted_ = true;
return false;
} else if(!isValidTarget(mob.level, blockPos)) {
synchronized(this) { aborted_ = true; }
} else if (!isValidTarget(mob.level(), blockPos)) {
synchronized (this) {
aborted_ = true;
}
return false;
} else if(--nextStartTick > 0) {
} else if (--nextStartTick > 0) {
return false;
} else {
nextStartTick = 10;
@ -656,10 +675,9 @@ public class EdMilker
}
@Override
public void start()
{
public void start() {
tryTicks = 0;
if(!mob.getNavigation().moveTo(target_pos_.x(), target_pos_.y(), target_pos_.z(), this.speedModifier)) {
if (!mob.getNavigation().moveTo(target_pos_.x(), target_pos_.y(), target_pos_.z(), this.speedModifier)) {
abort();
log("startExecuting() -> abort, no path");
} else {
@ -667,24 +685,23 @@ public class EdMilker
}
}
public boolean canContinueToUse()
{
if(aborted()) {
public boolean canContinueToUse() {
if (aborted()) {
log("shouldContinueExecuting() -> already aborted");
return false;
} else if(mob.getNavigation().isDone()) {
if((!mob.getNavigation().moveTo(mob.getNavigation().createPath(target_pos_.x(), target_pos_.y(), target_pos_.z(), 0), speedModifier))) {
} else if (mob.getNavigation().isDone()) {
if ((!mob.getNavigation().moveTo(mob.getNavigation().createPath(target_pos_.x(), target_pos_.y(), target_pos_.z(), 0), speedModifier))) {
log("shouldContinueExecuting() -> abort, no path");
abort();
return false;
} else {
return true;
}
} else if(tryTicks > motion_timeout) {
} else if (tryTicks > motion_timeout) {
log("shouldContinueExecuting() -> abort, timeout");
abort();
return false;
} else if(!isValidTarget(mob.level, blockPos)) {
} else if (!isValidTarget(mob.level(), blockPos)) {
log("shouldContinueExecuting() -> abort, !shouldMoveTo()");
abort();
return false;
@ -695,9 +712,8 @@ public class EdMilker
}
@Override
protected boolean isValidTarget(LevelReader world, BlockPos pos)
{
if(abort_condition_.test(this, world, pos)) {
protected boolean isValidTarget(LevelReader world, BlockPos pos) {
if (abort_condition_.test(this, world, pos)) {
log("shouldMoveTo() -> abort_condition");
return false;
} else {
@ -706,16 +722,15 @@ public class EdMilker
}
@Override
public void tick()
{
final BlockPos testpos = new BlockPos(target_pos_.x(), mob.position().y(), target_pos_.z());
if(!testpos.closerToCenterThan(mob.position(), acceptedDistance())) {
if((++tryTicks > motion_timeout)) {
public void tick() {
final BlockPos testpos = new BlockPos((int) target_pos_.x(), (int) mob.position().y(), (int) target_pos_.z());
if (!testpos.closerToCenterThan(mob.position(), acceptedDistance())) {
if ((++tryTicks > motion_timeout)) {
log("tick() -> abort, timeoutCounter");
abort();
return;
}
if(shouldRecalculatePath() && (!mob.getNavigation().moveTo(target_pos_.x(), target_pos_.y(), target_pos_.z(), speedModifier))) {
if (shouldRecalculatePath() && (!mob.getNavigation().moveTo(target_pos_.x(), target_pos_.y(), target_pos_.z(), speedModifier))) {
log("tick() -> abort, !tryMoveToXYZ()");
abort();
}
@ -723,8 +738,19 @@ public class EdMilker
log("tick() -> abort, in position)");
in_position_ = true;
abort();
if(on_target_position_reached_ != null) on_target_position_reached_.apply(this, mob.level, target_pos_);
if (on_target_position_reached_ != null)
on_target_position_reached_.apply(this, mob.level(), target_pos_);
}
}
@FunctionalInterface
public interface TargetPositionInValidCheck {
boolean test(SingleMoveGoal goal, LevelReader world, BlockPos pos);
}
@FunctionalInterface
public interface StrollEvent {
void apply(SingleMoveGoal goal, LevelReader world, Vec3 pos);
}
}
}

View file

@ -9,6 +9,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleOptions;
@ -29,7 +32,7 @@ import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -51,107 +54,109 @@ import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Fluidics;
import dev.zontreck.engineerdecor.libmc.Inventories;
import dev.zontreck.engineerdecor.libmc.RfEnergy;
import javax.annotation.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class EdMineralSmelter
{
public static void on_config(int consumption, int heatup_per_second)
{ MineralSmelterTileEntity.on_config(consumption, heatup_per_second); }
public class EdMineralSmelter {
public static void on_config(int consumption, int heatup_per_second) {
MineralSmelterTileEntity.on_config(consumption, heatup_per_second);
}
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class MineralSmelterBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<MineralSmelterTileEntity>
{
public static class MineralSmelterBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<MineralSmelterTileEntity> {
public static final int PHASE_MAX = 3;
public static final IntegerProperty PHASE = IntegerProperty.create("phase", 0, PHASE_MAX);
public MineralSmelterBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public MineralSmelterBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return Shapes.block(); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return Shapes.block();
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(PHASE); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(PHASE);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(PHASE, 0); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(PHASE, 0);
}
@Override
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state)
{ return true; }
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos)
{ return Mth.clamp((state.getValue(PHASE)*5), 0, 15); }
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
return Mth.clamp((state.getValue(PHASE) * 5), 0, 15);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{}
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion)
{
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks;
if(!(te instanceof MineralSmelterTileEntity)) return stacks;
((MineralSmelterTileEntity)te).reset_process();
if (world.isClientSide) return stacks;
if (!(te instanceof MineralSmelterTileEntity)) return stacks;
((MineralSmelterTileEntity) te).reset_process();
stacks.add(new ItemStack(this, 1));
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{
if(player.isShiftKeyDown()) return InteractionResult.PASS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
if (player.isShiftKeyDown()) return InteractionResult.PASS;
if (world.isClientSide()) return InteractionResult.SUCCESS;
MineralSmelterTileEntity te = getTe(world, pos);
if(te==null) return InteractionResult.FAIL;
if (te == null) return InteractionResult.FAIL;
final ItemStack stack = player.getItemInHand(hand);
boolean dirty = false;
if(te.accepts_lava_container(stack)) {
if(stack.sameItemStackIgnoreDurability(MineralSmelterTileEntity.BUCKET_STACK)) { // check how this works with item capabilities or so
if(te.bucket_extraction_possible()) {
if(stack.getCount() > 1) {
if (te.accepts_lava_container(stack)) {
if (stack.is(MineralSmelterTileEntity.BUCKET_STACK.getItem())) { // check how this works with item capabilities or so
if (te.bucket_extraction_possible()) {
if (stack.getCount() > 1) {
int target_stack_index = -1;
for(int i=0; i<player.getInventory().getContainerSize(); ++i) {
if(player.getInventory().getItem(i).isEmpty()) {
for (int i = 0; i < player.getInventory().getContainerSize(); ++i) {
if (player.getInventory().getItem(i).isEmpty()) {
target_stack_index = i;
break;
}
}
if(target_stack_index >= 0) {
if (target_stack_index >= 0) {
te.reset_process();
stack.shrink(1);
player.setItemInHand(hand, stack);
@ -167,60 +172,60 @@ public class EdMineralSmelter
}
}
}
} else if(stack.isEmpty()) {
} else if (stack.isEmpty()) {
final ItemStack istack = te.extract(true);
if(te.phase() > MineralSmelterTileEntity.PHASE_WARMUP) player.setSecondsOnFire(1);
if(!istack.isEmpty()) {
if (te.phase() > MineralSmelterTileEntity.PHASE_WARMUP) player.setSecondsOnFire(1);
if (!istack.isEmpty()) {
player.setItemInHand(hand, te.extract(false));
dirty = true;
}
} else if(te.insert(stack,false)) {
} else if (te.insert(stack, false)) {
stack.shrink(1);
dirty = true;
}
if(dirty) player.getInventory().setChanged();
if (dirty) player.getInventory().setChanged();
return InteractionResult.CONSUME;
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd)
{
if(state.getBlock()!=this) return;
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd) {
if (state.getBlock() != this) return;
ParticleOptions particle = ParticleTypes.SMOKE;
switch(state.getValue(PHASE)) {
switch (state.getValue(PHASE)) {
case MineralSmelterTileEntity.PHASE_WARMUP:
return;
case MineralSmelterTileEntity.PHASE_HOT:
if(rnd.nextInt(10) > 4) return;
if (rnd.nextInt(10) > 4) return;
break;
case MineralSmelterTileEntity.PHASE_MAGMABLOCK:
if(rnd.nextInt(10) > 7) return;
if (rnd.nextInt(10) > 7) return;
particle = ParticleTypes.LARGE_SMOKE;
break;
case MineralSmelterTileEntity.PHASE_LAVA:
if(rnd.nextInt(10) > 2) return;
if (rnd.nextInt(10) > 2) return;
particle = ParticleTypes.LAVA;
break;
default:
return;
}
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xr=rnd.nextDouble()*0.4-0.2, yr=rnd.nextDouble()*0.5, zr=rnd.nextDouble()*0.4-0.2;
world.addParticle(particle, x+xr, y+yr, z+zr, 0.0, 0.0, 0.0);
final double x = 0.5 + pos.getX(), y = 0.5 + pos.getY(), z = 0.5 + pos.getZ();
final double xr = rnd.nextDouble() * 0.4 - 0.2, yr = rnd.nextDouble() * 0.5, zr = rnd.nextDouble() * 0.4 - 0.2;
world.addParticle(particle, x + xr, y + yr, z + zr, 0.0, 0.0, 0.0);
}
@Nullable
private MineralSmelterTileEntity getTe(Level world, BlockPos pos)
{ final BlockEntity te=world.getBlockEntity(pos); return (!(te instanceof MineralSmelterTileEntity)) ? (null) : ((MineralSmelterTileEntity)te); }
private MineralSmelterTileEntity getTe(Level world, BlockPos pos) {
final BlockEntity te = world.getBlockEntity(pos);
return (!(te instanceof MineralSmelterTileEntity)) ? (null) : ((MineralSmelterTileEntity) te);
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class MineralSmelterTileEntity extends StandardEntityBlocks.StandardBlockEntity
{
public static class MineralSmelterTileEntity extends StandardEntityBlocks.StandardBlockEntity {
public static final int NUM_OF_SLOTS = 2;
public static final int TICK_INTERVAL = 20;
public static final int MAX_FLUID_LEVEL = 2000;
@ -242,9 +247,10 @@ public class EdMineralSmelter
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static int heatup_rate = DEFAULT_HEATUP_RATE;
private static int cooldown_rate = 1;
private int tick_timer_;
private int progress_;
private boolean force_block_update_;
static {
accepted_lava_contrainers.add(Items.BUCKET);
}
private final RfEnergy.Battery battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0);
private final LazyOptional<IEnergyStorage> energy_handler_ = battery_.createEnergyHandler();
@ -252,86 +258,85 @@ public class EdMineralSmelter
private final LazyOptional<? extends IFluidHandler> fluid_handler_ = tank_.createOutputFluidHandler();
private final Inventories.StorageInventory main_inventory_;
private final LazyOptional<? extends IItemHandler> item_handler_;
private int tick_timer_;
private int progress_;
private boolean force_block_update_;
static {
accepted_lava_contrainers.add(Items.BUCKET);
}
public static void on_config(int consumption, int heatup_per_second)
{
energy_consumption = Mth.clamp(consumption, 8, 4096);
heatup_rate = Mth.clamp(heatup_per_second, 1, 5);
cooldown_rate = Mth.clamp(heatup_per_second/2, 1, 5);
ModConfig.log("Config mineal smelter: energy consumption:" + energy_consumption + "rf/t, heat-up rate: " + heatup_rate + "%/s.");
}
public MineralSmelterTileEntity(BlockPos pos, BlockState state)
{
public MineralSmelterTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
main_inventory_ = (new Inventories.StorageInventory(this, NUM_OF_SLOTS, 1)).setStackLimit(1);
item_handler_ = Inventories.MappedItemHandler.createGenericHandler(
main_inventory_,
(index,stack)->((index==1) && (phase()!=PHASE_LAVA)),
(index,stack)->((index==0) && (progress_==0) && accepts_input(stack)),
(index,stack)->{},
(index,stack)->{ if(index!=0) reset_process(); }
(index, stack) -> ((index == 1) && (phase() != PHASE_LAVA)),
(index, stack) -> ((index == 0) && (progress_ == 0) && accepts_input(stack)),
(index, stack) -> {
},
(index, stack) -> {
if (index != 0) reset_process();
}
);
}
public int progress()
{ return progress_; }
public static void on_config(int consumption, int heatup_per_second) {
energy_consumption = Mth.clamp(consumption, 8, 4096);
heatup_rate = Mth.clamp(heatup_per_second, 1, 5);
cooldown_rate = Mth.clamp(heatup_per_second / 2, 1, 5);
ModConfig.log("Config mineal smelter: energy consumption:" + energy_consumption + "rf/t, heat-up rate: " + heatup_rate + "%/s.");
}
public int phase()
{
if(progress_ >= 100) return PHASE_LAVA;
if(progress_ >= 90) return PHASE_MAGMABLOCK;
if(progress_ >= 5) return PHASE_HOT;
public int progress() {
return progress_;
}
public int phase() {
if (progress_ >= 100) return PHASE_LAVA;
if (progress_ >= 90) return PHASE_MAGMABLOCK;
if (progress_ >= 5) return PHASE_HOT;
return PHASE_WARMUP;
}
public boolean bucket_extraction_possible()
{ return tank_.getFluidAmount() >= MAX_BUCKET_EXTRACT_FLUID_LEVEL; }
public boolean bucket_extraction_possible() {
return tank_.getFluidAmount() >= MAX_BUCKET_EXTRACT_FLUID_LEVEL;
}
public int comparator_signal()
{ return phase() * 5; }
public int comparator_signal() {
return phase() * 5;
}
private boolean accepts_lava_container(ItemStack stack)
{ return accepted_lava_contrainers.contains(stack.getItem()); }
private boolean accepts_lava_container(ItemStack stack) {
return accepted_lava_contrainers.contains(stack.getItem());
}
private boolean accepts_input(ItemStack stack)
{
if(!main_inventory_.isEmpty()) {
private boolean accepts_input(ItemStack stack) {
if (!main_inventory_.isEmpty()) {
return false;
} else if(bucket_extraction_possible()) {
} else if (bucket_extraction_possible()) {
return accepts_lava_container(stack);
} else {
return (accepted_minerals.contains(stack.getItem())) || (Auxiliaries.isInItemTag(stack.getItem(), new ResourceLocation(Auxiliaries.modid(), "accepted_mineral_smelter_input")));
}
}
public boolean insert(final ItemStack stack, boolean simulate)
{
if(stack.isEmpty() || (!accepts_input(stack))) return false;
if(!simulate) {
public boolean insert(final ItemStack stack, boolean simulate) {
if (stack.isEmpty() || (!accepts_input(stack))) return false;
if (!simulate) {
final ItemStack st = stack.copy();
st.setCount(1);
main_inventory_.setItem(0, st);
if(!accepts_lava_container(stack)) progress_ = 0;
if (!accepts_lava_container(stack)) progress_ = 0;
force_block_update_ = true;
}
return true;
}
public ItemStack extract(boolean simulate)
{
public ItemStack extract(boolean simulate) {
final ItemStack stack = main_inventory_.getItem(1).copy();
if(stack.isEmpty()) return ItemStack.EMPTY;
if(!simulate) reset_process();
if (stack.isEmpty()) return ItemStack.EMPTY;
if (!simulate) reset_process();
return stack;
}
protected void reset_process()
{
protected void reset_process() {
main_inventory_.setItem(0, ItemStack.EMPTY);
main_inventory_.setItem(1, ItemStack.EMPTY);
tank_.clear();
@ -340,35 +345,36 @@ public class EdMineralSmelter
progress_ = 0;
}
public void readnbt(CompoundTag nbt)
{
public void readnbt(CompoundTag nbt) {
main_inventory_.load(nbt);
battery_.load(nbt);
tank_.load(nbt);
progress_ = nbt.getInt("progress");
}
protected void writenbt(CompoundTag nbt)
{
protected void writenbt(CompoundTag nbt) {
main_inventory_.save(nbt);
battery_.save(nbt);
tank_.save(nbt);
nbt.putInt("progress", Mth.clamp(progress_,0 , 100));
nbt.putInt("progress", Mth.clamp(progress_, 0, 100));
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt); }
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt);
}
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt); }
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt);
}
@Override
public void setRemoved()
{
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
fluid_handler_.invalidate();
@ -378,45 +384,43 @@ public class EdMineralSmelter
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
if (capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
public void tick() {
if (--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
BlockState state = level.getBlockState(worldPosition);
if(!(state.getBlock() instanceof MineralSmelterBlock)) return;
if (!(state.getBlock() instanceof MineralSmelterBlock)) return;
boolean dirty = false;
final int last_phase = phase();
final ItemStack istack = main_inventory_.getItem(0);
if(istack.isEmpty() && (tank_.getFluidAmount()<MAX_BUCKET_EXTRACT_FLUID_LEVEL) && (phase()!=PHASE_LAVA)) {
if (istack.isEmpty() && (tank_.getFluidAmount() < MAX_BUCKET_EXTRACT_FLUID_LEVEL) && (phase() != PHASE_LAVA)) {
progress_ = 0;
tank_.clear();
main_inventory_.clearContent();
} else if((battery_.isEmpty()) || (level.hasNeighborSignal(worldPosition))) {
progress_ = Mth.clamp(progress_-cooldown_rate, 0,100);
} else if(progress_ >= 100) {
} else if ((battery_.isEmpty()) || (level.hasNeighborSignal(worldPosition))) {
progress_ = Mth.clamp(progress_ - cooldown_rate, 0, 100);
} else if (progress_ >= 100) {
progress_ = 100;
if(!battery_.draw(energy_consumption*TICK_INTERVAL/20)) battery_.clear();
} else if((phase()>=PHASE_LAVA) || (!istack.isEmpty())) {
if(!battery_.draw(energy_consumption*TICK_INTERVAL)) battery_.clear();
progress_ = Mth.clamp(progress_+heatup_rate, 0, 100);
if (!battery_.draw(energy_consumption * TICK_INTERVAL / 20)) battery_.clear();
} else if ((phase() >= PHASE_LAVA) || (!istack.isEmpty())) {
if (!battery_.draw(energy_consumption * TICK_INTERVAL)) battery_.clear();
progress_ = Mth.clamp(progress_ + heatup_rate, 0, 100);
}
final int new_phase = phase();
if(accepts_lava_container(istack)) {
if (accepts_lava_container(istack)) {
// That stays in the slot until its extracted or somone takes it out.
if(istack.sameItem(BUCKET_STACK)) {
if(!main_inventory_.getItem(1).sameItem(LAVA_BUCKET_STACK)) {
if(bucket_extraction_possible()) {
if (istack.is(BUCKET_STACK.getItem())) {
if (!main_inventory_.getItem(1).is(LAVA_BUCKET_STACK.getItem())) {
if (bucket_extraction_possible()) {
reset_process();
main_inventory_.setItem(1, LAVA_BUCKET_STACK);
level.playSound(null, worldPosition, SoundEvents.BUCKET_FILL_LAVA, SoundSource.BLOCKS, 0.2f, 1.3f);
@ -429,9 +433,9 @@ public class EdMineralSmelter
main_inventory_.setItem(1, istack.copy());
// Out stack -> Somehow the filled container or container with fluid+fluid_level().
}
} else if(new_phase > last_phase) {
} else if (new_phase > last_phase) {
// Heat-up to next phase happened.
switch(new_phase) {
switch (new_phase) {
case PHASE_LAVA -> {
tank_.fill(new FluidStack(Fluids.LAVA, 1000), IFluidHandler.FluidAction.EXECUTE);
main_inventory_.setItem(1, ItemStack.EMPTY);
@ -448,11 +452,11 @@ public class EdMineralSmelter
level.playSound(null, worldPosition, SoundEvents.FIRE_AMBIENT, SoundSource.BLOCKS, 0.2f, 0.8f);
}
}
} else if(new_phase < last_phase) {
} else if (new_phase < last_phase) {
// Cool-down to prev phase happened.
switch(new_phase) {
switch (new_phase) {
case PHASE_MAGMABLOCK -> {
if(tank_.getFluidAmount() < MAX_BUCKET_EXTRACT_FLUID_LEVEL) {
if (tank_.getFluidAmount() < MAX_BUCKET_EXTRACT_FLUID_LEVEL) {
reset_process();
} else {
main_inventory_.setItem(0, MAGMA_STACK.copy());
@ -463,7 +467,7 @@ public class EdMineralSmelter
dirty = true;
}
case PHASE_HOT -> {
if(istack.sameItem(MAGMA_STACK)) {
if (istack.is(MAGMA_STACK.getItem())) {
main_inventory_.setItem(1, new ItemStack(Blocks.OBSIDIAN));
} else {
main_inventory_.setItem(1, new ItemStack(Blocks.COBBLESTONE));
@ -475,18 +479,18 @@ public class EdMineralSmelter
level.playSound(null, worldPosition, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, 0.3f, 0.7f);
}
}
} else if(phase()>=PHASE_LAVA) {
if(tank_.getFluidAmount()<=0) {
} else if (phase() >= PHASE_LAVA) {
if (tank_.getFluidAmount() <= 0) {
reset_process();
level.playSound(null, worldPosition, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, 0.3f, 0.7f);
} else {
// Phase unchanged, fluid transfer check.
FluidStack fs = tank_.getFluid().copy();
if(fs.getAmount() > 100) fs.setAmount(100);
if (fs.getAmount() > 100) fs.setAmount(100);
final int n = Fluidics.fill(level, getBlockPos().below(), Direction.UP, fs);
if(n > 0) {
if (n > 0) {
tank_.drain(n);
if(tank_.isEmpty()) {
if (tank_.isEmpty()) {
final ItemStack prev = main_inventory_.getItem(0);
reset_process();
main_inventory_.setItem(0, prev);
@ -496,13 +500,13 @@ public class EdMineralSmelter
}
}
// Block state
if((force_block_update_ || (state.getValue(MineralSmelterBlock.PHASE) != new_phase))) {
if ((force_block_update_ || (state.getValue(MineralSmelterBlock.PHASE) != new_phase))) {
state = state.setValue(MineralSmelterBlock.PHASE, new_phase);
level.setBlock(worldPosition, state,3|16);
level.setBlock(worldPosition, state, 3 | 16);
level.updateNeighborsAt(getBlockPos(), state.getBlock());
force_block_update_ = false;
}
if(dirty) setChanged();
if (dirty) setChanged();
}
}
}

View file

@ -9,6 +9,11 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.RsSignals;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import dev.zontreck.libzontreck.edlibmc.StandardEntityBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
@ -18,7 +23,7 @@ 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.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -35,24 +40,17 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.RsSignals;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class EdPipeValve
{
public class EdPipeValve {
public static final int CFG_CHECK_VALVE = 0x1;
public static final int CFG_ANALOG_VALVE = 0x2;
public static final int CFG_REDSTONE_CONTROLLED_VALVE = 0x4;
public static void on_config(int container_size_decl, int redstone_slope)
{
public static void on_config(int container_size_decl, int redstone_slope) {
PipeValveTileEntity.fluid_maxflow_mb = Mth.clamp(container_size_decl, 1, 10000);
PipeValveTileEntity.redstone_flow_slope_mb = Mth.clamp(redstone_slope, 1, 10000);
ModConfig.log("Config pipe valve: maxflow:" + PipeValveTileEntity.fluid_maxflow_mb + "mb, redstone amp:" + PipeValveTileEntity.redstone_flow_slope_mb + "mb/sig.");
@ -62,8 +60,7 @@ public class EdPipeValve
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class PipeValveBlock extends StandardBlocks.DirectedWaterLoggable implements StandardEntityBlocks.IStandardEntityBlock<PipeValveTileEntity>
{
public static class PipeValveBlock extends StandardBlocks.DirectedWaterLoggable implements StandardEntityBlocks.IStandardEntityBlock<PipeValveTileEntity> {
public static final BooleanProperty RS_CN_N = BooleanProperty.create("rs_n");
public static final BooleanProperty RS_CN_S = BooleanProperty.create("rs_s");
public static final BooleanProperty RS_CN_E = BooleanProperty.create("rs_e");
@ -72,84 +69,98 @@ public class EdPipeValve
public static final BooleanProperty RS_CN_D = BooleanProperty.create("rs_d");
public final int valve_config;
public PipeValveBlock(long config, int valve_config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB)
{ super(config, builder, unrotatedAABB); this.valve_config = valve_config; }
@Override
@Nullable
public BlockEntity newBlockEntity(BlockPos pos, BlockState state)
{
final BlockEntityType<?> tet = ModContent.getBlockEntityTypeOfBlock("straight_pipe_valve");
return (tet==null) ? null : tet.create(pos, state);
public PipeValveBlock(long config, int valve_config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
super(config, builder, unrotatedAABB);
this.valve_config = valve_config;
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return false; }
@Nullable
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
final BlockEntityType<?> tet = ModContent.getBlockEntityTypeOfBlock("straight_pipe_valve");
return (tet == null) ? null : tet.create(pos, state);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return Shapes.block(); }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return false;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(RS_CN_N, RS_CN_S, RS_CN_E, RS_CN_W, RS_CN_U, RS_CN_D); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return Shapes.block();
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(RS_CN_N, RS_CN_S, RS_CN_E, RS_CN_W, RS_CN_U, RS_CN_D);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(RS_CN_N, false).setValue(RS_CN_S, false).setValue(RS_CN_E, false)
.setValue(RS_CN_W, false).setValue(RS_CN_U, false).setValue(RS_CN_D, false);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos)
{ return get_rsconnector_state(state, world, pos, null); }
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
return get_rsconnector_state(state, world, pos, null);
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{ world.updateNeighborsAt(pos,this); }
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
world.updateNeighborsAt(pos, this);
}
@Override
public BlockState rotate(BlockState state, LevelAccessor world, BlockPos pos, Rotation direction)
{ return get_rsconnector_state(state, world, pos, null); } // don't rotate at all
public BlockState rotate(BlockState state, LevelAccessor world, BlockPos pos, Rotation direction) {
return get_rsconnector_state(state, world, pos, null);
} // don't rotate at all
@Override
public boolean hasSignalConnector(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side)
{ return (side!=null) && (side!=state.getValue(FACING)) && (side!=state.getValue(FACING).getOpposite()); }
public boolean hasSignalConnector(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) {
return (side != null) && (side != state.getValue(FACING)) && (side != state.getValue(FACING).getOpposite());
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
@Override
@SuppressWarnings("deprecation") // public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { return true; }
public boolean isSignalSource(BlockState p_60571_)
{ return true; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
@SuppressWarnings("deprecation")
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side)
{ return 0; }
// public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { return true; }
public boolean isSignalSource(BlockState p_60571_) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side)
{ return 0; }
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
return 0;
}
private BlockState get_rsconnector_state(BlockState state, LevelAccessor world, BlockPos pos, @Nullable BlockPos fromPos)
{
if((valve_config & (CFG_REDSTONE_CONTROLLED_VALVE))==0) return state;
@Override
@SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
return 0;
}
private BlockState get_rsconnector_state(BlockState state, LevelAccessor world, BlockPos pos, @Nullable BlockPos fromPos) {
if ((valve_config & (CFG_REDSTONE_CONTROLLED_VALVE)) == 0) return state;
Direction.Axis bfa = state.getValue(FACING).getAxis();
for(Direction f:Direction.values()) {
for (Direction f : Direction.values()) {
boolean cn = (f.getAxis() != bfa);
if(cn) {
if (cn) {
BlockPos nbp = pos.relative(f);
if((fromPos != null) && (!nbp.equals(fromPos))) continue; // do not change connectors except form the frompos.
if ((fromPos != null) && (!nbp.equals(fromPos)))
continue; // do not change connectors except form the frompos.
BlockState nbs = world.getBlockState(nbp);
if((nbs.getBlock() instanceof PipeValveBlock) || (!nbs.isSignalSource()) || (!RsSignals.hasSignalConnector(nbs, world, nbp, f.getOpposite()))) cn = false;
if ((nbs.getBlock() instanceof PipeValveBlock) || (!nbs.isSignalSource()) || (!RsSignals.hasSignalConnector(nbs, world, nbp, f.getOpposite())))
cn = false;
}
switch (f) {
case NORTH -> state = state.setValue(RS_CN_N, cn);
@ -169,54 +180,49 @@ public class EdPipeValve
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class PipeValveTileEntity extends StandardEntityBlocks.StandardBlockEntity
{
public static class PipeValveTileEntity extends StandardEntityBlocks.StandardBlockEntity {
protected static int fluid_maxflow_mb = 1000;
protected static int redstone_flow_slope_mb = 1000/15;
protected static int redstone_flow_slope_mb = 1000 / 15;
private final Direction block_facing_ = null;
private final LazyOptional<IFluidHandler> back_flow_handler_ = LazyOptional.of(BackFlowHandler::new);
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new MainFlowHandler(this));
private boolean filling_ = false;
private int valve_config_;
public PipeValveTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock("straight_pipe_valve"), pos, state); }
private Direction block_facing()
{
BlockState st = getLevel().getBlockState(getBlockPos());
return (st.getBlock() instanceof PipeValveBlock) ? st.getValue(PipeValveBlock.FACING) : Direction.NORTH;
}
private long valve_config()
{
if(valve_config_ <= 0) {
final Block block = getLevel().getBlockState(getBlockPos()).getBlock();
if(block instanceof PipeValveBlock) valve_config_ = ((PipeValveBlock)block).valve_config;
}
return valve_config_;
public PipeValveTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock("straight_pipe_valve"), pos, state);
}
// BlockEntity -----------------------------------------------------------------------------
private Direction block_facing() {
BlockState st = getLevel().getBlockState(getBlockPos());
return (st.getBlock() instanceof PipeValveBlock) ? st.getValue(PipeValveBlock.FACING) : Direction.NORTH;
}
// ICapabilityProvider --------------------------------------------------------------------
private long valve_config() {
if (valve_config_ <= 0) {
final Block block = getLevel().getBlockState(getBlockPos()).getBlock();
if (block instanceof PipeValveBlock) valve_config_ = ((PipeValveBlock) block).valve_config;
}
return valve_config_;
}
@Override
public void setRemoved()
{
public void setRemoved() {
super.setRemoved();
back_flow_handler_.invalidate();
fluid_handler_.invalidate();
}
// ICapabilityProvider --------------------------------------------------------------------
private final LazyOptional<IFluidHandler> back_flow_handler_ = LazyOptional.of(BackFlowHandler::new);
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new MainFlowHandler(this));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.FLUID_HANDLER) {
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.FLUID_HANDLER) {
Direction bf = block_facing();
if(facing == bf) return back_flow_handler_.cast();
if(facing == bf.getOpposite()) return fluid_handler_.cast();
if (facing == bf) return back_flow_handler_.cast();
if (facing == bf.getOpposite()) return fluid_handler_.cast();
return LazyOptional.empty();
}
return super.getCapability(capability, facing);
@ -225,38 +231,64 @@ public class EdPipeValve
// IFluidHandlers
@Nullable
private IFluidHandler forward_fluid_handler()
{
private IFluidHandler forward_fluid_handler() {
final BlockEntity te = level.getBlockEntity(worldPosition.relative(block_facing()));
if(te == null) return null;
if (te == null) return null;
return te.getCapability(ForgeCapabilities.FLUID_HANDLER, block_facing().getOpposite()).orElse(null);
}
// Forward flow handler --
private static class MainFlowHandler implements IFluidHandler
{
private static class MainFlowHandler implements IFluidHandler {
private final PipeValveTileEntity te;
public MainFlowHandler(PipeValveTileEntity te) { this.te = te; }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank) { return fluid_maxflow_mb; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
@Override public int fill(FluidStack resource, FluidAction action)
{
if(te.filling_) return 0;
final IFluidHandler fh = te.forward_fluid_handler();
if(fh==null) return 0;
FluidStack res = resource.copy();
if((te.valve_config() & CFG_REDSTONE_CONTROLLED_VALVE) != 0) {
int rs = te.level.getBestNeighborSignal(te.worldPosition);
if(rs <= 0) return 0;
if(((te.valve_config() & CFG_ANALOG_VALVE) != 0) && (rs < 15)) res.setAmount(Mth.clamp(rs * redstone_flow_slope_mb, 1, res.getAmount()));
public MainFlowHandler(PipeValveTileEntity te) {
this.te = te;
}
if(res.getAmount() > fluid_maxflow_mb) res.setAmount(fluid_maxflow_mb);
@Override
public int getTanks() {
return 1;
}
@Override
public FluidStack getFluidInTank(int tank) {
return FluidStack.EMPTY;
}
@Override
public int getTankCapacity(int tank) {
return fluid_maxflow_mb;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return true;
}
@Override
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidStack.EMPTY;
}
@Override
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidStack.EMPTY;
}
@Override
public int fill(FluidStack resource, FluidAction action) {
if (te.filling_) return 0;
final IFluidHandler fh = te.forward_fluid_handler();
if (fh == null) return 0;
FluidStack res = resource.copy();
if ((te.valve_config() & CFG_REDSTONE_CONTROLLED_VALVE) != 0) {
int rs = te.level.getBestNeighborSignal(te.worldPosition);
if (rs <= 0) return 0;
if (((te.valve_config() & CFG_ANALOG_VALVE) != 0) && (rs < 15))
res.setAmount(Mth.clamp(rs * redstone_flow_slope_mb, 1, res.getAmount()));
}
if (res.getAmount() > fluid_maxflow_mb) res.setAmount(fluid_maxflow_mb);
te.filling_ = true;
int n_filled = fh.fill(res, action);
te.filling_ = false;
@ -266,15 +298,41 @@ public class EdPipeValve
// Back flow prevention handler --
private static class BackFlowHandler implements IFluidHandler
{
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank) { return 0; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return false; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
private static class BackFlowHandler implements IFluidHandler {
@Override
public int getTanks() {
return 1;
}
@Override
public FluidStack getFluidInTank(int tank) {
return FluidStack.EMPTY;
}
@Override
public int getTankCapacity(int tank) {
return 0;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return false;
}
@Override
public int fill(FluidStack resource, FluidAction action) {
return 0;
}
@Override
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidStack.EMPTY;
}
@Override
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidStack.EMPTY;
}
}
}
}

View file

@ -8,8 +8,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.zontreck.engineerdecor.libmc.*;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -32,7 +33,7 @@ import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType;
@ -54,8 +55,6 @@ import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.items.IItemHandler;
import dev.zontreck.engineerdecor.ModContent;
import wile.engineersdecor.libmc.*;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -63,120 +62,125 @@ import java.util.Arrays;
import java.util.List;
public class EdPlacer
{
public static void on_config()
{}
public class EdPlacer {
public static void on_config() {
}
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class PlacerBlock extends StandardBlocks.Directed implements StandardEntityBlocks.IStandardEntityBlock<PlacerTileEntity>
{
public PlacerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public static class PlacerBlock extends StandardBlocks.Directed implements StandardEntityBlocks.IStandardEntityBlock<PlacerTileEntity> {
public PlacerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return Shapes.block(); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return Shapes.block();
}
@Override
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state)
{ return true; }
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState blockState, Level world, BlockPos pos)
{ return (world.getBlockEntity(pos) instanceof EdPlacer.PlacerTileEntity te) ? RsSignals.fromContainer(te.inventory_) : 0; }
public int getAnalogOutputSignal(BlockState blockState, Level world, BlockPos pos) {
return (world.getBlockEntity(pos) instanceof EdPlacer.PlacerTileEntity te) ? RsSignals.fromContainer(te.inventory_) : 0;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isClientSide) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
if (world.isClientSide) return;
if ((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundTag te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
if(!(world.getBlockEntity(pos) instanceof final PlacerTileEntity te)) return;
if (te_nbt.isEmpty()) return;
if (!(world.getBlockEntity(pos) instanceof final PlacerTileEntity te)) return;
te.readnbt(te_nbt, false);
te.reset_rtstate();
te.setChanged();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion)
{
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks;
if(!(te instanceof PlacerTileEntity)) return stacks;
if(!explosion) {
if (world.isClientSide) return stacks;
if (!(te instanceof PlacerTileEntity)) return stacks;
if (!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundTag te_nbt = ((PlacerTileEntity) te).clear_getnbt();
if(!te_nbt.isEmpty()) {
if (!te_nbt.isEmpty()) {
CompoundTag nbt = new CompoundTag();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((PlacerTileEntity)te).inventory_) {
if(!stack.isEmpty()) stacks.add(stack);
for (ItemStack stack : ((PlacerTileEntity) te).inventory_) {
if (!stack.isEmpty()) stacks.add(stack);
}
((PlacerTileEntity)te).reset_rtstate();
((PlacerTileEntity) te).reset_rtstate();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{ return useOpenGui(state, world, pos, player); }
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof Level) || (world.isClientSide)) return;
BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof PlacerTileEntity)) return;
((PlacerTileEntity)te).block_updated();
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
return useOpenGui(state, world, pos, player);
}
@Override
@SuppressWarnings("deprecation")
public boolean isSignalSource(BlockState state)
{ return true; }
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) {
if (!(world instanceof Level) || (world.isClientSide)) return;
BlockEntity te = world.getBlockEntity(pos);
if (!(te instanceof PlacerTileEntity)) return;
((PlacerTileEntity) te).block_updated();
}
@Override
@SuppressWarnings("deprecation")
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side)
{ return 0; }
public boolean isSignalSource(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side)
{ return 0; }
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
return 0;
}
@Override
@SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
return 0;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class PlacerTileEntity extends StandardEntityBlocks.StandardBlockEntity implements MenuProvider, Nameable
{
public static class PlacerTileEntity extends StandardEntityBlocks.StandardBlockEntity implements MenuProvider, Nameable {
public static final int TICK_INTERVAL = 40;
public static final int NUM_OF_SLOTS = 18;
public static final int NUM_OF_FIELDS = 3;
@ -184,18 +188,42 @@ public class EdPlacer
public static final int LOGIC_INVERTED = 0x01;
public static final int LOGIC_CONTINUOUS = 0x02;
public static final int LOGIC_IGNORE_EXT = 0x04;
///
private boolean block_power_signal_ = false;
private boolean block_power_updated_ = false;
private int logic_ = LOGIC_IGNORE_EXT|LOGIC_CONTINUOUS;
private int current_slot_index_ = 0;
private int tick_timer_ = 0;
private final boolean debug_ = false; // @todo debug stick in `self::use()` toggling.
private final Inventories.StorageInventory inventory_ = new Inventories.StorageInventory(this, NUM_OF_SLOTS, 1);
private final LazyOptional<IItemHandler> item_handler_;
///
private boolean block_power_signal_ = false;
private boolean block_power_updated_ = false;
private int logic_ = LOGIC_IGNORE_EXT | LOGIC_CONTINUOUS;
private int current_slot_index_ = 0;
protected final ContainerData fields = new ContainerData() {
@Override
public int getCount() {
return PlacerTileEntity.NUM_OF_FIELDS;
}
public PlacerTileEntity(BlockPos pos, BlockState state)
{
@Override
public int get(int id) {
return switch (id) {
case 0 -> logic_;
case 1 -> block_power_signal_ ? 1 : 0;
case 2 -> Mth.clamp(current_slot_index_, 0, NUM_OF_SLOTS - 1);
default -> 0;
};
}
@Override
public void set(int id, int value) {
switch (id) {
case 0 -> logic_ = value;
case 1 -> block_power_signal_ = (value != 0);
case 2 -> current_slot_index_ = Mth.clamp(value, 0, NUM_OF_SLOTS - 1);
}
}
};
private int tick_timer_ = 0;
public PlacerTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
item_handler_ = Inventories.MappedItemHandler.createGenericHandler(inventory_,
(stack, slot) -> true,
@ -203,8 +231,11 @@ public class EdPlacer
);
}
public CompoundTag clear_getnbt()
{
private static int next_slot(int i) {
return (i < NUM_OF_SLOTS - 1) ? (i + 1) : 0;
}
public CompoundTag clear_getnbt() {
CompoundTag nbt = new CompoundTag();
writenbt(nbt, false);
inventory_.clearContent();
@ -213,188 +244,164 @@ public class EdPlacer
return nbt;
}
public void reset_rtstate()
{
public void reset_rtstate() {
block_power_signal_ = false;
block_power_updated_ = false;
}
public void readnbt(CompoundTag nbt, boolean update_packet)
{
public void readnbt(CompoundTag nbt, boolean update_packet) {
inventory_.load(nbt);
block_power_signal_ = nbt.getBoolean("powered");
current_slot_index_ = nbt.getInt("act_slot_index");
logic_ = nbt.getInt("logic");
}
protected void writenbt(CompoundTag nbt, boolean update_packet)
{
// BlockEntity ------------------------------------------------------------------------------
protected void writenbt(CompoundTag nbt, boolean update_packet) {
inventory_.save(nbt);
nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("act_slot_index", current_slot_index_);
nbt.putInt("logic", logic_);
}
public void block_updated()
{
public void block_updated() {
boolean powered = level.hasNeighborSignal(worldPosition);
if(block_power_signal_ != powered) block_power_updated_ = true;
if (block_power_signal_ != powered) block_power_updated_ = true;
block_power_signal_ = powered;
if(block_power_updated_) {
if (block_power_updated_) {
tick_timer_ = 1;
} else if(tick_timer_ > 4) {
} else if (tick_timer_ > 4) {
tick_timer_ = 4;
}
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt, false); }
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt, false); }
@Override
public void setRemoved()
{
super.setRemoved();
item_handler_.invalidate();
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt, false);
}
// Namable -----------------------------------------------------------------------------------------------
@Override
public Component getName()
{ return Auxiliaries.localizable(getBlockState().getBlock().getDescriptionId()); }
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt, false);
}
@Override
public boolean hasCustomName()
{ return false; }
public void setRemoved() {
super.setRemoved();
item_handler_.invalidate();
}
@Override
public Component getCustomName()
{ return getName(); }
public Component getName() {
return Auxiliaries.localizable(getBlockState().getBlock().getDescriptionId());
}
// INamedContainerProvider ------------------------------------------------------------------------------
@Override
public Component getDisplayName()
{ return Nameable.super.getDisplayName(); }
public boolean hasCustomName() {
return false;
}
@Override
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player )
{ return new PlacerContainer(id, inventory, inventory_, ContainerLevelAccess.create(level, worldPosition), fields); }
public Component getCustomName() {
return getName();
}
// Fields -----------------------------------------------------------------------------------------------
protected final ContainerData fields = new ContainerData()
{
@Override
public int getCount()
{ return PlacerTileEntity.NUM_OF_FIELDS; }
@Override
public int get(int id)
{
return switch (id) {
case 0 -> logic_;
case 1 -> block_power_signal_ ? 1 : 0;
case 2 -> Mth.clamp(current_slot_index_, 0, NUM_OF_SLOTS - 1);
default -> 0;
};
public Component getDisplayName() {
return Nameable.super.getDisplayName();
}
@Override
public void set(int id, int value)
{
switch (id) {
case 0 -> logic_ = value;
case 1 -> block_power_signal_ = (value != 0);
case 2 -> current_slot_index_ = Mth.clamp(value, 0, NUM_OF_SLOTS - 1);
}
}
};
// Capability export ------------------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
return super.getCapability(capability, facing);
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
return new PlacerContainer(id, inventory, inventory_, ContainerLevelAccess.create(level, worldPosition), fields);
}
// ITickable and aux methods ----------------------------------------------------------------------------
private static int next_slot(int i)
{ return (i<NUM_OF_SLOTS-1) ? (i+1) : 0; }
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
return super.getCapability(capability, facing);
}
private boolean spit_out(Direction facing)
{ return spit_out(facing, false); }
private boolean spit_out(Direction facing) {
return spit_out(facing, false);
}
private boolean spit_out(Direction facing, boolean all)
{
private boolean spit_out(Direction facing, boolean all) {
ItemStack stack = inventory_.getItem(current_slot_index_);
ItemStack drop = stack.copy();
if(!all) {
if (!all) {
stack.shrink(1);
inventory_.setItem(current_slot_index_, stack);
drop.setCount(1);
} else {
inventory_.setItem(current_slot_index_, ItemStack.EMPTY);
}
for(int i=0; i<8; ++i) {
for (int i = 0; i < 8; ++i) {
BlockPos p = worldPosition.relative(facing, i);
if(!level.isEmptyBlock(p)) continue;
level.addFreshEntity(new ItemEntity(level, (p.getX()+0.5), (p.getY()+0.5), (p.getZ()+0.5), drop));
if (!level.isEmptyBlock(p)) continue;
level.addFreshEntity(new ItemEntity(level, (p.getX() + 0.5), (p.getY() + 0.5), (p.getZ() + 0.5), drop));
level.playSound(null, p, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 0.7f, 0.8f);
break;
}
return true;
}
private boolean try_place(Direction facing, boolean triggered)
{
if(level.isClientSide()) return false;
private boolean try_place(Direction facing, boolean triggered) {
if (level.isClientSide()) return false;
BlockPos placement_pos = worldPosition.relative(facing);
if(level.getBlockEntity(placement_pos) != null) return false;
if (level.getBlockEntity(placement_pos) != null) return false;
ItemStack current_stack = ItemStack.EMPTY;
for(int i=0; i<NUM_OF_SLOTS; ++i) {
if(current_slot_index_ >= NUM_OF_SLOTS) current_slot_index_ = 0;
for (int i = 0; i < NUM_OF_SLOTS; ++i) {
if (current_slot_index_ >= NUM_OF_SLOTS) current_slot_index_ = 0;
current_stack = inventory_.getItem(current_slot_index_);
if(!current_stack.isEmpty()) break;
if (!current_stack.isEmpty()) break;
current_slot_index_ = next_slot(current_slot_index_);
}
if(current_stack.isEmpty()) { current_slot_index_ = 0; return false; }
if (current_stack.isEmpty()) {
current_slot_index_ = 0;
return false;
}
boolean no_space = false;
final Item item = current_stack.getItem();
Block block = Block.byItem(item);
if(block == Blocks.AIR) {
if(item != null) {
if(debug_) Auxiliaries.logInfo("Placer spit: No block for item " + Auxiliaries.getResourceLocation(item));
if (block == Blocks.AIR) {
if (item != null) {
if (debug_)
Auxiliaries.logInfo("Placer spit: No block for item " + Auxiliaries.getResourceLocation(item));
return spit_out(facing); // Item not accepted
}
} else if(block instanceof IPlantable) {
if(level.isEmptyBlock(placement_pos)) {
} else if (block instanceof IPlantable) {
if (level.isEmptyBlock(placement_pos)) {
// plant here, block below has to be valid soil.
BlockState soilstate = level.getBlockState(placement_pos.below());
if(!soilstate.getBlock().canSustainPlant(soilstate, level, worldPosition, Direction.UP, (IPlantable)block)) {
if (!soilstate.getBlock().canSustainPlant(soilstate, level, worldPosition, Direction.UP, (IPlantable) block)) {
block = Blocks.AIR;
}
} else {
// adjacent block is the soil, plant above if the soil is valid.
BlockState soilstate = level.getBlockState(placement_pos);
if(soilstate.getBlock() == block) {
if (soilstate.getBlock() == block) {
// The plant is already planted from the case above.
block = Blocks.AIR;
no_space = true;
} else if(!level.isEmptyBlock(placement_pos.above())) {
} else if (!level.isEmptyBlock(placement_pos.above())) {
// If this is the soil an air block is needed above, if that is blocked we can't plant.
block = Blocks.AIR;
no_space = true;
} else if(!soilstate.getBlock().canSustainPlant(soilstate, level, worldPosition, Direction.UP, (IPlantable)block)) {
} else if (!soilstate.getBlock().canSustainPlant(soilstate, level, worldPosition, Direction.UP, (IPlantable) block)) {
// Would be space above, but it's not the right soil for the plant.
block = Blocks.AIR;
} else {
@ -404,19 +411,20 @@ public class EdPlacer
}
} else {
final BlockState current_placement_pos_state = level.getBlockState(placement_pos);
@SuppressWarnings("deprecation")
final boolean replacable = (current_placement_pos_state.getBlock().canBeReplaced(current_placement_pos_state, Fluids.EMPTY)) && (
@SuppressWarnings("deprecation") final boolean replacable = (current_placement_pos_state.getBlock().canBeReplaced(current_placement_pos_state, Fluids.EMPTY)) && (
level.isEmptyBlock(placement_pos) ||
(current_placement_pos_state.getBlock() instanceof IFluidBlock) ||
(current_placement_pos_state.getMaterial().isReplaceable() && (!current_placement_pos_state.getMaterial().isSolid()))
(current_placement_pos_state.canBeReplaced() && (!current_placement_pos_state.isAir()))
);
if((!replacable) || (
(!level.getEntitiesOfClass(Entity.class, new AABB(placement_pos), (Entity e)->{
if(e.isPickable()) return true;
if(triggered) return false;
if((e instanceof ItemEntity)) {
if((e.getDeltaMovement().y() > 0) || (e.getDeltaMovement().y() < -0.5)) return true; // not falling or falling by
if(Math.abs(e.getDeltaMovement().x())+Math.abs(e.getDeltaMovement().z()) > 0) return true; // not straight
if ((!replacable) || (
(!level.getEntitiesOfClass(Entity.class, new AABB(placement_pos), (Entity e) -> {
if (e.isPickable()) return true;
if (triggered) return false;
if ((e instanceof ItemEntity)) {
if ((e.getDeltaMovement().y() > 0) || (e.getDeltaMovement().y() < -0.5))
return true; // not falling or falling by
if (Math.abs(e.getDeltaMovement().x()) + Math.abs(e.getDeltaMovement().z()) > 0)
return true; // not straight
}
return false;
}).isEmpty())
@ -426,86 +434,92 @@ public class EdPlacer
}
}
// println("PLACE " + current_stack + " --> " + block + " at " + placement_pos.subtract(pos) + "( item=" + item + ")");
if(block != Blocks.AIR) {
if (block != Blocks.AIR) {
try {
BlockPlaceContext use_context = null;
{
final FakePlayer placer = net.minecraftforge.common.util.FakePlayerFactory.getMinecraft((ServerLevel)level);
if(placer != null) {
final FakePlayer placer = net.minecraftforge.common.util.FakePlayerFactory.getMinecraft((ServerLevel) level);
if (placer != null) {
ItemStack placement_stack = current_stack.copy();
placement_stack.setCount(1);
ItemStack held = placer.getItemInHand(InteractionHand.MAIN_HAND);
placer.setItemInHand(InteractionHand.MAIN_HAND, placement_stack);
List<Direction> directions = new ArrayList<>(Arrays.asList(Direction.UP, facing.getOpposite()));
for(Direction d:Direction.values()) if(!directions.contains(d)) directions.add(d);
for(Direction d:directions) {
for (Direction d : Direction.values()) if (!directions.contains(d)) directions.add(d);
for (Direction d : directions) {
Vec3 v = Vec3.atCenterOf(placement_pos).subtract(Vec3.atLowerCornerOf(d.getNormal()));
use_context = new BlockPlaceContext(new UseOnContext(placer, InteractionHand.MAIN_HAND, new BlockHitResult(v, d, placement_pos, false)));
if(block.getStateForPlacement(use_context) == null) use_context = null;
if(use_context!=null) break;
if (block.getStateForPlacement(use_context) == null) use_context = null;
if (use_context != null) break;
}
placer.setItemInHand(InteractionHand.MAIN_HAND, held);
}
}
BlockState placement_state = (use_context==null) ? (block.defaultBlockState()) : (block.getStateForPlacement(use_context));
if(placement_state == null) {
if(debug_) Auxiliaries.logInfo("Placer spit: No valid placement state for item " + Auxiliaries.getResourceLocation(item));
BlockState placement_state = (use_context == null) ? (block.defaultBlockState()) : (block.getStateForPlacement(use_context));
if (placement_state == null) {
if (debug_)
Auxiliaries.logInfo("Placer spit: No valid placement state for item " + Auxiliaries.getResourceLocation(item));
return spit_out(facing);
} else if((use_context!=null) && (item instanceof BlockItem)) {
if(((BlockItem)item).place(use_context) != InteractionResult.FAIL) {
} else if ((use_context != null) && (item instanceof BlockItem)) {
if (((BlockItem) item).place(use_context) != InteractionResult.FAIL) {
SoundType stype = block.getSoundType(placement_state, level, worldPosition, null);
if(stype != null) level.playSound(null, placement_pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
if (stype != null)
level.playSound(null, placement_pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume() * 0.6f, stype.getPitch());
} else {
if(level.setBlock(placement_pos, placement_state, 1|2|8)) {
if (level.setBlock(placement_pos, placement_state, 1 | 2 | 8)) {
SoundType stype = block.getSoundType(placement_state, level, worldPosition, null);
if(stype != null) level.playSound(null, placement_pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
if (stype != null)
level.playSound(null, placement_pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume() * 0.6f, stype.getPitch());
}
}
} else {
if(level.setBlock(placement_pos, placement_state, 1|2|8)) {
if (level.setBlock(placement_pos, placement_state, 1 | 2 | 8)) {
SoundType stype = block.getSoundType(placement_state, level, worldPosition, null);
if(stype != null) level.playSound(null, placement_pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
if (stype != null)
level.playSound(null, placement_pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume() * 0.6f, stype.getPitch());
}
}
current_stack.shrink(1);
inventory_.setItem(current_slot_index_, current_stack);
return true;
} catch(Throwable e) {
} catch (Throwable e) {
// The block really needs a player or other issues happened during placement.
// A hard crash should not be fired here, instead spit out the item to indicated that this
// block is not compatible.
Auxiliaries.logger().error("Exception while trying to place " + ((block==null)?(""):(""+block)) + ", spitting out. Exception is: " + e);
Auxiliaries.logger().error("Exception while trying to place " + ((block == null) ? ("") : ("" + block)) + ", spitting out. Exception is: " + e);
try {
level.removeBlock(placement_pos, false);
} catch(Throwable e1) {
Auxiliaries.logger().error("Exception while removing failed block placement " + ((block==null)?(""):(""+block)) + ", spitting out. Exception is: " + e1);
} catch (Throwable e1) {
Auxiliaries.logger().error("Exception while removing failed block placement " + ((block == null) ? ("") : ("" + block)) + ", spitting out. Exception is: " + e1);
}
return spit_out(facing, true);
}
}
if((!no_space) && (!current_stack.isEmpty())) {
if ((!no_space) && (!current_stack.isEmpty())) {
// There is space, but the current plant cannot be planted there, so try next.
for(int i=0; i<NUM_OF_SLOTS; ++i) {
for (int i = 0; i < NUM_OF_SLOTS; ++i) {
current_slot_index_ = next_slot(current_slot_index_);
if(!inventory_.getItem(current_slot_index_).isEmpty()) break;
if (!inventory_.getItem(current_slot_index_).isEmpty()) break;
}
}
return false;
}
@Override
public void tick()
{
public void tick() {
// Tick cycle pre-conditions
if(level.isClientSide) return;
if(--tick_timer_ > 0) return;
if (level.isClientSide) return;
if (--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
// Cycle init
final BlockState state = level.getBlockState(worldPosition);
if(!(state.getBlock() instanceof PlacerBlock)) { block_power_signal_= false; return; }
if (!(state.getBlock() instanceof PlacerBlock)) {
block_power_signal_ = false;
return;
}
final boolean updated = block_power_updated_;
final boolean rssignal = ((logic_ & LOGIC_IGNORE_EXT)!=0) || ((logic_ & LOGIC_INVERTED)!=0)==(!block_power_signal_);
final boolean trigger = ((logic_ & LOGIC_IGNORE_EXT)!=0) || (rssignal && ((updated) || ((logic_ & LOGIC_CONTINUOUS)!=0)));
final boolean rssignal = ((logic_ & LOGIC_IGNORE_EXT) != 0) || ((logic_ & LOGIC_INVERTED) != 0) == (!block_power_signal_);
final boolean trigger = ((logic_ & LOGIC_IGNORE_EXT) != 0) || (rssignal && ((updated) || ((logic_ & LOGIC_CONTINUOUS) != 0)));
final Direction placer_facing = state.getValue(PlacerBlock.FACING);
boolean dirty = updated;
// Trigger edge detection for next cycle
@ -513,12 +527,12 @@ public class EdPlacer
boolean tr = level.hasNeighborSignal(worldPosition);
block_power_updated_ = (block_power_signal_ != tr);
block_power_signal_ = tr;
if(block_power_updated_) dirty = true;
if (block_power_updated_) dirty = true;
}
// Placing
if(trigger && try_place(placer_facing, rssignal && updated)) dirty = true;
if(dirty) setChanged();
if(trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL;
if (trigger && try_place(placer_facing, rssignal && updated)) dirty = true;
if (dirty) setChanged();
if (trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL;
}
}
@ -526,8 +540,7 @@ public class EdPlacer
// Container
//--------------------------------------------------------------------------------------------------------------------
public static class PlacerContainer extends AbstractContainerMenu implements Networking.INetworkSynchronisableContainer
{
public static class PlacerContainer extends AbstractContainerMenu implements Networking.INetworkSynchronisableContainer {
protected static final String QUICK_MOVE_ALL = "quick-move-all";
private static final int PLAYER_INV_START_SLOTNO = PlacerTileEntity.NUM_OF_SLOTS;
private final Player player_;
@ -537,13 +550,11 @@ public class EdPlacer
private final Inventories.InventoryRange player_inventory_range_;
private final Inventories.InventoryRange block_storage_range_;
public final int field(int index) { return fields_.get(index); }
public PlacerContainer(int cid, Inventory player_inventory) {
this(cid, player_inventory, new SimpleContainer(PlacerTileEntity.NUM_OF_SLOTS), ContainerLevelAccess.NULL, new SimpleContainerData(PlacerTileEntity.NUM_OF_FIELDS));
}
public PlacerContainer(int cid, Inventory player_inventory)
{ this(cid, player_inventory, new SimpleContainer(PlacerTileEntity.NUM_OF_SLOTS), ContainerLevelAccess.NULL, new SimpleContainerData(PlacerTileEntity.NUM_OF_FIELDS)); }
private PlacerContainer(int cid, Inventory player_inventory, Container block_inventory, ContainerLevelAccess wpc, ContainerData fields)
{
private PlacerContainer(int cid, Inventory player_inventory, Container block_inventory, ContainerLevelAccess wpc, ContainerData fields) {
super(ModContent.getMenuType("factory_placer"), cid); // @todo: class mapping
fields_ = fields;
wpc_ = wpc;
@ -551,53 +562,58 @@ public class EdPlacer
inventory_ = block_inventory;
block_storage_range_ = new Inventories.InventoryRange(inventory_, 0, PlacerTileEntity.NUM_OF_SLOTS);
player_inventory_range_ = Inventories.InventoryRange.fromPlayerInventory(player_);
int i=-1;
int i = -1;
// device slots (stacks 0 to 17)
for(int y=0; y<3; ++y) {
for(int x=0; x<6; ++x) {
int xpos = 11+x*18, ypos = 9+y*17;
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 6; ++x) {
int xpos = 11 + x * 18, ypos = 9 + y * 17;
addSlot(new Slot(inventory_, ++i, xpos, ypos));
}
}
// player slots
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 9+x*18, 129)); // player slots: 0..8
for (int x = 0; x < 9; ++x) {
addSlot(new Slot(player_inventory, x, 9 + x * 18, 129)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 9+x*18, 71+y*18)); // player slots: 9..35
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 9; ++x) {
addSlot(new Slot(player_inventory, x + y * 9 + 9, 9 + x * 18, 71 + y * 18)); // player slots: 9..35
}
}
this.addDataSlots(fields_); // === Add reference holders
}
@Override
public boolean stillValid(Player player)
{ return inventory_.stillValid(player); }
public final int field(int index) {
return fields_.get(index);
}
@Override
public ItemStack quickMoveStack(Player player, int index)
{
public boolean stillValid(Player player) {
return inventory_.stillValid(player);
}
@Override
public ItemStack quickMoveStack(Player player, int index) {
Slot slot = getSlot(index);
if((slot==null) || (!slot.hasItem())) return ItemStack.EMPTY;
if ((slot == null) || (!slot.hasItem())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getItem();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
if ((index >= 0) && (index < PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!moveItemStackTo(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
if (!moveItemStackTo(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO + 36, false))
return ItemStack.EMPTY;
} else if ((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO + 36)) {
// Player slot
if(!moveItemStackTo(slot_stack, 0, PlacerTileEntity.NUM_OF_SLOTS, false)) return ItemStack.EMPTY;
if (!moveItemStackTo(slot_stack, 0, PlacerTileEntity.NUM_OF_SLOTS, false)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
if (slot_stack.isEmpty()) {
slot.set(ItemStack.EMPTY);
} else {
slot.setChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
if (slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
@ -605,37 +621,36 @@ public class EdPlacer
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundTag nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt); }
public void onGuiAction(CompoundTag nbt) {
Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt);
}
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
public void onGuiAction(String key, int value) {
CompoundTag nbt = new CompoundTag();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt);
}
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String message, CompoundTag nbt)
{
public void onGuiAction(String message, CompoundTag nbt) {
nbt.putString("action", message);
Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundTag nbt)
{}
public void onServerPacketReceived(int windowId, CompoundTag nbt) {
}
@Override
public void onClientPacketReceived(int windowId, Player player, CompoundTag nbt)
{
if(!(inventory_ instanceof Inventories.StorageInventory)) return;
if(!((((Inventories.StorageInventory)inventory_).getBlockEntity()) instanceof PlacerTileEntity te)) return;
if(nbt.contains("action")) {
public void onClientPacketReceived(int windowId, Player player, CompoundTag nbt) {
if (!(inventory_ instanceof Inventories.StorageInventory)) return;
if (!((((Inventories.StorageInventory) inventory_).getBlockEntity()) instanceof PlacerTileEntity te))
return;
if (nbt.contains("action")) {
final int slotId = nbt.contains("slot") ? nbt.getInt("slot") : -1;
boolean changed = false;
switch(nbt.getString("action")) {
switch (nbt.getString("action")) {
case QUICK_MOVE_ALL -> {
if ((slotId >= 0) && (slotId < PLAYER_INV_START_SLOTNO) && (getSlot(slotId).hasItem())) {
changed = block_storage_range_.move(getSlot(slotId).getSlotIndex(), player_inventory_range_, true, false, true, true);
@ -644,14 +659,18 @@ public class EdPlacer
}
}
}
if(changed) {
if (changed) {
inventory_.setChanged();
player.getInventory().setChanged();
broadcastChanges();
}
} else {
if(nbt.contains("logic")) te.logic_ = nbt.getInt("logic");
if(nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger")!=0)) { te.block_power_signal_=true; te.block_power_updated_=true; te.tick_timer_=1; }
if (nbt.contains("logic")) te.logic_ = nbt.getInt("logic");
if (nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger") != 0)) {
te.block_power_signal_ = true;
te.block_power_updated_ = true;
te.tick_timer_ = 1;
}
te.setChanged();
}
@ -663,57 +682,54 @@ public class EdPlacer
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class PlacerGui extends Guis.ContainerGui<PlacerContainer>
{
public PlacerGui(PlacerContainer container, Inventory player_inventory, Component title)
{ super(container, player_inventory, title,"textures/gui/factory_placer_gui.png"); }
public static class PlacerGui extends Guis.ContainerGui<PlacerContainer> {
public PlacerGui(PlacerContainer container, Inventory player_inventory, Component title) {
super(container, player_inventory, title, "textures/gui/factory_placer_gui.png");
}
@Override
public void init()
{
public void init() {
super.init();
{
final Block block = ModContent.getBlock(Auxiliaries.getResourceLocation(getMenu().getType()).getPath().replaceAll("^ct_",""));
final Block block = ModContent.getBlock(Auxiliaries.getResourceLocation(getMenu().getType()).getPath().replaceAll("^ct_", ""));
final String prefix = block.getDescriptionId() + ".tooltips.";
final int x0 = getGuiLeft(), y0 = getGuiTop();
tooltip_.init(
new TooltipDisplay.TipRange(x0+133, y0+49, 9, 9, Component.translatable(prefix + "rssignal")),
new TooltipDisplay.TipRange(x0+145, y0+49, 9, 9, Component.translatable(prefix + "inversion")),
new TooltipDisplay.TipRange(x0+159, y0+49, 9, 9, Component.translatable(prefix + "triggermode"))
new TooltipDisplay.TipRange(x0 + 133, y0 + 49, 9, 9, Component.translatable(prefix + "rssignal")),
new TooltipDisplay.TipRange(x0 + 145, y0 + 49, 9, 9, Component.translatable(prefix + "inversion")),
new TooltipDisplay.TipRange(x0 + 159, y0 + 49, 9, 9, Component.translatable(prefix + "triggermode"))
);
}
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton)
{
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
tooltip_.resetTimer();
PlacerContainer container = getMenu();
int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5);
if((!isHovering(126, 1, 49, 60, mouseX, mouseY))) {
int mx = (int) (mouseX - getGuiLeft() + .5), my = (int) (mouseY - getGuiTop() + .5);
if ((!isHovering(126, 1, 49, 60, mouseX, mouseY))) {
return super.mouseClicked(mouseX, mouseY, mouseButton);
} else if(isHovering(133, 49, 9, 9, mouseX, mouseY)) {
} else if (isHovering(133, 49, 9, 9, mouseX, mouseY)) {
container.onGuiAction("manual_trigger", 1);
} else if(isHovering(145, 49, 9, 9, mouseX, mouseY)) {
final int mask = (PlacerTileEntity.LOGIC_INVERTED|PlacerTileEntity.LOGIC_IGNORE_EXT|PlacerTileEntity.LOGIC_NOT_INVERTED);
final int logic = switch((container.field(0) & mask)) {
} else if (isHovering(145, 49, 9, 9, mouseX, mouseY)) {
final int mask = (PlacerTileEntity.LOGIC_INVERTED | PlacerTileEntity.LOGIC_IGNORE_EXT | PlacerTileEntity.LOGIC_NOT_INVERTED);
final int logic = switch ((container.field(0) & mask)) {
case PlacerTileEntity.LOGIC_NOT_INVERTED -> PlacerTileEntity.LOGIC_INVERTED;
case PlacerTileEntity.LOGIC_INVERTED -> PlacerTileEntity.LOGIC_IGNORE_EXT;
case PlacerTileEntity.LOGIC_IGNORE_EXT -> PlacerTileEntity.LOGIC_NOT_INVERTED;
default -> PlacerTileEntity.LOGIC_IGNORE_EXT;
};
container.onGuiAction("logic", (container.field(0) & (~mask)) | logic);
} else if(isHovering(159, 49, 7, 9, mouseX, mouseY)) {
} else if (isHovering(159, 49, 7, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(0) ^ PlacerTileEntity.LOGIC_CONTINUOUS);
}
return true;
}
@Override
protected void slotClicked(Slot slot, int slotId, int button, ClickType type)
{
protected void slotClicked(Slot slot, int slotId, int button, ClickType type) {
tooltip_.resetTimer();
if((type == ClickType.QUICK_MOVE) && (slot!=null) && slot.hasItem() && Auxiliaries.isShiftDown() && Auxiliaries.isCtrlDown()) {
if ((type == ClickType.QUICK_MOVE) && (slot != null) && slot.hasItem() && Auxiliaries.isShiftDown() && Auxiliaries.isCtrlDown()) {
CompoundTag nbt = new CompoundTag();
nbt.putInt("slot", slotId);
menu.onGuiAction(PlacerContainer.QUICK_MOVE_ALL, nbt);
@ -723,31 +739,30 @@ public class EdPlacer
}
@Override
protected void renderBgWidgets(PoseStack mx, float partialTicks, int mouseX, int mouseY)
{
final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize();
protected void renderBgWidgets(GuiGraphics mx, float partialTicks, int mouseX, int mouseY) {
final int x0 = getGuiLeft(), y0 = getGuiTop(), w = getXSize(), h = getYSize();
PlacerContainer container = getMenu();
// active slot
{
int slot_index = container.field(2);
if((slot_index < 0) || (slot_index >= PlacerTileEntity.NUM_OF_SLOTS)) slot_index = 0;
int x = (x0+10+((slot_index % 6) * 18));
int y = (y0+8+((slot_index / 6) * 17));
blit(mx, x, y, 200, 8, 18, 18);
if ((slot_index < 0) || (slot_index >= PlacerTileEntity.NUM_OF_SLOTS)) slot_index = 0;
int x = (x0 + 10 + ((slot_index % 6) * 18));
int y = (y0 + 8 + ((slot_index / 6) * 17));
mx.blit(getBackgroundImage(), x, y, 200, 8, 18, 18);
}
// redstone input
{
if(container.field(1) != 0) {
blit(mx, x0+133, y0+49, 217, 49, 9, 9);
if (container.field(1) != 0) {
mx.blit(getBackgroundImage(), x0 + 133, y0 + 49, 217, 49, 9, 9);
}
}
// trigger logic
{
int inverter_offset_x = ((container.field(0) & PlacerTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0;
int inverter_offset_y = ((container.field(0) & PlacerTileEntity.LOGIC_IGNORE_EXT) != 0) ? 10 : 0;
blit(mx, x0+145, y0+49, 177+inverter_offset_x, 49+inverter_offset_y, 9, 9);
int pulse_mode_offset = ((container.field(0) & PlacerTileEntity.LOGIC_CONTINUOUS ) != 0) ? 9 : 0;
blit(mx, x0+159, y0+49, 199+pulse_mode_offset, 49, 9, 9);
mx.blit(getBackgroundImage(), x0 + 145, y0 + 49, 177 + inverter_offset_x, 49 + inverter_offset_y, 9, 9);
int pulse_mode_offset = ((container.field(0) & PlacerTileEntity.LOGIC_CONTINUOUS) != 0) ? 9 : 0;
mx.blit(getBackgroundImage(), x0 + 159, y0 + 49, 199 + pulse_mode_offset, 49, 9, 9);
}
}
}

View file

@ -8,6 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
@ -33,130 +35,44 @@ 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 dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
public class EdRoofBlock extends StandardBlocks.HorizontalWaterLoggable
{
public class EdRoofBlock extends StandardBlocks.HorizontalWaterLoggable {
public static final EnumProperty<StairsShape> SHAPE = BlockStateProperties.STAIRS_SHAPE;
public static final EnumProperty<Half> HALF = BlockStateProperties.HALF;
private final VoxelShape[][][] shape_cache_;
public EdRoofBlock(long config, BlockBehaviour.Properties properties)
{ this(config, properties.dynamicShape(), Shapes.empty(), Shapes.empty()); }
public EdRoofBlock(long config, BlockBehaviour.Properties properties) {
this(config, properties.dynamicShape(), Shapes.empty(), Shapes.empty());
}
public EdRoofBlock(long config, BlockBehaviour.Properties properties, VoxelShape add, VoxelShape cut)
{
super(config, properties, Auxiliaries.getPixeledAABB(0, 0,0,16, 8, 16));
public EdRoofBlock(long config, BlockBehaviour.Properties properties, VoxelShape add, VoxelShape cut) {
super(config, properties, Auxiliaries.getPixeledAABB(0, 0, 0, 16, 8, 16));
registerDefaultState(super.defaultBlockState().setValue(HORIZONTAL_FACING, Direction.NORTH).setValue(SHAPE, StairsShape.STRAIGHT));
shape_cache_ = makeShapes(add, cut);
}
@Override
@SuppressWarnings("deprecation")
public boolean useShapeForLightOcclusion(BlockState state)
{ return false; }
@OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation")
public float getShadeBrightness(BlockState state, BlockGetter world, BlockPos pos)
{ return 0.98f; }
@Override
@SuppressWarnings("deprecation")
public int getLightBlock(BlockState state, BlockGetter world, BlockPos pos)
{ return 1; }
@Override
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context)
{ return shape_cache_[state.getValue(HALF).ordinal()][state.getValue(HORIZONTAL_FACING).get3DDataValue()][state.getValue(SHAPE).ordinal()]; }
@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(SHAPE, HALF); }
@Override
public FluidState getFluidState(BlockState state)
{ return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state); }
@Override
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type)
{ return false; }
@Override
public BlockState getStateForPlacement(BlockPlaceContext context)
{
BlockPos pos = context.getClickedPos();
Direction face = context.getClickedFace();
BlockState state = defaultBlockState()
.setValue(HORIZONTAL_FACING, context.getHorizontalDirection())
.setValue(HALF, (face == Direction.DOWN) ? Half.TOP : Half.BOTTOM)
.setValue(WATERLOGGED, context.getLevel().getFluidState(pos).getType()==Fluids.WATER);
return state.setValue(SHAPE, getStairsShapeProperty(state, context.getLevel(), pos));
private static boolean isRoofBlock(BlockState state) {
return (state.getBlock() instanceof EdRoofBlock);
}
@Override
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos)
{
if(state.getValue(WATERLOGGED)) world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
return (facing.getAxis().isHorizontal()) ? (state.setValue(SHAPE, getStairsShapeProperty(state, world, pos))) : (super.updateShape(state, facing, facingState, world, pos, facingPos));
}
@Override
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 where)
{
if((where==Mirror.LEFT_RIGHT) && (state.getValue(HORIZONTAL_FACING).getAxis()==Direction.Axis.Z)) {
return switch (state.getValue(SHAPE)) {
case INNER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_RIGHT);
case INNER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_LEFT);
case OUTER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_RIGHT);
case OUTER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_LEFT);
default -> state.rotate(Rotation.CLOCKWISE_180);
};
} else if((where==Mirror.FRONT_BACK) && (state.getValue(HORIZONTAL_FACING).getAxis() == Direction.Axis.X)) {
return switch (state.getValue(SHAPE)) {
case INNER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_LEFT);
case INNER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_RIGHT);
case OUTER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_RIGHT);
case OUTER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_LEFT);
case STRAIGHT -> state.rotate(Rotation.CLOCKWISE_180);
};
}
return super.mirror(state, where);
}
private static boolean isRoofBlock(BlockState state)
{ return (state.getBlock() instanceof EdRoofBlock); }
private static boolean isOtherRoofState(BlockState state, BlockGetter world, BlockPos pos, Direction facing)
{
private static boolean isOtherRoofState(BlockState state, BlockGetter world, BlockPos pos, Direction facing) {
BlockState st = world.getBlockState(pos.relative(facing));
return (!isRoofBlock(st)) || (st.getValue(HORIZONTAL_FACING) != state.getValue(HORIZONTAL_FACING));
}
private static VoxelShape[][][] makeShapes(VoxelShape add, VoxelShape cut)
{
private static VoxelShape[][][] makeShapes(VoxelShape add, VoxelShape cut) {
VoxelShape[][][] shapes = new VoxelShape[2][6][5];
for(int half_index=0; half_index<Half.values().length; ++half_index) {
for(int direction_index=0; direction_index<Direction.values().length; ++direction_index) {
for(int stairs_shape_index=0; stairs_shape_index<StairsShape.values().length; ++stairs_shape_index) {
for (int half_index = 0; half_index < Half.values().length; ++half_index) {
for (int direction_index = 0; direction_index < Direction.values().length; ++direction_index) {
for (int stairs_shape_index = 0; stairs_shape_index < StairsShape.values().length; ++stairs_shape_index) {
VoxelShape shape = makeShape(half_index, direction_index, stairs_shape_index);
try {
// Only in case something changes and this fails, log but do not prevent the game from starting.
// Roof shapes are not the most important thing in the world.
if(!add.isEmpty()) shape = Shapes.joinUnoptimized(shape, add, BooleanOp.OR);
if(!cut.isEmpty()) shape = Shapes.joinUnoptimized(shape, cut, BooleanOp.ONLY_FIRST);
} catch(Throwable ex) {
if (!add.isEmpty()) shape = Shapes.joinUnoptimized(shape, add, BooleanOp.OR);
if (!cut.isEmpty()) shape = Shapes.joinUnoptimized(shape, cut, BooleanOp.ONLY_FIRST);
} catch (Throwable ex) {
Auxiliaries.logError("Failed to cut shape using Boolean function. This is bug.");
}
shapes[half_index][direction_index][stairs_shape_index] = shape;
@ -166,28 +82,27 @@ public class EdRoofBlock extends StandardBlocks.HorizontalWaterLoggable
return shapes;
}
private static VoxelShape makeShape(int half_index, int direction_index, int stairs_shape_index)
{
private static VoxelShape makeShape(int half_index, int direction_index, int stairs_shape_index) {
AABB[] straight = new AABB[]{
Auxiliaries.getPixeledAABB( 0, 0, 0, 16, 4, 16),
Auxiliaries.getPixeledAABB( 4, 4, 0, 16, 8, 16),
Auxiliaries.getPixeledAABB( 8, 8, 0, 16, 12, 16),
Auxiliaries.getPixeledAABB(0, 0, 0, 16, 4, 16),
Auxiliaries.getPixeledAABB(4, 4, 0, 16, 8, 16),
Auxiliaries.getPixeledAABB(8, 8, 0, 16, 12, 16),
Auxiliaries.getPixeledAABB(12, 12, 0, 16, 16, 16)
};
AABB[] pyramid = new AABB[]{
Auxiliaries.getPixeledAABB( 0, 0, 0, 16, 4, 16),
Auxiliaries.getPixeledAABB( 4, 4, 4, 16, 8, 16),
Auxiliaries.getPixeledAABB( 8, 8, 8, 16, 12, 16),
Auxiliaries.getPixeledAABB(0, 0, 0, 16, 4, 16),
Auxiliaries.getPixeledAABB(4, 4, 4, 16, 8, 16),
Auxiliaries.getPixeledAABB(8, 8, 8, 16, 12, 16),
Auxiliaries.getPixeledAABB(12, 12, 12, 16, 16, 16)
};
final Half half = Half.values()[half_index];
if(half==Half.TOP) {
if (half == Half.TOP) {
straight = Auxiliaries.getMirroredAABB(straight, Direction.Axis.Y);
pyramid = Auxiliaries.getMirroredAABB(pyramid, Direction.Axis.Y);
}
Direction direction = Direction.from3DDataValue(direction_index);
if((direction==Direction.UP) || (direction==Direction.DOWN)) return Shapes.block();
direction_index = (direction.get2DDataValue()+1) & 0x03; // ref NORTH -> EAST for stairs compliancy.
if ((direction == Direction.UP) || (direction == Direction.DOWN)) return Shapes.block();
direction_index = (direction.get2DDataValue() + 1) & 0x03; // ref NORTH -> EAST for stairs compliancy.
final StairsShape stairs = StairsShape.values()[stairs_shape_index];
return switch (stairs) {
case STRAIGHT -> Auxiliaries.getUnionShape(Auxiliaries.getYRotatedAABB(straight, direction_index));
@ -204,27 +119,115 @@ public class EdRoofBlock extends StandardBlocks.HorizontalWaterLoggable
};
}
private static StairsShape getStairsShapeProperty(BlockState state, BlockGetter world, BlockPos pos)
{
private static StairsShape getStairsShapeProperty(BlockState state, BlockGetter world, BlockPos pos) {
Direction direction = state.getValue(HORIZONTAL_FACING);
{
BlockState ns = world.getBlockState(pos.relative(direction));
if(isRoofBlock(ns) && (state.getValue(HALF) == ns.getValue(HALF))) {
if (isRoofBlock(ns) && (state.getValue(HALF) == ns.getValue(HALF))) {
Direction nf = ns.getValue(HORIZONTAL_FACING);
if(nf.getAxis() != state.getValue(HORIZONTAL_FACING).getAxis() && isOtherRoofState(state, world, pos, nf.getOpposite())) {
if (nf.getAxis() != state.getValue(HORIZONTAL_FACING).getAxis() && isOtherRoofState(state, world, pos, nf.getOpposite())) {
return (nf == direction.getCounterClockWise()) ? StairsShape.OUTER_LEFT : StairsShape.OUTER_RIGHT;
}
}
}
{
BlockState ns = world.getBlockState(pos.relative(direction.getOpposite()));
if(isRoofBlock(ns) && (state.getValue(HALF) == ns.getValue(HALF))) {
if (isRoofBlock(ns) && (state.getValue(HALF) == ns.getValue(HALF))) {
Direction nf = ns.getValue(HORIZONTAL_FACING);
if(nf.getAxis() != state.getValue(HORIZONTAL_FACING).getAxis() && isOtherRoofState(state, world, pos, nf)) {
if (nf.getAxis() != state.getValue(HORIZONTAL_FACING).getAxis() && isOtherRoofState(state, world, pos, nf)) {
return (nf == direction.getCounterClockWise()) ? StairsShape.INNER_LEFT : StairsShape.INNER_RIGHT;
}
}
}
return StairsShape.STRAIGHT;
}
@Override
@SuppressWarnings("deprecation")
public boolean useShapeForLightOcclusion(BlockState state) {
return false;
}
@OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation")
public float getShadeBrightness(BlockState state, BlockGetter world, BlockPos pos) {
return 0.98f;
}
@Override
@SuppressWarnings("deprecation")
public int getLightBlock(BlockState state, BlockGetter world, BlockPos pos) {
return 1;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
return shape_cache_[state.getValue(HALF).ordinal()][state.getValue(HORIZONTAL_FACING).get3DDataValue()][state.getValue(SHAPE).ordinal()];
}
@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(SHAPE, HALF);
}
@Override
public FluidState getFluidState(BlockState state) {
return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
}
@Override
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) {
return false;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockPos pos = context.getClickedPos();
Direction face = context.getClickedFace();
BlockState state = defaultBlockState()
.setValue(HORIZONTAL_FACING, context.getHorizontalDirection())
.setValue(HALF, (face == Direction.DOWN) ? Half.TOP : Half.BOTTOM)
.setValue(WATERLOGGED, context.getLevel().getFluidState(pos).getType() == Fluids.WATER);
return state.setValue(SHAPE, getStairsShapeProperty(state, context.getLevel(), pos));
}
@Override
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
if (state.getValue(WATERLOGGED)) world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
return (facing.getAxis().isHorizontal()) ? (state.setValue(SHAPE, getStairsShapeProperty(state, world, pos))) : (super.updateShape(state, facing, facingState, world, pos, facingPos));
}
@Override
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 where) {
if ((where == Mirror.LEFT_RIGHT) && (state.getValue(HORIZONTAL_FACING).getAxis() == Direction.Axis.Z)) {
return switch (state.getValue(SHAPE)) {
case INNER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_RIGHT);
case INNER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_LEFT);
case OUTER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_RIGHT);
case OUTER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_LEFT);
default -> state.rotate(Rotation.CLOCKWISE_180);
};
} else if ((where == Mirror.FRONT_BACK) && (state.getValue(HORIZONTAL_FACING).getAxis() == Direction.Axis.X)) {
return switch (state.getValue(SHAPE)) {
case INNER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_LEFT);
case INNER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.INNER_RIGHT);
case OUTER_LEFT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_RIGHT);
case OUTER_RIGHT -> state.rotate(Rotation.CLOCKWISE_180).setValue(SHAPE, StairsShape.OUTER_LEFT);
case STRAIGHT -> state.rotate(Rotation.CLOCKWISE_180);
};
}
return super.mirror(state, where);
}
}

View file

@ -8,6 +8,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -16,8 +19,8 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -29,199 +32,193 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Overlay;
import dev.zontreck.engineerdecor.libmc.RfEnergy;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class EdSolarPanel
{
public class EdSolarPanel {
public static final int DEFAULT_PEAK_POWER = 40;
private static int peak_power_per_tick_ = DEFAULT_PEAK_POWER;
private static int max_power_storage_ = 64000;
private static int max_feed_power = 4096;
private static int feeding_threshold = max_power_storage_/5;
private static int balancing_threshold = max_power_storage_/10;
private static int feeding_threshold = max_power_storage_ / 5;
private static int balancing_threshold = max_power_storage_ / 10;
public static void on_config(int peak_power_per_tick, int battery_capacity, int max_feed_in_power)
{
public static void on_config(int peak_power_per_tick, int battery_capacity, int max_feed_in_power) {
final int t = SolarPanelTileEntity.TICK_INTERVAL;
peak_power_per_tick_ = Mth.clamp(peak_power_per_tick, 12, 8192);
feeding_threshold = Math.max(max_power_storage_/5, 1000);
balancing_threshold = Math.max(max_power_storage_/10, 1000);
feeding_threshold = Math.max(max_power_storage_ / 5, 1000);
balancing_threshold = Math.max(max_power_storage_ / 10, 1000);
max_power_storage_ = battery_capacity;
max_feed_power = max_feed_in_power * t;
ModConfig.log("Config small solar panel: Peak production:" + peak_power_per_tick_ + "/t, capacity:" + max_power_storage_ + "rf, max-feed:" + (max_feed_power/t) + "rf/t");
ModConfig.log("Config small solar panel: Peak production:" + peak_power_per_tick_ + "/t, capacity:" + max_power_storage_ + "rf, max-feed:" + (max_feed_power / t) + "rf/t");
}
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class SolarPanelBlock extends StandardBlocks.Cutout implements StandardEntityBlocks.IStandardEntityBlock<SolarPanelTileEntity>
{
public static class SolarPanelBlock extends StandardBlocks.Cutout implements StandardEntityBlocks.IStandardEntityBlock<SolarPanelTileEntity> {
public static final IntegerProperty EXPOSITION = IntegerProperty.create("exposition", 0, 4);
public SolarPanelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB)
{
public SolarPanelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
super(config, builder, unrotatedAABB);
registerDefaultState(super.defaultBlockState().setValue(EXPOSITION, 1));
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(EXPOSITION); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(EXPOSITION);
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (world.isClientSide()) return InteractionResult.SUCCESS;
BlockEntity te = world.getBlockEntity(pos);
if(te instanceof SolarPanelTileEntity) ((SolarPanelTileEntity)te).state_message(player);
if (te instanceof SolarPanelTileEntity) ((SolarPanelTileEntity) te).state_message(player);
return InteractionResult.CONSUME;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class SolarPanelTileEntity extends StandardEntityBlocks.StandardBlockEntity
{
public static class SolarPanelTileEntity extends StandardEntityBlocks.StandardBlockEntity {
public static final int TICK_INTERVAL = 4;
public static final int ACCUMULATION_INTERVAL = 8;
private static final Direction[] transfer_directions_ = {Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH };
private static final Direction[] transfer_directions_ = {Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH};
private final RfEnergy.Battery battery_ = new RfEnergy.Battery(max_power_storage_, 0, 1024);
private final LazyOptional<IEnergyStorage> energy_handler_ = battery_.createEnergyHandler();
private int tick_timer_ = 0;
private int recalc_timer_ = 0;
private int current_production_ = 0;
private int current_feedin_ = 0;
private boolean output_enabled_ = false;
private final RfEnergy.Battery battery_ = new RfEnergy.Battery(max_power_storage_, 0, 1024);
private final LazyOptional<IEnergyStorage> energy_handler_ = battery_.createEnergyHandler();
//------------------------------------------------------------------------------------------------------------------
public SolarPanelTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); }
public SolarPanelTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
public void readnbt(CompoundTag nbt, boolean update_packet)
{ battery_.load(nbt); }
public void readnbt(CompoundTag nbt, boolean update_packet) {
battery_.load(nbt);
}
protected void writenbt(CompoundTag nbt, boolean update_packet)
{ battery_.save(nbt); }
protected void writenbt(CompoundTag nbt, boolean update_packet) {
battery_.save(nbt);
}
public void state_message(Player player)
{
String soc = Integer.toString(Mth.clamp((battery_.getEnergyStored()*100/max_power_storage_),0,100));
public void state_message(Player player) {
String soc = Integer.toString(Mth.clamp((battery_.getEnergyStored() * 100 / max_power_storage_), 0, 100));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_solar_panel.status", soc, max_power_storage_, current_production_, current_feedin_));
}
// ICapabilityProvider ---------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt, false); }
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt, false);
}
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt, false); }
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt, false);
}
@Override
public void setRemoved()
{
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
}
@Override
public void tick()
{
if((level.isClientSide) || (--tick_timer_ > 0)) return;
public void tick() {
if ((level.isClientSide) || (--tick_timer_ > 0)) return;
tick_timer_ = TICK_INTERVAL;
BlockState state = level.getBlockState(worldPosition);
if(!(state.getBlock() instanceof SolarPanelBlock)) return;
if (!(state.getBlock() instanceof SolarPanelBlock)) return;
current_feedin_ = 0;
final List<SolarPanelTileEntity> adjacent_panels = new ArrayList<>();
if(output_enabled_) {
for(int i=0; (i<transfer_directions_.length) && (!battery_.isEmpty()); ++i) {
if (output_enabled_) {
for (int i = 0; (i < transfer_directions_.length) && (!battery_.isEmpty()); ++i) {
final Direction f = transfer_directions_[i];
BlockEntity te = level.getBlockEntity(worldPosition.relative(f));
if(te==null) continue;
if (te == null) continue;
IEnergyStorage es = te.getCapability(ForgeCapabilities.ENERGY, f.getOpposite()).orElse(null);
if(es==null) continue;
if(!es.canReceive()) {
if(!(te instanceof SolarPanelTileEntity)) continue;
adjacent_panels.add((SolarPanelTileEntity)te);
if (es == null) continue;
if (!es.canReceive()) {
if (!(te instanceof SolarPanelTileEntity)) continue;
adjacent_panels.add((SolarPanelTileEntity) te);
continue;
}
final int feed_power = (battery_.getEnergyStored() > (max_power_storage_/10)) ? max_feed_power : Math.max(current_production_*2, (peak_power_per_tick_/4));
final int feed_power = (battery_.getEnergyStored() > (max_power_storage_ / 10)) ? max_feed_power : Math.max(current_production_ * 2, (peak_power_per_tick_ / 4));
final int fed = es.receiveEnergy(Math.min(battery_.getEnergyStored(), feed_power * TICK_INTERVAL), false);
battery_.draw(fed);
current_feedin_ += fed;
}
}
current_feedin_ /= TICK_INTERVAL;
if((current_feedin_ <= 0) && ((battery_.getEnergyStored() >= balancing_threshold) || (current_production_ <= 0))) {
for(SolarPanelTileEntity panel: adjacent_panels) {
if(panel.battery_.getEnergyStored() >= (battery_.getEnergyStored()-balancing_threshold)) continue;
if ((current_feedin_ <= 0) && ((battery_.getEnergyStored() >= balancing_threshold) || (current_production_ <= 0))) {
for (SolarPanelTileEntity panel : adjacent_panels) {
if (panel.battery_.getEnergyStored() >= (battery_.getEnergyStored() - balancing_threshold))
continue;
panel.battery_.setEnergyStored(panel.battery_.getEnergyStored() + balancing_threshold);
battery_.setEnergyStored(battery_.getEnergyStored() - balancing_threshold);
if(battery_.getEnergyStored() < balancing_threshold) break;
if (battery_.getEnergyStored() < balancing_threshold) break;
}
}
if(!level.canSeeSkyFromBelowWater(worldPosition)) {
if (!level.canSeeSkyFromBelowWater(worldPosition)) {
tick_timer_ = TICK_INTERVAL * 10;
current_production_ = 0;
if((!battery_.isEmpty())) output_enabled_ = true;
if(state.getValue((SolarPanelBlock.EXPOSITION))!=2) level.setBlockAndUpdate(worldPosition, state.setValue(SolarPanelBlock.EXPOSITION, 2));
if ((!battery_.isEmpty())) output_enabled_ = true;
if (state.getValue((SolarPanelBlock.EXPOSITION)) != 2)
level.setBlockAndUpdate(worldPosition, state.setValue(SolarPanelBlock.EXPOSITION, 2));
return;
}
if(battery_.isEmpty()) output_enabled_ = false;
if(--recalc_timer_ > 0) return;
recalc_timer_ = ACCUMULATION_INTERVAL + ((int)(Math.random()+.5));
int theta = ((((int)(level.getSunAngle(1f) * (180.0/Math.PI)))+90) % 360);
if (battery_.isEmpty()) output_enabled_ = false;
if (--recalc_timer_ > 0) return;
recalc_timer_ = ACCUMULATION_INTERVAL + ((int) (Math.random() + .5));
int theta = ((((int) (level.getSunAngle(1f) * (180.0 / Math.PI))) + 90) % 360);
int e = 2;
if(theta > 340) e = 2;
else if(theta < 45) e = 0;
else if(theta < 80) e = 1;
else if(theta < 100) e = 2;
else if(theta < 135) e = 3;
else if(theta < 190) e = 4;
if (theta > 340) e = 2;
else if (theta < 45) e = 0;
else if (theta < 80) e = 1;
else if (theta < 100) e = 2;
else if (theta < 135) e = 3;
else if (theta < 190) e = 4;
BlockState nstate = state.setValue(SolarPanelBlock.EXPOSITION, e);
if(nstate != state) level.setBlock(worldPosition, nstate, 1|2);
final double eff = (1.0-((level.getRainLevel(1f)*0.6)+(level.getThunderLevel(1f)*0.3)));
final double ll = ((double)(level.getLightEngine().getLayerListener(LightLayer.SKY).getLightValue(getBlockPos())))/15;
final double rf = Math.sin((Math.PI/2) * Math.sqrt(((double)(((theta<0)||(theta>180))?(0):((theta>90)?(180-theta):(theta))))/90));
current_production_ = (int)(Math.min(rf*rf*eff*ll, 1) * peak_power_per_tick_);
battery_.setEnergyStored(Math.min(battery_.getEnergyStored() + (current_production_*(TICK_INTERVAL*ACCUMULATION_INTERVAL)), max_power_storage_));
if(battery_.getEnergyStored() >= (feeding_threshold)) output_enabled_ = true;
if (nstate != state) level.setBlock(worldPosition, nstate, 1 | 2);
final double eff = (1.0 - ((level.getRainLevel(1f) * 0.6) + (level.getThunderLevel(1f) * 0.3)));
final double ll = ((double) (level.getLightEngine().getLayerListener(LightLayer.SKY).getLightValue(getBlockPos()))) / 15;
final double rf = Math.sin((Math.PI / 2) * Math.sqrt(((double) (((theta < 0) || (theta > 180)) ? (0) : ((theta > 90) ? (180 - theta) : (theta)))) / 90));
current_production_ = (int) (Math.min(rf * rf * eff * ll, 1) * peak_power_per_tick_);
battery_.setEnergyStored(Math.min(battery_.getEnergyStored() + (current_production_ * (TICK_INTERVAL * ACCUMULATION_INTERVAL)), max_power_storage_));
if (battery_.getEnergyStored() >= (feeding_threshold)) output_enabled_ = true;
}
}
}

View file

@ -8,6 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.Inventories;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
@ -26,30 +28,28 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Inventories;
import javax.annotation.Nullable;
import java.util.Arrays;
public class EdStraightPoleBlock extends StandardBlocks.DirectedWaterLoggable
{
public class EdStraightPoleBlock extends StandardBlocks.DirectedWaterLoggable {
private final EdStraightPoleBlock default_pole;
public EdStraightPoleBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB, @Nullable EdStraightPoleBlock defaultPole)
{ super(config, builder, unrotatedAABB); default_pole=(defaultPole==null) ? (this) : (defaultPole); }
public EdStraightPoleBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB, @Nullable EdStraightPoleBlock defaultPole) {
super(config, builder, unrotatedAABB);
default_pole = (defaultPole == null) ? (this) : (defaultPole);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction facing = context.getClickedFace();
BlockState state = super.getStateForPlacement(context).setValue(FACING, facing);
if((config & StandardBlocks.CFG_FLIP_PLACEMENT_IF_SAME) != 0) {
if ((config & StandardBlocks.CFG_FLIP_PLACEMENT_IF_SAME) != 0) {
Level world = context.getLevel();
BlockPos pos = context.getClickedPos();
if(world.getBlockState(pos.relative(facing.getOpposite())).getBlock() instanceof EdStraightPoleBlock) {
if (world.getBlockState(pos.relative(facing.getOpposite())).getBlock() instanceof EdStraightPoleBlock) {
state = state.setValue(FACING, state.getValue(FACING).getOpposite());
}
}
@ -58,27 +58,27 @@ public class EdStraightPoleBlock extends StandardBlocks.DirectedWaterLoggable
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if((hit.getDirection().getAxis() == state.getValue(FACING).getAxis())) return InteractionResult.PASS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if ((hit.getDirection().getAxis() == state.getValue(FACING).getAxis())) return InteractionResult.PASS;
final ItemStack held_stack = player.getItemInHand(hand);
if((held_stack.isEmpty()) || (!(held_stack.getItem() instanceof BlockItem))) return InteractionResult.PASS;
if(!(((BlockItem)(held_stack.getItem())).getBlock() instanceof EdStraightPoleBlock)) return InteractionResult.PASS;
if(held_stack.getItem() != default_pole.asItem()) return InteractionResult.sidedSuccess(world.isClientSide());
final Block held_block = ((BlockItem)(held_stack.getItem())).getBlock();
if ((held_stack.isEmpty()) || (!(held_stack.getItem() instanceof BlockItem))) return InteractionResult.PASS;
if (!(((BlockItem) (held_stack.getItem())).getBlock() instanceof EdStraightPoleBlock))
return InteractionResult.PASS;
if (held_stack.getItem() != default_pole.asItem()) return InteractionResult.sidedSuccess(world.isClientSide());
final Block held_block = ((BlockItem) (held_stack.getItem())).getBlock();
final Direction block_direction = state.getValue(FACING);
final Vec3 block_vec = Vec3.atLowerCornerOf(state.getValue(FACING).getNormal());
final double colinearity = 1.0-block_vec.cross(player.getLookAngle()).length();
final Direction placement_direction = Arrays.stream(Direction.orderedByNearest(player)).filter(d->d.getAxis()==block_direction.getAxis()).findFirst().orElse(Direction.NORTH);
final double colinearity = 1.0 - block_vec.cross(player.getLookAngle()).length();
final Direction placement_direction = Arrays.stream(Direction.orderedByNearest(player)).filter(d -> d.getAxis() == block_direction.getAxis()).findFirst().orElse(Direction.NORTH);
final BlockPos adjacent_pos = pos.relative(placement_direction);
final BlockState adjacent = world.getBlockState(adjacent_pos);
final BlockPlaceContext ctx = new DirectionalPlaceContext(world, adjacent_pos, placement_direction, player.getItemInHand(hand), placement_direction.getOpposite());
if(!adjacent.canBeReplaced(ctx)) return InteractionResult.sidedSuccess(world.isClientSide());
if (!adjacent.canBeReplaced(ctx)) return InteractionResult.sidedSuccess(world.isClientSide());
final BlockState new_state = held_block.getStateForPlacement(ctx);
if(new_state == null) return InteractionResult.FAIL;
if(!world.setBlock(adjacent_pos, new_state, 1|2)) return InteractionResult.FAIL;
if (new_state == null) return InteractionResult.FAIL;
if (!world.setBlock(adjacent_pos, new_state, 1 | 2)) return InteractionResult.FAIL;
world.playSound(player, pos, SoundEvents.METAL_PLACE, SoundSource.BLOCKS, 1f, 1f);
if(!player.isCreative()) {
if (!player.isCreative()) {
held_stack.shrink(1);
Inventories.setItemInPlayerHand(player, hand, held_stack);
}

View file

@ -8,7 +8,8 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.libmc.*;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
@ -20,7 +21,7 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -38,9 +39,6 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.registries.ForgeRegistries;
import dev.zontreck.engineerdecor.ModContent;
import wile.engineersdecor.libmc.*;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -48,50 +46,55 @@ import java.util.Collections;
import java.util.List;
public class EdTestBlock
{
public class EdTestBlock {
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class TestBlock extends StandardBlocks.Directed implements StandardEntityBlocks.IStandardEntityBlock<TestTileEntity>, Auxiliaries.IExperimentalFeature
{
public TestBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public static class TestBlock extends StandardBlocks.Directed implements StandardEntityBlocks.IStandardEntityBlock<TestTileEntity>, Auxiliaries.IExperimentalFeature {
public TestBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext)
{ return Shapes.block(); }
@Override
@SuppressWarnings("deprecation") // public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { return true; }
public boolean isSignalSource(BlockState p_60571_)
{ return true; }
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion)
{ return Collections.singletonList(new ItemStack(this)); }
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return Shapes.block();
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if(world.isClientSide()) return InteractionResult.SUCCESS;
// public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { return true; }
public boolean isSignalSource(BlockState p_60571_) {
return true;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, BlockEntity te, boolean explosion) {
return Collections.singletonList(new ItemStack(this));
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (world.isClientSide()) return InteractionResult.SUCCESS;
BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof TestTileEntity)) return InteractionResult.FAIL;
return ((TestTileEntity)te).activated(player, hand, hit) ? InteractionResult.CONSUME : InteractionResult.PASS;
if (!(te instanceof TestTileEntity)) return InteractionResult.FAIL;
return ((TestTileEntity) te).activated(player, hand, hit) ? InteractionResult.CONSUME : InteractionResult.PASS;
}
}
@ -99,8 +102,7 @@ public class EdTestBlock
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class TestTileEntity extends StandardEntityBlocks.StandardBlockEntity
{
public static class TestTileEntity extends StandardEntityBlocks.StandardBlockEntity {
private final RfEnergy.Battery battery_;
private final LazyOptional<IEnergyStorage> energy_handler_;
private final Fluidics.Tank tank_;
@ -127,20 +129,18 @@ public class EdTestBlock
private boolean paused = false;
public TestTileEntity(BlockPos pos, BlockState state)
{
public TestTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
battery_ = new RfEnergy.Battery((int)1e9, (int)1e9, 0, 0);
battery_ = new RfEnergy.Battery((int) 1e9, (int) 1e9, 0, 0);
energy_handler_ = battery_.createEnergyHandler();
tank_ = new Fluidics.Tank((int)1e9);
tank_ = new Fluidics.Tank((int) 1e9);
fluid_handler_ = tank_.createFluidHandler();
inventory_ = new Inventories.StorageInventory(this, 1);
item_handler_ = Inventories.MappedItemHandler.createInsertionHandler(inventory_);
}
@Override
public void load(CompoundTag nbt)
{
public void load(CompoundTag nbt) {
super.load(nbt);
tank_.load(nbt);
battery_.load(nbt);
@ -157,13 +157,13 @@ public class EdTestBlock
rf_feed_setting = nbt.getInt("rf_feed_setting");
items_received_total = nbt.getInt("items_received_total");
items_inserted_total = nbt.getInt("items_inserted_total");
if(nbt.contains("liq_fill_stack")) liq_fill_stack = FluidStack.loadFluidStackFromNBT(nbt.getCompound("liq_fill_stack"));
if(nbt.contains("insertion_item")) insertion_item = ItemStack.of(nbt.getCompound("insertion_item"));
if (nbt.contains("liq_fill_stack"))
liq_fill_stack = FluidStack.loadFluidStackFromNBT(nbt.getCompound("liq_fill_stack"));
if (nbt.contains("insertion_item")) insertion_item = ItemStack.of(nbt.getCompound("insertion_item"));
}
@Override
protected void saveAdditional(CompoundTag nbt)
{
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
tank_.save(nbt);
battery_.save(nbt);
@ -180,69 +180,66 @@ public class EdTestBlock
nbt.putInt("rf_feed_setting", rf_feed_setting);
nbt.putInt("items_received_total", items_received_total);
nbt.putInt("items_inserted_total", items_inserted_total);
if(!liq_fill_stack.isEmpty()) nbt.put("liq_fill_stack", liq_fill_stack.writeToNBT(new CompoundTag()));
if(!insertion_item.isEmpty()) nbt.put("insertion_item", insertion_item.save(new CompoundTag()));
if (!liq_fill_stack.isEmpty()) nbt.put("liq_fill_stack", liq_fill_stack.writeToNBT(new CompoundTag()));
if (!insertion_item.isEmpty()) nbt.put("insertion_item", insertion_item.save(new CompoundTag()));
}
private FluidStack getFillFluid(ItemStack stack)
{
private FluidStack getFillFluid(ItemStack stack) {
// intentionally not item fluid handler, only specific items.
if(stack.getItem() == Items.WATER_BUCKET) return new FluidStack(Fluids.WATER, 1000);
if(stack.getItem() == Items.LAVA_BUCKET) return new FluidStack(Fluids.LAVA, 1000);
if (stack.getItem() == Items.WATER_BUCKET) return new FluidStack(Fluids.WATER, 1000);
if (stack.getItem() == Items.LAVA_BUCKET) return new FluidStack(Fluids.LAVA, 1000);
return FluidStack.EMPTY;
}
private ItemStack getRandomItemstack()
{
final int n = (int)Math.floor(Math.random() * ForgeRegistries.ITEMS.getValues().size());
private ItemStack getRandomItemstack() {
final int n = (int) Math.floor(Math.random() * ForgeRegistries.ITEMS.getValues().size());
ItemStack stack = new ItemStack(ForgeRegistries.ITEMS.getValues().stream().skip(n).findAny().orElse(Items.COBBLESTONE));
stack.setCount((int)Math.floor(Math.random() * stack.getMaxStackSize()));
stack.setCount((int) Math.floor(Math.random() * stack.getMaxStackSize()));
return stack;
}
public boolean activated(Player player, InteractionHand hand, BlockHitResult hit)
{
public boolean activated(Player player, InteractionHand hand, BlockHitResult hit) {
final ItemStack held = player.getItemInHand(hand);
if(held.isEmpty()) {
if (held.isEmpty()) {
ArrayList<String> msgs = new ArrayList<>();
if(rf_fed_avg > 0) msgs.add("-" + rf_fed_avg + "rf/t");
if(rf_fed_total > 0) msgs.add("-" + rf_fed_total + "rf");
if(rf_received_avg > 0) msgs.add("+" + rf_received_avg + "rf/t");
if(rf_received_total > 0) msgs.add("+" + rf_received_total + "rf");
if(liq_filled_avg > 0) msgs.add("-" + liq_filled_avg + "mb/t");
if(liq_filled_total > 0) msgs.add("-" + liq_filled_total + "mb");
if(liq_received_avg > 0) msgs.add("+" + liq_received_avg + "mb/t");
if(liq_received_total > 0) msgs.add("+" + liq_received_total + "mb");
if(items_received_total > 0) msgs.add("+" + items_received_total + "items");
if(items_inserted_total > 0) msgs.add("-" + items_inserted_total + "items");
if(msgs.isEmpty()) msgs.add("Nothing transferred yet.");
if (rf_fed_avg > 0) msgs.add("-" + rf_fed_avg + "rf/t");
if (rf_fed_total > 0) msgs.add("-" + rf_fed_total + "rf");
if (rf_received_avg > 0) msgs.add("+" + rf_received_avg + "rf/t");
if (rf_received_total > 0) msgs.add("+" + rf_received_total + "rf");
if (liq_filled_avg > 0) msgs.add("-" + liq_filled_avg + "mb/t");
if (liq_filled_total > 0) msgs.add("-" + liq_filled_total + "mb");
if (liq_received_avg > 0) msgs.add("+" + liq_received_avg + "mb/t");
if (liq_received_total > 0) msgs.add("+" + liq_received_total + "mb");
if (items_received_total > 0) msgs.add("+" + items_received_total + "items");
if (items_inserted_total > 0) msgs.add("-" + items_inserted_total + "items");
if (msgs.isEmpty()) msgs.add("Nothing transferred yet.");
Overlay.show(player, Component.literal(String.join(" | ", msgs)), 1000);
return true;
} else if(paused) {
if(!getFillFluid(held).isEmpty()) {
} else if (paused) {
if (!getFillFluid(held).isEmpty()) {
FluidStack fs = getFillFluid(held);
if(liq_fill_stack.isEmpty() || !liq_fill_stack.isFluidEqual(fs)) {
if (liq_fill_stack.isEmpty() || !liq_fill_stack.isFluidEqual(fs)) {
fs.setAmount(128);
liq_fill_stack = fs;
} else {
int amount = liq_fill_stack.getAmount() * 2;
if(amount > 4096) amount = 16;
if (amount > 4096) amount = 16;
liq_fill_stack.setAmount(amount);
}
if(liq_fill_stack.isEmpty()) {
if (liq_fill_stack.isEmpty()) {
Overlay.show(player, Component.literal("Fluid fill: none"), 1000);
} else {
Overlay.show(player, Component.literal("Fluid fill: " + liq_fill_stack.getAmount() + "mb/t of " + Auxiliaries.getResourceLocation(liq_fill_stack.getFluid())), 1000);
}
} else if(held.getItem() == Items.REDSTONE) {
rf_feed_setting = (rf_feed_setting<<1) & 0x00fffff0;
if(rf_feed_setting == 0) rf_feed_setting = 0x10;
} else if (held.getItem() == Items.REDSTONE) {
rf_feed_setting = (rf_feed_setting << 1) & 0x00fffff0;
if (rf_feed_setting == 0) rf_feed_setting = 0x10;
Overlay.show(player, Component.literal("RF feed rate: " + rf_feed_setting + "rf/t"), 1000);
} else {
BlockState adjacent_state = level.getBlockState(worldPosition.relative(block_facing));
if(adjacent_state.getBlock()==Blocks.HOPPER || adjacent_state.getBlock()==ModContent.getBlock("factory_hopper")) {
if (adjacent_state.getBlock() == Blocks.HOPPER || adjacent_state.getBlock() == ModContent.getBlock("factory_hopper")) {
insertion_item = held.copy();
Overlay.show(player, Component.literal("Insertion item: " + (insertion_item.getItem()==Items.LEVER ? "random" : insertion_item.toString()) + "/s"), 1000);
Overlay.show(player, Component.literal("Insertion item: " + (insertion_item.getItem() == Items.LEVER ? "random" : insertion_item.toString()) + "/s"), 1000);
}
}
return true;
@ -252,8 +249,7 @@ public class EdTestBlock
}
@Override
public void setRemoved()
{
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
fluid_handler_.invalidate();
@ -261,67 +257,65 @@ public class EdTestBlock
}
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if((!paused) && (facing != block_facing)) {
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
if(capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if ((!paused) && (facing != block_facing)) {
if (capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
if (capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
}
return super.getCapability(capability, facing);
}
@Override
public void tick()
{
if(level.isClientSide()) return;
public void tick() {
if (level.isClientSide()) return;
block_facing = getBlockState().getValue(TestBlock.FACING);
paused = level.hasNeighborSignal(getBlockPos());
if(!paused) {
if (!paused) {
boolean dirty = false;
{
int p = RfEnergy.feed(getLevel(), getBlockPos().relative(block_facing), block_facing.getOpposite(), rf_feed_setting);
rf_fed_acc += p;
dirty |= p>0;
dirty |= p > 0;
}
if(!liq_fill_stack.isEmpty()) {
if (!liq_fill_stack.isEmpty()) {
int f = Fluidics.fill(getLevel(), getBlockPos().relative(block_facing), block_facing.getOpposite(), liq_fill_stack);
liq_filled_acc += f;
dirty |= f>0;
dirty |= f > 0;
}
if(!inventory_.isEmpty()) {
if (!inventory_.isEmpty()) {
int i = inventory_.getItem(0).getCount();
items_received_total += i;
inventory_.clearContent();
dirty |= i>0;
dirty |= i > 0;
}
if((tick_timer == 1) && (!insertion_item.isEmpty())) {
if ((tick_timer == 1) && (!insertion_item.isEmpty())) {
BlockState adjacent_state = level.getBlockState(worldPosition.relative(block_facing));
ItemStack stack = (insertion_item.getItem()==Items.LEVER) ? getRandomItemstack() : insertion_item.copy();
if(adjacent_state.getBlock()==Blocks.HOPPER || adjacent_state.getBlock()==ModContent.getBlock("factory_hopper")) {
ItemStack stack = (insertion_item.getItem() == Items.LEVER) ? getRandomItemstack() : insertion_item.copy();
if (adjacent_state.getBlock() == Blocks.HOPPER || adjacent_state.getBlock() == ModContent.getBlock("factory_hopper")) {
ItemStack remaining = Inventories.insert(getLevel(), getBlockPos().relative(block_facing), block_facing.getOpposite(), stack, false);
int n = stack.getCount() - remaining.getCount();
items_inserted_total += n;
dirty |= n>0;
dirty |= n > 0;
}
}
if(dirty) {
if (dirty) {
setChanged();
}
}
if(--tick_timer <= 0) {
if (--tick_timer <= 0) {
tick_timer = 20;
rf_fed_avg = rf_fed_acc/20;
rf_fed_avg = rf_fed_acc / 20;
rf_fed_total += rf_fed_acc;
rf_fed_acc = 0;
rf_received_avg = battery_.getEnergyStored()/20;
rf_received_avg = battery_.getEnergyStored() / 20;
rf_received_total += battery_.getEnergyStored();
battery_.clear();
liq_received_avg = tank_.getFluidAmount();
liq_received_total += tank_.getFluidAmount();
tank_.clear();
liq_filled_avg = (liq_fill_stack.isEmpty()) ? 0 : (liq_filled_acc/20);
liq_filled_total = (liq_fill_stack.isEmpty()) ? 0 : (liq_filled_total+liq_filled_acc);
liq_filled_avg = (liq_fill_stack.isEmpty()) ? 0 : (liq_filled_acc / 20);
liq_filled_total = (liq_fill_stack.isEmpty()) ? 0 : (liq_filled_total + liq_filled_acc);
liq_filled_acc = 0;
}
}

View file

@ -8,7 +8,13 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.detail.TreeCutting;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.libzontreck.edlibmc.Overlay;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import dev.zontreck.libzontreck.edlibmc.StandardEntityBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
@ -21,7 +27,7 @@ import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -35,62 +41,59 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Overlay;
import javax.annotation.Nullable;
import java.util.Random;
public class EdTreeCutter
{
public static void on_config(int boost_energy_per_tick, int cutting_time_seconds, boolean power_required)
{ TreeCutterTileEntity.on_config(boost_energy_per_tick, cutting_time_seconds,power_required); }
public class EdTreeCutter {
public static void on_config(int boost_energy_per_tick, int cutting_time_seconds, boolean power_required) {
TreeCutterTileEntity.on_config(boost_energy_per_tick, cutting_time_seconds, power_required);
}
//--------------------------------------------------------------------------------------------------------------------
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class TreeCutterBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<TreeCutterTileEntity>
{
public static class TreeCutterBlock extends StandardBlocks.Horizontal implements StandardEntityBlocks.IStandardEntityBlock<TreeCutterTileEntity> {
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public TreeCutterBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public TreeCutterBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(ACTIVE); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(ACTIVE);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(ACTIVE, false); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(ACTIVE, false);
}
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.getValue(ACTIVE))) return;
public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) {
if ((state.getBlock() != this) || (!state.getValue(ACTIVE))) return;
// Sound
/*if((world.getGameTime() & 0x1) == 0)*/ {
/*if((world.getGameTime() & 0x1) == 0)*/
{
world.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), SoundEvents.WOOD_HIT, SoundSource.BLOCKS, 0.1f, 1.0f, false);
}
// Particles
{
final double rv = rnd.nextDouble();
if(rv < 0.8) {
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
switch(state.getValue(HORIZONTAL_FACING)) {
if (rv < 0.8) {
final double x = 0.5 + pos.getX(), y = 0.5 + pos.getY(), z = 0.5 + pos.getZ();
final double xc = 0.52, xr = rnd.nextDouble() * 0.4 - 0.2, yr = (y - 0.3 + rnd.nextDouble() * 0.2);
switch (state.getValue(HORIZONTAL_FACING)) {
case WEST -> world.addParticle(ParticleTypes.SMOKE, x - xc, yr, z + xr, 0.0, 0.0, 0.0);
case EAST -> world.addParticle(ParticleTypes.SMOKE, x + xc, yr, z + xr, 0.0, 0.0, 0.0);
case NORTH -> world.addParticle(ParticleTypes.SMOKE, x + xr, yr, z - xc, 0.0, 0.0, 0.0);
@ -102,25 +105,24 @@ public class EdTreeCutter
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if(world.isClientSide()) return InteractionResult.SUCCESS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (world.isClientSide()) return InteractionResult.SUCCESS;
BlockEntity te = world.getBlockEntity(pos);
if(te instanceof TreeCutterTileEntity) ((TreeCutterTileEntity)te).state_message(player);
if (te instanceof TreeCutterTileEntity) ((TreeCutterTileEntity) te).state_message(player);
return InteractionResult.CONSUME;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class TreeCutterTileEntity extends StandardEntityBlocks.StandardBlockEntity implements IEnergyStorage
{
public static class TreeCutterTileEntity extends StandardEntityBlocks.StandardBlockEntity implements IEnergyStorage {
public static final int IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5;
public static final int BOOST_FACTOR = 6;
@ -130,138 +132,143 @@ public class EdTreeCutter
private static int energy_max = DEFAULT_BOOST_ENERGY * 20;
private static int cutting_time_needed = 20 * DEFAULT_CUTTING_TIME_NEEDED;
private static boolean requires_power = false;
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> this);
private int tick_timer_;
private int active_timer_;
private int proc_time_elapsed_;
private int energy_;
public static void on_config(int boost_energy_per_tick, int cutting_time_seconds, boolean power_required)
{
public TreeCutterTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
public static void on_config(int boost_energy_per_tick, int cutting_time_seconds, boolean power_required) {
boost_energy_consumption = TICK_INTERVAL * Mth.clamp(boost_energy_per_tick, 4, 4096);
energy_max = Math.max(boost_energy_consumption * 10, 10000);
cutting_time_needed = 20 * Mth.clamp(cutting_time_seconds, 10, 240);
requires_power = power_required;
ModConfig.log("Config tree cutter: energy consumption:" + (boost_energy_consumption/TICK_INTERVAL) + "rf/t" + (requires_power?" (power required for operation) ":"") + ", cutting time:" + cutting_time_needed + "t." );
ModConfig.log("Config tree cutter: energy consumption:" + (boost_energy_consumption / TICK_INTERVAL) + "rf/t" + (requires_power ? " (power required for operation) " : "") + ", cutting time:" + cutting_time_needed + "t.");
}
public TreeCutterTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); }
public void readnbt(CompoundTag nbt)
{ energy_ = nbt.getInt("energy"); }
private void writenbt(CompoundTag nbt)
{ nbt.putInt("energy", energy_); }
public void state_message(Player player)
{
String progress = "0";
if((active_timer_ > 0) && (cutting_time_needed > 0) && (active_timer_ > 0)) {
progress = Integer.toString((int)Mth.clamp((((double)proc_time_elapsed_) / ((double)cutting_time_needed) * 100), 0, 100));
public void readnbt(CompoundTag nbt) {
energy_ = nbt.getInt("energy");
}
String soc = Integer.toString(Mth.clamp((energy_*100/energy_max),0,100));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_tree_cutter.status", soc, energy_max, progress, (cutting_time_needed/20)));
private void writenbt(CompoundTag nbt) {
nbt.putInt("energy", energy_);
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt); }
public void state_message(Player player) {
String progress = "0";
if ((active_timer_ > 0) && (cutting_time_needed > 0) && (active_timer_ > 0)) {
progress = Integer.toString((int) Mth.clamp((((double) proc_time_elapsed_) / ((double) cutting_time_needed) * 100), 0, 100));
}
String soc = Integer.toString(Mth.clamp((energy_ * 100 / energy_max), 0, 100));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_tree_cutter.status", soc, energy_max, progress, (cutting_time_needed / 20)));
}
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt); }
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt);
}
@Override
public void setRemoved()
{
super.setRemoved();
energy_handler_.invalidate();
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt);
}
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> this);
@Override
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
}
@Override
public boolean canExtract()
{ return false; }
public boolean canExtract() {
return false;
}
@Override
public boolean canReceive()
{ return true; }
public boolean canReceive() {
return true;
}
@Override
public int getMaxEnergyStored()
{ return boost_energy_consumption*2; }
public int getMaxEnergyStored() {
return boost_energy_consumption * 2;
}
@Override
public int getEnergyStored()
{ return energy_; }
public int getEnergyStored() {
return energy_;
}
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
public int extractEnergy(int maxExtract, boolean simulate) {
return 0;
}
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
public int receiveEnergy(int maxReceive, boolean simulate) {
maxReceive = Mth.clamp(maxReceive, 0, Math.max((energy_max) - energy_, 0));
if(!simulate) energy_ += maxReceive;
if (!simulate) energy_ += maxReceive;
return maxReceive;
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
public void tick() {
if (--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final BlockState device_state = level.getBlockState(worldPosition);
if(!(device_state.getBlock() instanceof TreeCutterBlock)) return;
if (!(device_state.getBlock() instanceof TreeCutterBlock)) return;
final BlockPos tree_pos = worldPosition.relative(device_state.getValue(TreeCutterBlock.HORIZONTAL_FACING));
final BlockState tree_state = level.getBlockState(tree_pos);
if(!TreeCutting.canChop(level, tree_state, tree_pos) || (level.hasNeighborSignal(worldPosition))) {
if(device_state.getValue(TreeCutterBlock.ACTIVE)) level.setBlock(worldPosition, device_state.setValue(TreeCutterBlock.ACTIVE, false), 1|2);
if (!TreeCutting.canChop(level, tree_state, tree_pos) || (level.hasNeighborSignal(worldPosition))) {
if (device_state.getValue(TreeCutterBlock.ACTIVE))
level.setBlock(worldPosition, device_state.setValue(TreeCutterBlock.ACTIVE, false), 1 | 2);
proc_time_elapsed_ = 0;
active_timer_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL;
return;
}
proc_time_elapsed_ += TICK_INTERVAL;
if(energy_ >= boost_energy_consumption) {
if (energy_ >= boost_energy_consumption) {
energy_ -= boost_energy_consumption;
proc_time_elapsed_ += TICK_INTERVAL*BOOST_FACTOR;
proc_time_elapsed_ += TICK_INTERVAL * BOOST_FACTOR;
active_timer_ = 2;
} else if(!requires_power) {
} else if (!requires_power) {
active_timer_ = 1024;
} else if(active_timer_ > 0) {
} else if (active_timer_ > 0) {
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL);
if (requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2 * TICK_INTERVAL);
}
if(proc_time_elapsed_ >= cutting_time_needed) {
if (proc_time_elapsed_ >= cutting_time_needed) {
proc_time_elapsed_ = 0;
TreeCutting.chopTree(level, tree_state, tree_pos, 512, false);
level.playSound(null, worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), SoundEvents.WOOD_BREAK, SoundSource.BLOCKS, 1.0f, 1.0f);
active = false;
}
if(device_state.getValue(TreeCutterBlock.ACTIVE) != active) {
level.setBlock(worldPosition, device_state.setValue(TreeCutterBlock.ACTIVE, active), 1|2);
if (device_state.getValue(TreeCutterBlock.ACTIVE) != active) {
level.setBlock(worldPosition, device_state.setValue(TreeCutterBlock.ACTIVE, active), 1 | 2);
}
}
}

View file

@ -8,6 +8,7 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.VariantWallBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.LevelReader;
@ -15,21 +16,19 @@ import net.minecraft.world.level.block.IronBarsBlock;
import net.minecraft.world.level.block.StainedGlassPaneBlock;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import dev.zontreck.engineerdecor.libmc.VariantWallBlock;
public class EdWallBlock extends VariantWallBlock
{
public EdWallBlock(long config, BlockBehaviour.Properties builder)
{ super(config, builder); }
public class EdWallBlock extends VariantWallBlock {
public EdWallBlock(long config, BlockBehaviour.Properties builder) {
super(config, builder);
}
protected boolean attachesTo(BlockState facingState, LevelReader world, BlockPos facingPos, Direction side)
{
if(facingState==null) return false;
if(super.attachesTo(facingState, world, facingPos, side)) return true;
if(facingState.getBlock() instanceof EdWindowBlock) return true;
if(facingState.getBlock() instanceof IronBarsBlock) return true;
if(facingState.getBlock() instanceof StainedGlassPaneBlock) return true;
protected boolean attachesTo(BlockState facingState, LevelReader world, BlockPos facingPos, Direction side) {
if (facingState == null) return false;
if (super.attachesTo(facingState, world, facingPos, side)) return true;
if (facingState.getBlock() instanceof EdWindowBlock) return true;
if (facingState.getBlock() instanceof IronBarsBlock) return true;
if (facingState.getBlock() instanceof StainedGlassPaneBlock) return true;
return false;
}
}

View file

@ -8,7 +8,9 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.libmc.RfEnergy;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
@ -26,7 +28,7 @@ import net.minecraft.world.inventory.*;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.SignalGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour;
@ -41,29 +43,19 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.IItemHandler;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.StandardEntityBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Inventories;
import dev.zontreck.engineerdecor.libmc.RsSignals;
import dev.zontreck.engineerdecor.libmc.Guis;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class EdWasteIncinerator
{
public class EdWasteIncinerator {
public static final int MAX_ENERGY_BUFFER = 16000;
public static final int MAX_ENERGY_TRANSFER = 256;
public static final int DEFAULT_ENERGY_CONSUMPTION = 16;
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
public static void on_config(int boost_energy_per_tick)
{
public static void on_config(int boost_energy_per_tick) {
energy_consumption = Mth.clamp(boost_energy_per_tick, 4, 4096);
ModConfig.log("Config waste incinerator: boost energy consumption:" + energy_consumption + ".");
}
@ -72,94 +64,100 @@ public class EdWasteIncinerator
// Block
//--------------------------------------------------------------------------------------------------------------------
public static class WasteIncineratorBlock extends StandardBlocks.Cutout implements StandardEntityBlocks.IStandardEntityBlock<WasteIncineratorTileEntity>
{
public static class WasteIncineratorBlock extends StandardBlocks.Cutout implements StandardEntityBlocks.IStandardEntityBlock<WasteIncineratorTileEntity> {
public static final BooleanProperty LIT = EdFurnace.FurnaceBlock.LIT;
public WasteIncineratorBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public WasteIncineratorBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public boolean isBlockEntityTicking(Level world, BlockState state)
{ return true; }
public boolean isBlockEntityTicking(Level world, BlockState state) {
return true;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder)
{ super.createBlockStateDefinition(builder); builder.add(LIT); }
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(LIT);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{ return super.getStateForPlacement(context).setValue(LIT, false); }
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(LIT, false);
}
@Override
@SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state)
{ return true; }
public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState blockState, Level world, BlockPos pos)
{ return (!(world.getBlockEntity(pos) instanceof WasteIncineratorTileEntity te)) ? 0 : RsSignals.fromContainer(te.main_inventory_); }
public int getAnalogOutputSignal(BlockState blockState, Level world, BlockPos pos) {
return (!(world.getBlockEntity(pos) instanceof WasteIncineratorTileEntity te)) ? 0 : RsSignals.fromContainer(te.main_inventory_);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side)
{ return false; }
public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
return false;
}
@Override
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isClientSide) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
public void setPlacedBy(Level world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
if (world.isClientSide) return;
if ((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundTag te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
if (te_nbt.isEmpty()) return;
final BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof EdWasteIncinerator.WasteIncineratorTileEntity)) return;
((EdWasteIncinerator.WasteIncineratorTileEntity)te).readnbt(te_nbt);
if (!(te instanceof EdWasteIncinerator.WasteIncineratorTileEntity)) return;
((EdWasteIncinerator.WasteIncineratorTileEntity) te).readnbt(te_nbt);
te.setChanged();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion)
{
public List<ItemStack> dropList(BlockState state, Level world, final BlockEntity te, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks;
if(!(te instanceof WasteIncineratorTileEntity)) return stacks;
if(!explosion) {
if (world.isClientSide) return stacks;
if (!(te instanceof WasteIncineratorTileEntity)) return stacks;
if (!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundTag te_nbt = ((WasteIncineratorTileEntity) te).getnbt();
if(!te_nbt.isEmpty()) {
if (!te_nbt.isEmpty()) {
CompoundTag nbt = new CompoundTag();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((WasteIncineratorTileEntity)te).main_inventory_) stacks.add(stack);
((WasteIncineratorTileEntity)te).getnbt();
for (ItemStack stack : ((WasteIncineratorTileEntity) te).main_inventory_) stacks.add(stack);
((WasteIncineratorTileEntity) te).getnbt();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult)
{ return useOpenGui(state, world, pos, player); }
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
return useOpenGui(state, world, pos, player);
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd)
{
if((state.getBlock()!=this) || (!state.getValue(LIT))) return;
public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource rnd) {
if ((state.getBlock() != this) || (!state.getValue(LIT))) return;
final double rv = rnd.nextDouble();
if(rv > 0.5) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xr=rnd.nextDouble()*0.4-0.2, yr=rnd.nextDouble()*0.5, zr=rnd.nextDouble()*0.4-0.2;
world.addParticle(ParticleTypes.SMOKE, x+xr, y+yr, z+zr, 0.0, 0.0, 0.0);
if (rv > 0.5) return;
final double x = 0.5 + pos.getX(), y = 0.5 + pos.getY(), z = 0.5 + pos.getZ();
final double xr = rnd.nextDouble() * 0.4 - 0.2, yr = rnd.nextDouble() * 0.5, zr = rnd.nextDouble() * 0.4 - 0.2;
world.addParticle(ParticleTypes.SMOKE, x + xr, y + yr, z + zr, 0.0, 0.0, 0.0);
}
}
@ -167,179 +165,183 @@ public class EdWasteIncinerator
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class WasteIncineratorTileEntity extends StandardEntityBlocks.StandardBlockEntity implements MenuProvider, Nameable
{
public static class WasteIncineratorTileEntity extends StandardEntityBlocks.StandardBlockEntity implements MenuProvider, Nameable {
public static final int NUM_OF_FIELDS = 1;
public static final int TICK_INTERVAL = 20;
public static final int ENERGIZED_TICK_INTERVAL = 5;
public static final int INCINERATION_STACK_DECREMENT = 4;
public static final int NUM_OF_SLOTS = 16;
public static final int INPUT_SLOT_NO = 0;
public static final int BURN_SLOT_NO = NUM_OF_SLOTS-1;
public static final int BURN_SLOT_NO = NUM_OF_SLOTS - 1;
// WasteIncineratorTileEntity -----------------------------------------------------------------------------
protected final ContainerData fields = new ContainerData() {
@Override
public int getCount() {
return WasteIncineratorTileEntity.NUM_OF_FIELDS;
}
private int tick_timer_;
private int check_timer_;
@Override
public int get(int id) {
return switch (id) {
default -> 0;
};
}
@Override
public void set(int id, int value) {
}
};
private final Inventories.StorageInventory main_inventory_ = new Inventories.StorageInventory(this, NUM_OF_SLOTS, 1);
private final LazyOptional<? extends IItemHandler> item_handler_ = Inventories.MappedItemHandler.createInsertionHandler(main_inventory_, INPUT_SLOT_NO);
private final RfEnergy.Battery battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0);
private final LazyOptional<IEnergyStorage> energy_handler_ = battery_.createEnergyHandler();
private int tick_timer_;
private int check_timer_;
public WasteIncineratorTileEntity(BlockPos pos, BlockState state)
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); reset(); }
public WasteIncineratorTileEntity(BlockPos pos, BlockState state) {
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
reset();
}
public CompoundTag getnbt()
{ return writenbt(new CompoundTag()); }
public CompoundTag getnbt() {
return writenbt(new CompoundTag());
}
protected void reset()
{
protected void reset() {
main_inventory_.clearContent();
check_timer_ = 0;
tick_timer_ = 0;
}
public void readnbt(CompoundTag nbt)
{
public void readnbt(CompoundTag nbt) {
main_inventory_.load(nbt);
battery_.load(nbt);
}
protected CompoundTag writenbt(CompoundTag nbt)
{
// BlockEntity ------------------------------------------------------------------------------
protected CompoundTag writenbt(CompoundTag nbt) {
main_inventory_.save(nbt);
battery_.save(nbt);
return nbt;
}
// BlockEntity ------------------------------------------------------------------------------
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
readnbt(nbt);
}
@Override
public void load(CompoundTag nbt)
{ super.load(nbt); readnbt(nbt); }
@Override
protected void saveAdditional(CompoundTag nbt)
{ super.saveAdditional(nbt); writenbt(nbt); }
@Override
public void setRemoved()
{
super.setRemoved();
energy_handler_.invalidate();
item_handler_.invalidate();
protected void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
writenbt(nbt);
}
// INameable ---------------------------------------------------------------------------
@Override
public Component getName()
{ return Auxiliaries.localizable(getBlockState().getBlock().getDescriptionId()); }
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
item_handler_.invalidate();
}
@Override
public boolean hasCustomName()
{ return false; }
public Component getName() {
return Auxiliaries.localizable(getBlockState().getBlock().getDescriptionId());
}
@Override
public Component getCustomName()
{ return getName(); }
public boolean hasCustomName() {
return false;
}
// IContainerProvider ----------------------------------------------------------------------
@Override
public Component getDisplayName()
{ return Nameable.super.getDisplayName(); }
public Component getCustomName() {
return getName();
}
@Override
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player )
{ return new EdWasteIncinerator.WasteIncineratorContainer(id, inventory, main_inventory_, ContainerLevelAccess.create(level, worldPosition), fields); }
public Component getDisplayName() {
return Nameable.super.getDisplayName();
}
// Fields -----------------------------------------------------------------------------------------------
protected final ContainerData fields = new ContainerData()
{
@Override
public int getCount()
{ return WasteIncineratorTileEntity.NUM_OF_FIELDS; }
@Override
public int get(int id)
{
return switch (id) {
default -> 0;
};
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
return new EdWasteIncinerator.WasteIncineratorContainer(id, inventory, main_inventory_, ContainerLevelAccess.create(level, worldPosition), fields);
}
@Override
public void set(int id, int value)
{}
};
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
if (capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
// -----------------------------------------------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
public void tick() {
if (--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
if(level.isClientSide) return;
if (level.isClientSide) return;
boolean dirty = false;
ItemStack processing_stack = main_inventory_.getItem(BURN_SLOT_NO);
final boolean was_processing = !processing_stack.isEmpty();
boolean is_processing = was_processing;
boolean new_stack_processing = false;
if((!main_inventory_.getItem(0).isEmpty()) && transferItems(0, 1, main_inventory_.getMaxStackSize())) dirty = true;
if ((!main_inventory_.getItem(0).isEmpty()) && transferItems(0, 1, main_inventory_.getMaxStackSize()))
dirty = true;
ItemStack first_stack = main_inventory_.getItem(0);
boolean shift = !first_stack.isEmpty();
if(is_processing) {
if (is_processing) {
processing_stack.shrink(INCINERATION_STACK_DECREMENT);
if(processing_stack.getCount() <= 0) {
if (processing_stack.getCount() <= 0) {
processing_stack = ItemStack.EMPTY;
is_processing = false;
}
main_inventory_.setItem(BURN_SLOT_NO, processing_stack);
if(battery_.draw(energy_consumption * TICK_INTERVAL)) {
if (battery_.draw(energy_consumption * TICK_INTERVAL)) {
tick_timer_ = ENERGIZED_TICK_INTERVAL;
}
dirty = true;
}
if(shift) {
if (shift) {
boolean transferred = false;
for(int i=BURN_SLOT_NO-1; i>0; --i) {
transferred |= transferItems(i-1, i, main_inventory_.getMaxStackSize());
for (int i = BURN_SLOT_NO - 1; i > 0; --i) {
transferred |= transferItems(i - 1, i, main_inventory_.getMaxStackSize());
}
if((!is_processing) && (!transferred)) {
if ((!is_processing) && (!transferred)) {
shiftStacks(0, BURN_SLOT_NO);
dirty = true;
}
}
if((was_processing != is_processing) || (new_stack_processing)) {
if(new_stack_processing) level.playSound(null, worldPosition, SoundEvents.LAVA_AMBIENT, SoundSource.BLOCKS, 0.05f, 2.4f);
if ((was_processing != is_processing) || (new_stack_processing)) {
if (new_stack_processing)
level.playSound(null, worldPosition, SoundEvents.LAVA_AMBIENT, SoundSource.BLOCKS, 0.05f, 2.4f);
final BlockState state = level.getBlockState(worldPosition);
if(state.getBlock() instanceof WasteIncineratorBlock) {
level.setBlock(worldPosition, state.setValue(WasteIncineratorBlock.LIT, is_processing), 2|16);
if (state.getBlock() instanceof WasteIncineratorBlock) {
level.setBlock(worldPosition, state.setValue(WasteIncineratorBlock.LIT, is_processing), 2 | 16);
}
}
if(dirty) setChanged();
if (dirty) setChanged();
}
// Aux methods ----------------------------------------------------------------------------------
private ItemStack shiftStacks(final int index_from, final int index_to)
{
if(index_from >= index_to) return ItemStack.EMPTY;
private ItemStack shiftStacks(final int index_from, final int index_to) {
if (index_from >= index_to) return ItemStack.EMPTY;
ItemStack out_stack = ItemStack.EMPTY;
ItemStack stack = main_inventory_.getItem(index_from);
for(int i=index_from+1; i<=index_to; ++i) {
for (int i = index_from + 1; i <= index_to; ++i) {
out_stack = main_inventory_.getItem(i);
main_inventory_.setItem(i, stack);
stack = out_stack;
@ -348,30 +350,29 @@ public class EdWasteIncinerator
return out_stack;
}
private boolean transferItems(final int index_from, final int index_to, int count)
{
private boolean transferItems(final int index_from, final int index_to, int count) {
ItemStack from = main_inventory_.getItem(index_from);
if(from.isEmpty()) return false;
if (from.isEmpty()) return false;
ItemStack to = main_inventory_.getItem(index_to);
if(from.getCount() < count) count = from.getCount();
if(count <= 0) return false;
if (from.getCount() < count) count = from.getCount();
if (count <= 0) return false;
boolean changed = true;
if(to.isEmpty()) {
if (to.isEmpty()) {
main_inventory_.setItem(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
} else if (to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if(Inventories.areItemStacksDifferent(from, to)) {
} else if (Inventories.areItemStacksDifferent(from, to)) {
changed = false;
} else {
if((to.getCount()+count) >= to.getMaxStackSize()) {
from.shrink(to.getMaxStackSize()-to.getCount());
if ((to.getCount() + count) >= to.getMaxStackSize()) {
from.shrink(to.getMaxStackSize() - to.getCount());
to.setCount(to.getMaxStackSize());
} else {
from.shrink(count);
to.grow(count);
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
if (from.isEmpty() && from != ItemStack.EMPTY) {
main_inventory_.setItem(index_from, ItemStack.EMPTY);
changed = true;
}
@ -383,8 +384,7 @@ public class EdWasteIncinerator
// Container
//--------------------------------------------------------------------------------------------------------------------
public static class WasteIncineratorContainer extends AbstractContainerMenu
{
public static class WasteIncineratorContainer extends AbstractContainerMenu {
private static final int PLAYER_INV_START_SLOTNO = WasteIncineratorTileEntity.NUM_OF_SLOTS;
protected final Player player_;
protected final Container inventory_;
@ -392,22 +392,17 @@ public class EdWasteIncinerator
private final ContainerData fields_;
private int proc_time_needed_;
public int field(int index) { return fields_.get(index); }
public Player player() { return player_ ; }
public Container inventory() { return inventory_ ; }
public Level world() { return player_.level; }
public WasteIncineratorContainer(int cid, Inventory player_inventory) {
this(cid, player_inventory, new SimpleContainer(WasteIncineratorTileEntity.NUM_OF_SLOTS), ContainerLevelAccess.NULL, new SimpleContainerData(WasteIncineratorTileEntity.NUM_OF_FIELDS));
}
public WasteIncineratorContainer(int cid, Inventory player_inventory)
{ this(cid, player_inventory, new SimpleContainer(WasteIncineratorTileEntity.NUM_OF_SLOTS), ContainerLevelAccess.NULL, new SimpleContainerData(WasteIncineratorTileEntity.NUM_OF_FIELDS)); }
private WasteIncineratorContainer(int cid, Inventory player_inventory, Container block_inventory, ContainerLevelAccess wpc, ContainerData fields)
{
private WasteIncineratorContainer(int cid, Inventory player_inventory, Container block_inventory, ContainerLevelAccess wpc, ContainerData fields) {
super(ModContent.getMenuType("small_waste_incinerator"), cid); // @todo: class mapping
player_ = player_inventory.player;
inventory_ = block_inventory;
wpc_ = wpc;
fields_ = fields;
int i=-1;
int i = -1;
addSlot(new Slot(inventory_, ++i, 13, 9));
addSlot(new Slot(inventory_, ++i, 37, 12));
addSlot(new Slot(inventory_, ++i, 54, 13));
@ -424,43 +419,60 @@ public class EdWasteIncinerator
addSlot(new Slot(inventory_, ++i, 59, 43));
addSlot(new Slot(inventory_, ++i, 42, 44));
addSlot(new Slot(inventory_, ++i, 17, 58));
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
for (int x = 0; x < 9; ++x) {
addSlot(new Slot(player_inventory, x, 8 + x * 18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 9; ++x) {
addSlot(new Slot(player_inventory, x + y * 9 + 9, 8 + x * 18, 86 + y * 18)); // player slots: 9..35
}
}
}
@Override
public boolean stillValid(Player player)
{ return inventory_.stillValid(player); }
public int field(int index) {
return fields_.get(index);
}
public Player player() {
return player_;
}
public Container inventory() {
return inventory_;
}
public Level world() {
return player_.level();
}
@Override
public ItemStack quickMoveStack(Player player, int index)
{
public boolean stillValid(Player player) {
return inventory_.stillValid(player);
}
@Override
public ItemStack quickMoveStack(Player player, int index) {
Slot slot = getSlot(index);
if((slot==null) || (!slot.hasItem())) return ItemStack.EMPTY;
if ((slot == null) || (!slot.hasItem())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getItem();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
if ((index >= 0) && (index < PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!moveItemStackTo(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, true)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
if (!moveItemStackTo(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO + 36, true))
return ItemStack.EMPTY;
} else if ((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO + 36)) {
// Player slot
if(!moveItemStackTo(slot_stack, 0, PLAYER_INV_START_SLOTNO-1, true)) return ItemStack.EMPTY;
if (!moveItemStackTo(slot_stack, 0, PLAYER_INV_START_SLOTNO - 1, true)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
if (slot_stack.isEmpty()) {
slot.set(ItemStack.EMPTY);
} else {
slot.setChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
if (slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
@ -471,10 +483,10 @@ public class EdWasteIncinerator
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class WasteIncineratorGui extends Guis.ContainerGui<WasteIncineratorContainer>
{
public WasteIncineratorGui(WasteIncineratorContainer container, Inventory player_inventory, Component title)
{ super(container, player_inventory, title, "textures/gui/small_waste_incinerator_gui.png"); }
public static class WasteIncineratorGui extends Guis.ContainerGui<WasteIncineratorContainer> {
public WasteIncineratorGui(WasteIncineratorContainer container, Inventory player_inventory, Component title) {
super(container, player_inventory, title, "textures/gui/small_waste_incinerator_gui.png");
}
}
}

View file

@ -8,6 +8,7 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
@ -24,33 +25,31 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import javax.annotation.Nullable;
import java.util.Arrays;
public class EdWindowBlock extends StandardBlocks.DirectedWaterLoggable
{
public EdWindowBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
public class EdWindowBlock extends StandardBlocks.DirectedWaterLoggable {
public EdWindowBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
super(config, builder, unrotatedAABB);
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.TRANSLUCENT; }
public RenderTypeHint getRenderTypeHint() {
return RenderTypeHint.TRANSLUCENT;
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction facing = context.getHorizontalDirection();
if(Math.abs(context.getPlayer().getLookAngle().y) > 0.9) {
if (Math.abs(context.getPlayer().getLookAngle().y) > 0.9) {
facing = context.getNearestLookingDirection();
} else {
for(Direction f: Direction.values()) {
for (Direction f : Direction.values()) {
BlockState st = context.getLevel().getBlockState(context.getClickedPos().relative(f));
if(st.getBlock() == this) {
if (st.getBlock() == this) {
facing = st.getValue(FACING);
break;
}
@ -61,19 +60,18 @@ public class EdWindowBlock extends StandardBlocks.DirectedWaterLoggable
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if(player.getItemInHand(hand).getItem() != asItem()) return InteractionResult.PASS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (player.getItemInHand(hand).getItem() != asItem()) return InteractionResult.PASS;
final Direction facing = state.getValue(FACING);
if(facing.getAxis() != hit.getDirection().getAxis()) return InteractionResult.PASS;
if (facing.getAxis() != hit.getDirection().getAxis()) return InteractionResult.PASS;
Arrays.stream(Direction.orderedByNearest(player))
.filter(d->d.getAxis() != facing.getAxis())
.filter(d->world.getBlockState(pos.relative(d)).canBeReplaced((new DirectionalPlaceContext(world, pos.relative(d), facing.getOpposite(), player.getItemInHand(hand), facing))))
.findFirst().ifPresent((d)->{
.filter(d -> d.getAxis() != facing.getAxis())
.filter(d -> world.getBlockState(pos.relative(d)).canBeReplaced((new DirectionalPlaceContext(world, pos.relative(d), facing.getOpposite(), player.getItemInHand(hand), facing))))
.findFirst().ifPresent((d) -> {
BlockState st = defaultBlockState()
.setValue(FACING, facing)
.setValue(WATERLOGGED,world.getBlockState(pos.relative(d)).getFluidState().getType()==Fluids.WATER);
world.setBlock(pos.relative(d), st, 1|2);
.setValue(WATERLOGGED, world.getBlockState(pos.relative(d)).getFluidState().getType() == Fluids.WATER);
world.setBlock(pos.relative(d), st, 1 | 2);
world.playSound(player, pos, SoundEvents.METAL_PLACE, SoundSource.BLOCKS, 1f, 1f);
player.getItemInHand(hand).shrink(1);
}
@ -82,12 +80,14 @@ public class EdWindowBlock extends StandardBlocks.DirectedWaterLoggable
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos)
{ return true; }
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public boolean useShapeForLightOcclusion(BlockState state)
{ return true; }
public boolean useShapeForLightOcclusion(BlockState state) {
return true;
}
}

View file

@ -8,6 +8,7 @@
*/
package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
@ -26,7 +27,6 @@ import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -34,27 +34,28 @@ import java.util.Collections;
import java.util.List;
public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWaterLoggable
{
public EdgeAlignedRailingBlock(long config, BlockBehaviour.Properties properties, final AABB base_aabb, final AABB railing_aabb)
{ super(config, properties, base_aabb, railing_aabb, 0); }
public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWaterLoggable {
public EdgeAlignedRailingBlock(long config, BlockBehaviour.Properties properties, final AABB base_aabb, final AABB railing_aabb) {
super(config, properties, base_aabb, railing_aabb, 0);
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos)
{ return true; }
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return true;
}
@Override
@SuppressWarnings("deprecation")
public boolean canBeReplaced(BlockState state, BlockPlaceContext useContext)
{ return (useContext.getItemInHand().getItem() == asItem()) || super.canBeReplaced(state, useContext); }
public boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) {
return (useContext.getItemInHand().getItem() == asItem()) || super.canBeReplaced(state, useContext);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context)
{
if(context.getClickedFace() != Direction.UP) return null;
public BlockState getStateForPlacement(BlockPlaceContext context) {
if (context.getClickedFace() != Direction.UP) return null;
BlockState state = context.getLevel().getBlockState(context.getClickedPos());
if(state.getBlock() != this) state = super.getStateForPlacement(context);
if (state.getBlock() != this) state = super.getStateForPlacement(context);
final Vec3 rhv = context.getClickLocation().subtract(Vec3.atCenterOf(context.getClickedPos()));
BooleanProperty side = getDirectionProperty(Direction.getNearest(rhv.x, 0, rhv.z));
return state.setValue(side, true);
@ -62,17 +63,17 @@ public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWat
@Override
@SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit)
{
if(player.getItemInHand(hand).getItem() != asItem()) return InteractionResult.PASS;
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if (player.getItemInHand(hand).getItem() != asItem()) return InteractionResult.PASS;
Direction face = hit.getDirection();
if(!face.getAxis().isHorizontal()) return InteractionResult.sidedSuccess(world.isClientSide());
if (!face.getAxis().isHorizontal()) return InteractionResult.sidedSuccess(world.isClientSide());
final Vec3 rhv = hit.getLocation().subtract(Vec3.atCenterOf(hit.getBlockPos()));
if(rhv.multiply(Vec3.atLowerCornerOf(face.getNormal())).scale(2).lengthSqr() < 0.99) face = face.getOpposite(); // click on railing, not the outer side.
if (rhv.multiply(Vec3.atLowerCornerOf(face.getNormal())).scale(2).lengthSqr() < 0.99)
face = face.getOpposite(); // click on railing, not the outer side.
BooleanProperty railing = getDirectionProperty(face);
boolean add = (!state.getValue(railing));
state = state.setValue(railing, add);
if((!state.getValue(NORTH)) && (!state.getValue(EAST)) && (!state.getValue(SOUTH)) && (!state.getValue(WEST))) {
if ((!state.getValue(NORTH)) && (!state.getValue(EAST)) && (!state.getValue(SOUTH)) && (!state.getValue(WEST))) {
state = (world.getFluidState(pos).getType() == Fluids.WATER) ? Blocks.WATER.defaultBlockState() : (Blocks.AIR.defaultBlockState());
EdCatwalkBlock.place_consume(state, world, pos, player, hand, add ? 1 : -1);
} else {
@ -84,15 +85,15 @@ public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWat
// -- IDecorBlock
@Override
public boolean hasDynamicDropList()
{ return true; }
public boolean hasDynamicDropList() {
return true;
}
@Override
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion)
{
if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) {
if (world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
List<ItemStack> drops = new ArrayList<>();
int n = (state.getValue(NORTH)?1:0)+(state.getValue(EAST)?1:0)+(state.getValue(SOUTH)?1:0)+(state.getValue(WEST)?1:0);
int n = (state.getValue(NORTH) ? 1 : 0) + (state.getValue(EAST) ? 1 : 0) + (state.getValue(SOUTH) ? 1 : 0) + (state.getValue(WEST) ? 1 : 0);
drops.add(new ItemStack(state.getBlock().asItem(), Math.max(n, 1)));
return drops;
}

View file

@ -0,0 +1,16 @@
package dev.zontreck.engineerdecor.datagen;
import dev.zontreck.engineerdecor.ModEngineersDecor;
import net.minecraftforge.data.event.GatherDataEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(modid = ModEngineersDecor.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ModDatagen
{
@SubscribeEvent
public static void onDatagen(GatherDataEvent ev)
{
}
}

View file

@ -23,35 +23,37 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class ModRenderers
{
public class ModRenderers {
//--------------------------------------------------------------------------------------------------------------------
// InvisibleEntityRenderer
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class InvisibleEntityRenderer<T extends Entity> extends EntityRenderer<T>
{
public static class InvisibleEntityRenderer<T extends Entity> extends EntityRenderer<T> {
private final Minecraft mc = Minecraft.getInstance();
public InvisibleEntityRenderer(EntityRendererProvider.Context context)
{ super(context); }
public InvisibleEntityRenderer(EntityRendererProvider.Context context) {
super(context);
}
public void render(T entity, float entityYaw, float partialTicks, PoseStack matrixStack, MultiBufferSource buffer, int packedLight)
{}
public void render(T entity, float entityYaw, float partialTicks, PoseStack matrixStack, MultiBufferSource buffer, int packedLight) {
}
public Vec3 getRenderOffset(T entity, float partialTicks)
{ return Vec3.ZERO; }
public Vec3 getRenderOffset(T entity, float partialTicks) {
return Vec3.ZERO;
}
@SuppressWarnings("deprecation")
public ResourceLocation getTextureLocation(T entity)
{ return TextureAtlas.LOCATION_BLOCKS; }
public ResourceLocation getTextureLocation(T entity) {
return TextureAtlas.LOCATION_BLOCKS;
}
protected boolean shouldShowName(T entity)
{ return false; }
protected boolean shouldShowName(T entity) {
return false;
}
protected void renderNameTag(T entity, Component displayName, PoseStack matrixStack, MultiBufferSource buffer, int packedLight)
{}
protected void renderNameTag(T entity, Component displayName, PoseStack matrixStack, MultiBufferSource buffer, int packedLight) {
}
}
}

View file

@ -9,6 +9,7 @@
package dev.zontreck.engineerdecor.detail;
import com.google.common.collect.ImmutableList;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.resources.ResourceLocation;
@ -20,74 +21,69 @@ import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.VineBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.ForgeRegistries;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import java.util.*;
import java.util.stream.Collectors;
public class TreeCutting
{
public class TreeCutting {
private static final Set<Block> universal_logs_ = new HashSet<>();
private static final List<Vec3i> hoffsets = ImmutableList.of(
new Vec3i(1, 0, 0), new Vec3i(1, 0, 1), new Vec3i(0, 0, 1),
new Vec3i(-1, 0, 1), new Vec3i(-1, 0, 0), new Vec3i(-1, 0, -1),
new Vec3i(0, 0, -1), new Vec3i(1, 0, -1)
);
public static void on_config(List<String> universal_logs)
{
public static void on_config(List<String> universal_logs) {
universal_logs_.clear();
if(universal_logs.isEmpty()) return;
if (universal_logs.isEmpty()) return;
try {
universal_logs.forEach(rls->{
universal_logs.forEach(rls -> {
final ResourceLocation rl = ResourceLocation.tryParse(rls);
if((rl == null) || (!ForgeRegistries.BLOCKS.containsKey(rl))) return;
if ((rl == null) || (!ForgeRegistries.BLOCKS.containsKey(rl))) return;
universal_logs_.add(ForgeRegistries.BLOCKS.getValue(rl));
});
} catch(Throwable ex) {
} catch (Throwable ex) {
Auxiliaries.logError("Unexpected exception parsing universal log blocks: " + ex.getMessage());
}
if(!universal_logs_.isEmpty()) {
if (!universal_logs_.isEmpty()) {
Auxiliaries.logger().info("Tree cutting: Universal logs:" + universal_logs_.stream().map(Block::toString).collect(Collectors.joining()) + ".");
}
}
public static boolean canChop(Level world, BlockState state, BlockPos pos)
{ return isLog(state) || (universal_logs_.contains(state.getBlock()) && isLog(world.getBlockState(pos.above()))); }
// -------------------------------------------------------------------------------------------------------------------
private static final List<Vec3i> hoffsets = ImmutableList.of(
new Vec3i( 1,0, 0), new Vec3i( 1,0, 1), new Vec3i( 0,0, 1),
new Vec3i(-1,0, 1), new Vec3i(-1,0, 0), new Vec3i(-1,0,-1),
new Vec3i( 0,0,-1), new Vec3i( 1,0,-1)
);
private static boolean isLog(BlockState state)
{ return (state.is(BlockTags.LOGS)); }
private static boolean isSameLog(BlockState a, BlockState b)
{
final Block ba = a.getBlock();
final Block bb = b.getBlock();
return (ba==bb) || (universal_logs_.contains(ba) && isLog(b)) || (universal_logs_.contains(bb) && isLog(a)) || (universal_logs_.contains(ba) && universal_logs_.contains(bb));
public static boolean canChop(Level world, BlockState state, BlockPos pos) {
return isLog(state) || (universal_logs_.contains(state.getBlock()) && isLog(world.getBlockState(pos.above())));
}
private static boolean isLeaves(BlockState state)
{
if(state.getBlock() instanceof LeavesBlock) return true;
if(state.is(BlockTags.LEAVES)) return true;
private static boolean isLog(BlockState state) {
return (state.is(BlockTags.LOGS));
}
private static boolean isSameLog(BlockState a, BlockState b) {
final Block ba = a.getBlock();
final Block bb = b.getBlock();
return (ba == bb) || (universal_logs_.contains(ba) && isLog(b)) || (universal_logs_.contains(bb) && isLog(a)) || (universal_logs_.contains(ba) && universal_logs_.contains(bb));
}
private static boolean isLeaves(BlockState state) {
if (state.getBlock() instanceof LeavesBlock) return true;
if (state.is(BlockTags.LEAVES)) return true;
return false;
}
private static List<BlockPos> findBlocksAround(final Level world, final BlockPos centerPos, final BlockState leaf_type_state, final Set<BlockPos> checked, int recursion_left)
{
private static List<BlockPos> findBlocksAround(final Level world, final BlockPos centerPos, final BlockState leaf_type_state, final Set<BlockPos> checked, int recursion_left) {
ArrayList<BlockPos> to_decay = new ArrayList<>();
for(int y=-1; y<=1; ++y) {
final BlockPos layer = centerPos.offset(0,y,0);
for(Vec3i v:hoffsets) {
for (int y = -1; y <= 1; ++y) {
final BlockPos layer = centerPos.offset(0, y, 0);
for (Vec3i v : hoffsets) {
BlockPos pos = layer.offset(v);
if((!checked.contains(pos)) && (world.getBlockState(pos).getBlock()==leaf_type_state.getBlock())) {
if ((!checked.contains(pos)) && (world.getBlockState(pos).getBlock() == leaf_type_state.getBlock())) {
checked.add(pos);
to_decay.add(pos);
if(recursion_left > 0) {
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, recursion_left-1));
if (recursion_left > 0) {
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, recursion_left - 1));
}
}
}
@ -95,17 +91,16 @@ public class TreeCutting
return to_decay;
}
private static void breakBlock(Level world, BlockPos pos)
{
private static void breakBlock(Level world, BlockPos pos) {
Block.dropResources(world.getBlockState(pos), world, pos);
world.setBlock(pos, world.getFluidState(pos).createLegacyBlock(), 1|2|8);
world.setBlock(pos, world.getFluidState(pos).createLegacyBlock(), 1 | 2 | 8);
}
public static int chopTree(Level world, BlockState broken_state, BlockPos startPos, int max_blocks_to_break, boolean without_target_block)
{
if(world.isClientSide) return 0;
if(universal_logs_.contains(broken_state.getBlock())) broken_state = world.getBlockState(startPos.above()); // For safe detection, at least the block above must be a normal log block.
if(!isLog(broken_state)) return 0;
public static int chopTree(Level world, BlockState broken_state, BlockPos startPos, int max_blocks_to_break, boolean without_target_block) {
if (world.isClientSide) return 0;
if (universal_logs_.contains(broken_state.getBlock()))
broken_state = world.getBlockState(startPos.above()); // For safe detection, at least the block above must be a normal log block.
if (!isLog(broken_state)) return 0;
final long ymin = startPos.getY();
final long max_leaf_distance = 8;
Set<BlockPos> checked = new HashSet<>();
@ -120,33 +115,33 @@ public class TreeCutting
queue.add(startPos);
int cutlevel = 0;
int steps_left = 128;
while(!queue.isEmpty() && (--steps_left >= 0)) {
while (!queue.isEmpty() && (--steps_left >= 0)) {
final BlockPos pos = queue.removeFirst();
// Vertical search
final BlockPos uppos = pos.above();
final BlockState upstate = world.getBlockState(uppos);
if(!checked.contains(uppos)) {
if (!checked.contains(uppos)) {
checked.add(uppos);
if(isSameLog(upstate, broken_state)) {
if (isSameLog(upstate, broken_state)) {
// Up is log
upqueue.add(uppos);
to_break.add(uppos);
steps_left = 128;
} else {
boolean isleaf = isLeaves(upstate);
if(isleaf || world.isEmptyBlock(uppos) || (upstate.getBlock() instanceof VineBlock)) {
if(isleaf) to_decay.add(uppos);
if (isleaf || world.isEmptyBlock(uppos) || (upstate.getBlock() instanceof VineBlock)) {
if (isleaf) to_decay.add(uppos);
// Up is air, check adjacent for diagonal up (e.g. Accacia)
for(Vec3i v:hoffsets) {
for (Vec3i v : hoffsets) {
final BlockPos p = uppos.offset(v);
if(checked.contains(p)) continue;
if (checked.contains(p)) continue;
checked.add(p);
final BlockState st = world.getBlockState(p);
final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) {
if (isSameLog(st, broken_state)) {
queue.add(p);
to_break.add(p);
} else if(isLeaves(st)) {
} else if (isLeaves(st)) {
to_decay.add(p);
}
}
@ -154,22 +149,23 @@ public class TreeCutting
}
}
// Lateral search
for(Vec3i v:hoffsets) {
for (Vec3i v : hoffsets) {
final BlockPos p = pos.offset(v);
if(checked.contains(p)) continue;
if (checked.contains(p)) continue;
checked.add(p);
if(p.distSqr(new BlockPos(startPos.getX(), p.getY(), startPos.getZ())) > (cutlevel > 2 ? 256 : 9)) continue;
if (p.distSqr(new BlockPos(startPos.getX(), p.getY(), startPos.getZ())) > (cutlevel > 2 ? 256 : 9))
continue;
final BlockState st = world.getBlockState(p);
final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) {
if (isSameLog(st, broken_state)) {
queue.add(p);
to_break.add(p);
} else if(isLeaves(st)) {
} else if (isLeaves(st)) {
queue.add(p);
to_decay.add(p);
}
}
if(queue.isEmpty() && (!upqueue.isEmpty())) {
if (queue.isEmpty() && (!upqueue.isEmpty())) {
queue = upqueue;
upqueue = new LinkedList<>();
++cutlevel;
@ -178,31 +174,31 @@ public class TreeCutting
}
{
// Determine lose logs between the leafs
for(BlockPos pos:to_decay) {
for (BlockPos pos : to_decay) {
int dist = 1;
to_break.addAll(findBlocksAround(world, pos, broken_state, checked, dist));
}
}
if(!to_decay.isEmpty()) {
if (!to_decay.isEmpty()) {
final BlockState leaf_type_state = world.getBlockState(to_decay.get(0));
final ArrayList<BlockPos> leafs = to_decay;
to_decay = new ArrayList<>();
for(BlockPos pos:leafs) {
for (BlockPos pos : leafs) {
int dist = 3;
to_decay.add(pos);
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, dist));
}
}
if(without_target_block) {
if (without_target_block) {
checked.remove(startPos);
} else {
to_break.add(startPos);
}
for(BlockPos pos:to_break) breakBlock(world, pos);
for(BlockPos pos:to_decay) breakBlock(world, pos);
for (BlockPos pos : to_break) breakBlock(world, pos);
for (BlockPos pos : to_decay) breakBlock(world, pos);
{
// And now the bill.
return Mth.clamp(((to_break.size()*6/5)+(to_decay.size()/10)-1), 1, 65535);
return Mth.clamp(((to_break.size() * 6 / 5) + (to_decay.size() / 10) - 1), 1, 65535);
}
}
}

View file

@ -8,7 +8,8 @@
*/
package dev.zontreck.engineerdecor.eapi.jei;
public class JEIPlugin {}
public class JEIPlugin {
}
/*
import mezz.jei.api.constants.RecipeTypes;

View file

@ -8,35 +8,26 @@
*/
package dev.zontreck.engineerdecor.items;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.Registries;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class EdItem extends Item
{
public EdItem(Item.Properties properties)
{ super(properties.tab(Registries.getCreativeModeTab())); }
public class EdItem extends Item {
public EdItem(Item.Properties properties) {
super(properties);
}
@Override
@OnlyIn(Dist.CLIENT)
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> tooltip, TooltipFlag flag)
{ Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
@Override
public Collection<CreativeModeTab> getCreativeTabs()
{ return ModConfig.isOptedOut(this) ? (new ArrayList<>()) : (Collections.singletonList(Registries.getCreativeModeTab())); }
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> tooltip, TooltipFlag flag) {
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
}
}