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.blocks.*;
import dev.zontreck.engineerdecor.detail.TreeCutting; import dev.zontreck.engineerdecor.detail.TreeCutting;
import dev.zontreck.engineerdecor.libmc.Auxiliaries; import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import dev.zontreck.engineerdecor.libmc.OptionalRecipeCondition; import dev.zontreck.libzontreck.edlibmc.OptionalRecipeCondition;
import dev.zontreck.engineerdecor.libmc.SlabSliceBlock; import dev.zontreck.libzontreck.edlibmc.SlabSliceBlock;
import dev.zontreck.engineerdecor.libmc.VariantSlabBlock; import dev.zontreck.libzontreck.edlibmc.VariantSlabBlock;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.ForgeConfigSpec;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import wile.engineersdecor.blocks.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class ModConfig public class ModConfig {
{
//--------------------------------------------------------------------------------------------------------------------
private static final String MODID = ModEngineersDecor.MODID;
public static final CommonConfig COMMON; public static final CommonConfig COMMON;
public static final ServerConfig SERVER; public static final ServerConfig SERVER;
public static final ForgeConfigSpec COMMON_CONFIG_SPEC; public static final ForgeConfigSpec COMMON_CONFIG_SPEC;
public static final ForgeConfigSpec SERVER_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 { static {
final Pair<CommonConfig, ForgeConfigSpec> common_ = (new ForgeConfigSpec.Builder()).configure(CommonConfig::new); final Pair<CommonConfig, ForgeConfigSpec> common_ = (new ForgeConfigSpec.Builder()).configure(CommonConfig::new);
@ -44,10 +60,161 @@ public class ModConfig
SERVER = server_.getLeft(); 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 // Optout
public final ForgeConfigSpec.ConfigValue<String> pattern_excludes; public final ForgeConfigSpec.ConfigValue<String> pattern_excludes;
public final ForgeConfigSpec.ConfigValue<String> pattern_includes; 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_config_logging;
public final ForgeConfigSpec.BooleanValue with_debug_logging; public final ForgeConfigSpec.BooleanValue with_debug_logging;
CommonConfig(ForgeConfigSpec.Builder builder) CommonConfig(ForgeConfigSpec.Builder builder) {
{
builder.comment("Settings affecting the logical server side.") builder.comment("Settings affecting the logical server side.")
.push("server"); .push("server");
// --- OPTOUTS ------------------------------------------------------------ // --- OPTOUTS ------------------------------------------------------------
@ -109,10 +275,7 @@ public class ModConfig
} }
} }
//-------------------------------------------------------------------------------------------------------------------- public static class ServerConfig {
public static class ServerConfig
{
// Optout // Optout
public final ForgeConfigSpec.BooleanValue without_chair_sitting; public final ForgeConfigSpec.BooleanValue without_chair_sitting;
public final ForgeConfigSpec.BooleanValue without_mob_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_energy_consumption;
public final ForgeConfigSpec.IntValue milking_machine_milking_delay; public final ForgeConfigSpec.IntValue milking_machine_milking_delay;
ServerConfig(ForgeConfigSpec.Builder builder) ServerConfig(ForgeConfigSpec.Builder builder) {
{
builder.comment("Settings affecting the logical server side.") builder.comment("Settings affecting the logical server side.")
.push("server"); .push("server");
// --- OPTOUTS ------------------------------------------------------------ // --- OPTOUTS ------------------------------------------------------------
@ -315,172 +477,11 @@ public class ModConfig
.defineInRange("milking_machine_energy_consumption", EdMilker.DEFAULT_ENERGY_CONSUMPTION, 0, 1024); .defineInRange("milking_machine_energy_consumption", EdMilker.DEFAULT_ENERGY_CONSUMPTION, 0, 1024);
milking_machine_milking_delay = builder milking_machine_milking_delay = builder
.translation(MODID + ".config.milking_machine_milking_delay") .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); .defineInRange("milking_machine_milking_delay", EdMilker.DEFAULT_MILKING_DELAY_PER_COW, 1000, 24000);
builder.pop(); 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; package dev.zontreck.engineerdecor;
import dev.zontreck.engineerdecor.blocks.EdLadderBlock; 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.minecraft.world.entity.player.Player;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; 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.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger; 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") @Mod("engineersdecor")
public class ModEngineersDecor public class ModEngineersDecor {
{
public static final String MODID = "engineersdecor"; public static final String MODID = "engineersdecor";
public static final String MODNAME = "Engineer's Decor"; public static final String MODNAME = "Engineer's Decor";
public static final int VERSION_DATAFIXER = 0; public static final int VERSION_DATAFIXER = 0;
private static final Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); private static final Logger LOGGER = com.mojang.logging.LogUtils.getLogger();
public ModEngineersDecor() public ModEngineersDecor() {
{
Auxiliaries.init(MODID, LOGGER, ModConfig::getServerConfig); Auxiliaries.init(MODID, LOGGER, ModConfig::getServerConfig);
Auxiliaries.logGitVersion(MODNAME); 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); ModContent.init(MODID);
OptionalRecipeCondition.init(MODID, LOGGER); OptionalRecipeCondition.init(MODID, LOGGER);
ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.SERVER, ModConfig.SERVER_CONFIG_SPEC); 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); MinecraftForge.EVENT_BUS.register(this);
} }
private void onSetup(final FMLCommonSetupEvent event) private void onSetup(final FMLCommonSetupEvent event) {
{
CraftingHelper.register(OptionalRecipeCondition.Serializer.INSTANCE); CraftingHelper.register(OptionalRecipeCondition.Serializer.INSTANCE);
Networking.init(MODID); 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); Overlay.TextOverlayGui.on_config(0.75, 0x00ffaa00, 0x55333333, 0x55333333, 0x55444444);
Networking.OverlayTextMessage.setHandler(Overlay.TextOverlayGui::show); Networking.OverlayTextMessage.setHandler(Overlay.TextOverlayGui::show);
ModContent.registerMenuGuis(event); ModContent.registerMenuGuis(event);
@ -59,45 +51,42 @@ public class ModEngineersDecor
ModContent.processContentClientSide(event); ModContent.processContentClientSide(event);
} }
@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
public static class ForgeEvents
{
@SubscribeEvent @SubscribeEvent
public static void onConfigLoad(final ModConfigEvent.Loading event) public void onPlayerEvent(final LivingEvent.LivingTickEvent event) {
{ ModConfig.apply(); } 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 @SubscribeEvent
public static void onConfigReload(final ModConfigEvent.Reloading event) public static void onConfigReload(final ModConfigEvent.Reloading event) {
{
try { try {
Auxiliaries.logger().info("Config file changed {}", event.getConfig().getFileName()); Auxiliaries.logger().info("Config file changed {}", event.getConfig().getFileName());
ModConfig.apply(); ModConfig.apply();
} catch(Throwable e) { } catch (Throwable e) {
Auxiliaries.logger().error("Failed to load changed config: " + e.getMessage()); 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) @OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(Dist.CLIENT) @Mod.EventBusSubscriber(Dist.CLIENT)
public static class ForgeClientEvents public static class ForgeClientEvents {
{
@SubscribeEvent @SubscribeEvent
public static void onRenderGui(net.minecraftforge.client.event.RenderGuiOverlayEvent.Post event) public static void onRenderGui(net.minecraftforge.client.event.RenderGuiOverlayEvent.Post event) {
{ Overlay.TextOverlayGui.INSTANCE.onRenderGui(event.getPoseStack()); } Overlay.TextOverlayGui.INSTANCE.onRenderGui(event.getGuiGraphics());
}
@SubscribeEvent @SubscribeEvent
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public static void onRenderWorldOverlay(net.minecraftforge.client.event.RenderLevelStageEvent event) public static void onRenderWorldOverlay(net.minecraftforge.client.event.RenderLevelStageEvent event) {
{ if (event.getStage() == net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_WEATHER) {
if(event.getStage() == net.minecraftforge.client.event.RenderLevelStageEvent.Stage.AFTER_WEATHER) {
Overlay.TextOverlayGui.INSTANCE.onRenderWorldOverlay(event.getPoseStack(), event.getPartialTick()); Overlay.TextOverlayGui.INSTANCE.onRenderWorldOverlay(event.getPoseStack(), event.getPartialTick());
} }
} }

View file

@ -8,6 +8,9 @@
*/ */
package dev.zontreck.engineerdecor.blocks; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes; 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.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks; 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.SoundType;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour; 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.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage; 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 javax.annotation.Nullable;
import java.util.HashSet; import java.util.HashSet;
@ -56,8 +52,7 @@ import java.util.List;
import java.util.Random; import java.util.Random;
public class EdBreaker public class EdBreaker {
{
public static final int BOOST_FACTOR = 8; public static final int BOOST_FACTOR = 8;
public static final int DEFAULT_BOOST_ENERGY = 64; public static final int DEFAULT_BOOST_ENERGY = 64;
public static final int DEFAULT_BREAKING_RELUCTANCE = 17; 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 int min_breaking_time = DEFAULT_MIN_BREAKING_TIME;
private static boolean requires_power = false; 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; final int interval = BreakerTileEntity.TICK_INTERVAL;
boost_energy_consumption = interval * Mth.clamp(boost_energy_per_tick, 4, 4096); boost_energy_consumption = interval * Mth.clamp(boost_energy_per_tick, 4, 4096);
energy_max = Math.max(boost_energy_consumption * 10, 100000); energy_max = Math.max(boost_energy_consumption * 10, 100000);
breaking_reluctance = Mth.clamp(breaking_time_per_hardness, 5, 50); breaking_reluctance = Mth.clamp(breaking_time_per_hardness, 5, 50);
min_breaking_time = Mth.clamp(min_breaking_time_ticks, 10, 100); min_breaking_time = Mth.clamp(min_breaking_time_ticks, 10, 100);
requires_power = power_required; 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 // 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 static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BreakerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs) public BreakerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs) {
{ super(config, builder, unrotatedAABBs); } super(config, builder, unrotatedAABBs);
}
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(ACTIVE); } super.createBlockStateDefinition(builder);
builder.add(ACTIVE);
}
@Override @Override
@Nullable @Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) public BlockState getStateForPlacement(BlockPlaceContext context) {
{ return super.getStateForPlacement(context).setValue(ACTIVE, false); } return super.getStateForPlacement(context).setValue(ACTIVE, false);
}
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) {
{ if ((state.getBlock() != this) || (!state.getValue(ACTIVE))) return;
if((state.getBlock()!=this) || (!state.getValue(ACTIVE))) return;
// Sound // Sound
{ {
SoundEvent sound = SoundEvents.WOOD_HIT; SoundEvent sound = SoundEvents.WOOD_HIT;
BlockState target_state = world.getBlockState(pos.relative(state.getValue(BreakerBlock.HORIZONTAL_FACING))); BlockState target_state = world.getBlockState(pos.relative(state.getValue(BreakerBlock.HORIZONTAL_FACING)));
SoundType stype = target_state.getBlock().getSoundType(target_state); 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; sound = SoundEvents.WOOL_HIT;
} else if((stype == SoundType.GRAVEL) || (stype == SoundType.SAND)) { } else if ((stype == SoundType.GRAVEL) || (stype == SoundType.SAND)) {
sound = SoundEvents.GRAVEL_HIT; sound = SoundEvents.GRAVEL_HIT;
} }
world.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), sound, SoundSource.BLOCKS, 0.1f, 1.2f, false); world.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), sound, SoundSource.BLOCKS, 0.1f, 1.2f, false);
@ -125,9 +122,9 @@ public class EdBreaker
// Particles // Particles
{ {
final double rv = rnd.nextDouble(); final double rv = rnd.nextDouble();
if(rv < 0.8) { if (rv < 0.8) {
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ(); 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); 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)) { switch (state.getValue(HORIZONTAL_FACING)) {
case WEST -> world.addParticle(ParticleTypes.SMOKE, x - xc, yr, z + xr, 0.0, 0.0, 0.0); 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 EAST -> world.addParticle(ParticleTypes.SMOKE, x + xc, yr, z + xr, 0.0, 0.0, 0.0);
@ -140,36 +137,37 @@ public class EdBreaker
@Override @Override
@SuppressWarnings("deprecation") @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) {
{ if (!(world instanceof Level) || (world.isClientSide)) return;
if(!(world instanceof Level) || (world.isClientSide)) return;
BlockEntity te = world.getBlockEntity(pos); BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof BreakerTileEntity)) return; if (!(te instanceof BreakerTileEntity)) return;
((BreakerTileEntity)te).block_updated(); ((BreakerTileEntity) te).block_updated();
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean isSignalSource(BlockState state) public boolean isSignalSource(BlockState state) {
{ return true; } return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
{ return 0; } return 0;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
{ return 0; } return 0;
}
@Override @Override
@SuppressWarnings("deprecation") @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) {
{ if (world.isClientSide()) return InteractionResult.SUCCESS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
BlockEntity te = world.getBlockEntity(pos); 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; return InteractionResult.CONSUME;
} }
} }
@ -178,67 +176,11 @@ public class EdBreaker
// Tile entity // 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 IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5; 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<>(); private static final HashSet<Block> blacklist = new HashSet<>();
static { static {
blacklist.add(Blocks.AIR); blacklist.add(Blocks.AIR);
blacklist.add(Blocks.BEDROCK); blacklist.add(Blocks.BEDROCK);
@ -250,96 +192,157 @@ public class EdBreaker
blacklist.add(Blocks.BARRIER); 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(); final Block block = state.getBlock();
if(blacklist.contains(block)) return false; if (blacklist.contains(block)) return false;
if(state.isAir()) return false; if (state.isAir()) return false;
if(state.getMaterial().isLiquid()) return false; if (state.getBlock() instanceof LiquidBlock) return false;
float bh = state.getDestroySpeed(world, pos); 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) { 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, ItemEntity e = new ItemEntity(world,
((world.random.nextFloat()*0.1)+0.5) + pos.getX(), ((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.getY(),
((world.random.nextFloat()*0.1)+0.5) + pos.getZ(), ((world.random.nextFloat() * 0.1) + 0.5) + pos.getZ(),
stack stack
); );
e.setDefaultPickUpDelay(); 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); 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 // 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. // tag spamming the game. So for now only FH and VH.
final BlockState state = world.getBlockState(pos); final BlockState state = world.getBlockState(pos);
return (state.getBlock() == ModContent.getBlock("factory_hopper")) || (state.getBlock() == Blocks.HOPPER); return (state.getBlock() == ModContent.getBlock("factory_hopper")) || (state.getBlock() == Blocks.HOPPER);
} }
private boolean breakBlock(BlockState state, BlockPos pos, Level world) public void block_updated() {
{ if (tick_timer_ > 2) tick_timer_ = 2;
if(world.isClientSide || (!(world instanceof ServerLevel)) || world.restoringBlockSnapshots) return false; // retry next cycle }
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; List<ItemStack> drops;
final Block block = state.getBlock(); final Block block = state.getBlock();
final boolean insert = canInsertInto(world, getBlockPos().below()); 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); world.removeBlock(pos, false);
for(ItemStack drop:drops) { for (ItemStack drop : drops) {
if(!insert) { if (!insert) {
spawnBlockAsEntity(world, pos, drop); spawnBlockAsEntity(world, pos, drop);
} else { } else {
final ItemStack remaining = Inventories.insert(world, getBlockPos().below(), Direction.UP, drop, false); 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); 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; return true;
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void tick() public void tick() {
{ if (--tick_timer_ > 0) return;
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
final BlockState device_state = level.getBlockState(worldPosition); 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 BlockPos target_pos = worldPosition.relative(device_state.getValue(BreakerBlock.HORIZONTAL_FACING));
final BlockState target_state = level.getBlockState(target_pos); final BlockState target_state = level.getBlockState(target_pos);
if((level.hasNeighborSignal(worldPosition)) || (!isBreakable(target_state, target_pos, level))) { 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 (device_state.getValue(BreakerBlock.ACTIVE))
level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, false), 1 | 2);
proc_time_elapsed_ = 0; proc_time_elapsed_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL; tick_timer_ = IDLE_TICK_INTERVAL;
return; return;
} }
time_needed_ = Mth.clamp((int)(target_state.getDestroySpeed(level, worldPosition) * breaking_reluctance) + min_breaking_time, min_breaking_time, MAX_BREAKING_TIME); 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)) { if (battery_.draw(boost_energy_consumption)) {
proc_time_elapsed_ += TICK_INTERVAL * (1+BOOST_FACTOR); proc_time_elapsed_ += TICK_INTERVAL * (1 + BOOST_FACTOR);
time_needed_ += min_breaking_time * (3*BOOST_FACTOR/5); time_needed_ += min_breaking_time * (3 * BOOST_FACTOR / 5);
active_timer_ = 2; active_timer_ = 2;
} else if(!requires_power) { } else if (!requires_power) {
proc_time_elapsed_ += TICK_INTERVAL; proc_time_elapsed_ += TICK_INTERVAL;
active_timer_ = 1024; active_timer_ = 1024;
} else if(active_timer_ > 0) { } else if (active_timer_ > 0) {
--active_timer_; --active_timer_;
} }
boolean active = (active_timer_ > 0); boolean active = (active_timer_ > 0);
if(requires_power && !active) { if (requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL); 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; proc_time_elapsed_ = 0;
breakBlock(target_state, target_pos, level); breakBlock(target_state, target_pos, level);
active = false; active = false;
} }
if(device_state.getValue(BreakerBlock.ACTIVE) != active) { if (device_state.getValue(BreakerBlock.ACTIVE) != active) {
level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, active), 1|2); level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, active), 1 | 2);
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,6 +10,11 @@
*/ */
package dev.zontreck.engineerdecor.blocks; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i; 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.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; 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.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity; 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.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler; 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 javax.annotation.Nullable;
import java.util.*; import java.util.*;
public class EdFluidFunnel public class EdFluidFunnel {
{
private static boolean with_device_fluid_handler_collection = false; 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; with_device_fluid_handler_collection = with_tank_fluid_collection;
ModConfig.log("Config fluid funnel: tank-fluid-collection:" + with_device_fluid_handler_collection + "."); ModConfig.log("Config fluid funnel: tank-fluid-collection:" + with_device_fluid_handler_collection + ".");
} }
@ -68,74 +66,81 @@ public class EdFluidFunnel
// Block // 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 int FILL_LEVEL_MAX = 3;
public static final IntegerProperty FILL_LEVEL = IntegerProperty.create("level", 0, FILL_LEVEL_MAX); public static final IntegerProperty FILL_LEVEL = IntegerProperty.create("level", 0, FILL_LEVEL_MAX);
public FluidFunnelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) public FluidFunnelBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
{ super(config, builder, unrotatedAABB); } super(config, builder, unrotatedAABB);
}
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
public RenderTypeHint getRenderTypeHint() public RenderTypeHint getRenderTypeHint() {
{ return RenderTypeHint.CUTOUT; } return RenderTypeHint.CUTOUT;
}
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
{ return Shapes.block(); } return Shapes.block();
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(FILL_LEVEL); } super.createBlockStateDefinition(builder);
builder.add(FILL_LEVEL);
}
@Override @Override
@Nullable @Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) public BlockState getStateForPlacement(BlockPlaceContext context) {
{ return super.getStateForPlacement(context).setValue(FILL_LEVEL, 0); } return super.getStateForPlacement(context).setValue(FILL_LEVEL, 0);
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state) public boolean hasAnalogOutputSignal(BlockState state) {
{ return true; } return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
{ return Mth.clamp((state.getValue(FILL_LEVEL)*5), 0, 15); } return Mth.clamp((state.getValue(FILL_LEVEL) * 5), 0, 15);
}
@Override @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) {
{ if (world.isClientSide) return;
if(world.isClientSide) return; if ((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundTag te_nbt = stack.getTag().getCompound("tedata"); CompoundTag te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return; if (te_nbt.isEmpty()) return;
final BlockEntity te = world.getBlockEntity(pos); final BlockEntity te = world.getBlockEntity(pos);
if(!(te instanceof FluidFunnelTileEntity)) return; if (!(te instanceof FluidFunnelTileEntity)) return;
((FluidFunnelTileEntity)te).readnbt(te_nbt); ((FluidFunnelTileEntity) te).readnbt(te_nbt);
te.setChanged(); te.setChanged();
world.setBlockAndUpdate(pos, state.setValue(FILL_LEVEL, 0)); world.setBlockAndUpdate(pos, state.setValue(FILL_LEVEL, 0));
} }
@Override @Override
public boolean hasDynamicDropList() public boolean hasDynamicDropList() {
{ return true; } return true;
}
@Override @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<>(); final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks; if (world.isClientSide) return stacks;
if(!(te instanceof FluidFunnelTileEntity)) return stacks; if (!(te instanceof FluidFunnelTileEntity)) return stacks;
if(!explosion) { if (!explosion) {
ItemStack stack = new ItemStack(this, 1); ItemStack stack = new ItemStack(this, 1);
CompoundTag te_nbt = new CompoundTag(); CompoundTag te_nbt = new CompoundTag();
((FluidFunnelTileEntity)te).writenbt(te_nbt); ((FluidFunnelTileEntity) te).writenbt(te_nbt);
if(!te_nbt.isEmpty()) { if (!te_nbt.isEmpty()) {
CompoundTag nbt = new CompoundTag(); CompoundTag nbt = new CompoundTag();
nbt.put("tedata", te_nbt); nbt.put("tedata", te_nbt);
stack.setTag(nbt); stack.setTag(nbt);
@ -149,36 +154,40 @@ public class EdFluidFunnel
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
{ if (world.isClientSide) return InteractionResult.SUCCESS;
if(world.isClientSide) return InteractionResult.SUCCESS;
return (world.getBlockEntity(pos) instanceof FluidFunnelTileEntity) && Fluidics.manualFluidHandlerInteraction(player, hand, world, pos, rayTraceResult.getDirection()) ? InteractionResult.CONSUME : InteractionResult.FAIL; return (world.getBlockEntity(pos) instanceof FluidFunnelTileEntity) && Fluidics.manualFluidHandlerInteraction(player, hand, world, pos, rayTraceResult.getDirection()) ? InteractionResult.CONSUME : InteractionResult.FAIL;
} }
@Override @Override
@SuppressWarnings("deprecation") @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) {
{ BlockEntity te = world.getBlockEntity(pos); if(te instanceof FluidFunnelTileEntity) ((FluidFunnelTileEntity)te).block_changed(); } BlockEntity te = world.getBlockEntity(pos);
if (te instanceof FluidFunnelTileEntity) ((FluidFunnelTileEntity) te).block_changed();
}
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } return false;
}
} }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Tile entity // 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 TANK_CAPACITY = 3000;
public static final int TICK_INTERVAL = 10; // ca 500ms 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 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_TRACK_RADIUS = 16;
public static final int MAX_TRACKING_STEPS_PER_CYCLE = 72; 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_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; 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 tick_timer_ = 0;
private int collection_timer_ = 0; private int collection_timer_ = 0;
private int no_fluid_found_counter_ = 0; private int no_fluid_found_counter_ = 0;
@ -186,38 +195,39 @@ public class EdFluidFunnel
private int total_pick_counter_ = 0; private int total_pick_counter_ = 0;
private BlockPos last_pick_pos_ = BlockPos.ZERO; private BlockPos last_pick_pos_ = BlockPos.ZERO;
private ArrayList<Vec3i> search_offsets_ = null; 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) public FluidFunnelTileEntity(BlockPos pos, BlockState state) {
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); } super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
public void readnbt(CompoundTag nbt) public void readnbt(CompoundTag nbt) {
{
tank_.load(nbt); tank_.load(nbt);
} }
public void writenbt(CompoundTag nbt) public void writenbt(CompoundTag nbt) {
{
tank_.save(nbt); tank_.save(nbt);
} }
public void block_changed() public void block_changed() {
{ tick_timer_ = TICK_INTERVAL; } tick_timer_ = TICK_INTERVAL;
}
// BlockEntity ----------------------------------------------------------------------------------------- // BlockEntity -----------------------------------------------------------------------------------------
@Override @Override
public void load(CompoundTag nbt) public void load(CompoundTag nbt) {
{ super.load(nbt); readnbt(nbt); } super.load(nbt);
readnbt(nbt);
}
@Override @Override
protected void saveAdditional(CompoundTag nbt) protected void saveAdditional(CompoundTag nbt) {
{ super.saveAdditional(nbt); writenbt(nbt); } super.saveAdditional(nbt);
writenbt(nbt);
}
@Override @Override
public void setRemoved() public void setRemoved() {
{
super.setRemoved(); super.setRemoved();
fluid_handler_.invalidate(); fluid_handler_.invalidate();
} }
@ -225,39 +235,37 @@ public class EdFluidFunnel
// ICapabilityProvider / Output flow handler ---------------------------------------------------------- // ICapabilityProvider / Output flow handler ----------------------------------------------------------
@Override @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
{ if (capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
return super.getCapability(capability, facing); return super.getCapability(capability, facing);
} }
// ----------------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------------
private FluidState get_fluidstate(BlockPos pos) private FluidState get_fluidstate(BlockPos pos) {
{
return level.getFluidState(pos); return level.getFluidState(pos);
} }
private boolean try_pick(BlockPos pos, FluidState fluidstate) private boolean try_pick(BlockPos pos, FluidState fluidstate) {
{ if (!fluidstate.isSource()) return false;
if(!fluidstate.isSource()) return false;
IFluidHandler hnd = Fluidics.handler(level, pos, null); IFluidHandler hnd = Fluidics.handler(level, pos, null);
FluidStack fs; FluidStack fs;
if(hnd != null) { if (hnd != null) {
fs = hnd.drain(TANK_CAPACITY, IFluidHandler.FluidAction.EXECUTE); // IFluidBlock fs = hnd.drain(TANK_CAPACITY, IFluidHandler.FluidAction.EXECUTE); // IFluidBlock
} else { } else {
fs = new FluidStack(fluidstate.getType(), 1000); fs = new FluidStack(fluidstate.getType(), 1000);
BlockState state = level.getBlockState(pos); BlockState state = level.getBlockState(pos);
if(state.hasProperty(BlockStateProperties.WATERLOGGED)) { if (state.hasProperty(BlockStateProperties.WATERLOGGED)) {
level.setBlock(pos, state.setValue(BlockStateProperties.WATERLOGGED, false), 1|2); level.setBlock(pos, state.setValue(BlockStateProperties.WATERLOGGED, false), 1 | 2);
} else { } 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 ((fs == null) || (fs.isEmpty()))
if(tank_.isEmpty()) { return false; // it's marked nonnull but I don't trust every modder - including meself ...
if (tank_.isEmpty()) {
tank_.setFluid(fs.copy()); tank_.setFluid(fs.copy());
} else if(tank_.isFluidEqual(fs)) { } else if (tank_.isFluidEqual(fs)) {
tank_.fill(fs, IFluidHandler.FluidAction.EXECUTE); tank_.fill(fs, IFluidHandler.FluidAction.EXECUTE);
} else { } else {
return false; return false;
@ -265,132 +273,138 @@ public class EdFluidFunnel
return true; return true;
} }
private boolean can_pick(BlockPos pos, FluidState fluidstate) private boolean can_pick(BlockPos pos, FluidState fluidstate) {
{ if (fluidstate.isSource()) return true;
if(fluidstate.isSource()) return true;
final IFluidHandler hnd = Fluidics.handler(level, pos, null); 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 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_ = new ArrayList<>(9);
search_offsets_.add(new Vec3i(0, 1, 0)); // up first 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))); 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); if (intensive || (total_pick_counter_ > 50)) Collections.shuffle(ofs);
search_offsets_.addAll(ofs); search_offsets_.addAll(ofs);
} }
if(intensive) { 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))); 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); Collections.shuffle(ofs);
search_offsets_.addAll(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); 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(); Fluid fluid_to_collect = collection_fluidstate.getType();
if((!tank_.isEmpty()) && (!tank_.getFluid().getFluid().isSame(fluid_to_collect))) return false; 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 (try_pick(collection_pos, collection_fluidstate)) {
if((last_pick_pos_==null) || (last_pick_pos_.distSqr(collection_pos) > MAX_TRACK_RADIUS_SQ)) { last_pick_pos_ = collection_pos; search_offsets_ = null; } 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_; BlockPos pos = last_pick_pos_;
HashSet<BlockPos> checked = new HashSet<>(); HashSet<BlockPos> checked = new HashSet<>();
Stack<BlockPos> trail = new Stack<>(); Stack<BlockPos> trail = new Stack<>();
trail.add(pos); trail.add(pos);
checked.add(pos); checked.add(pos);
int steps=0; int steps = 0;
boolean intensive = (no_fluid_found_counter_ >= INTENSIVE_SEARCH_TRIGGER_THRESHOLD); boolean intensive = (no_fluid_found_counter_ >= INTENSIVE_SEARCH_TRIGGER_THRESHOLD);
if(intensive) { no_fluid_found_counter_ = 0; ++intensive_search_counter_; } if (intensive) {
if(search_offsets_ == null) rebuild_search_offsets(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; int max = intensive ? MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE : MAX_TRACKING_STEPS_PER_CYCLE;
while(++steps <= max) { while (++steps <= max) {
int num_adjacent = 0; 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)); BlockPos p = pos.offset(search_offsets_.get(i));
if(checked.contains(p)) continue; if (checked.contains(p)) continue;
checked.add(p); checked.add(p);
++steps; ++steps;
FluidState fluidstate = get_fluidstate(p); FluidState fluidstate = get_fluidstate(p);
if(fluidstate.getType().isSame(fluid_to_collect)) { if (fluidstate.getType().isSame(fluid_to_collect)) {
++num_adjacent; ++num_adjacent;
pos = p; pos = p;
trail.push(pos); 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) // check for same fluid above (only source blocks)
final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2)-steps; final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE / 2) - steps;
for(int k=0; k<max_surface_search; ++k) { for (int k = 0; k < max_surface_search; ++k) {
FluidState fs = get_fluidstate(pos.above()); FluidState fs = get_fluidstate(pos.above());
if(!can_pick(pos.above(), fs)) break; if (!can_pick(pos.above(), fs)) break;
fluidstate = fs; fluidstate = fs;
pos = pos.above(); pos = pos.above();
trail.push(pos); trail.push(pos);
} }
} }
if(try_pick(pos, fluidstate)) { if (try_pick(pos, fluidstate)) {
last_pick_pos_ = pos; last_pick_pos_ = pos;
no_fluid_found_counter_ = 0; no_fluid_found_counter_ = 0;
search_offsets_ = null; search_offsets_ = null;
// probability reset, so it's not turteling too far away, mainly for large nether lava seas, not desert lakes. // 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))); //println("PASS " + steps + " - " + (pos.subtract(collection_pos)));
return true; return true;
} }
} }
} }
if(trail.isEmpty()) break; // reset search if (trail.isEmpty()) break; // reset search
if(num_adjacent==0) pos = trail.pop(); if (num_adjacent == 0) pos = trail.pop();
} }
//println("FAIL=" + steps + " - " + (pos.subtract(collection_pos))); //println("FAIL=" + steps + " - " + (pos.subtract(collection_pos)));
//String s = new String(); for(BlockPos p:checked) s += "\n" + p; println(s); //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; last_pick_pos_ = collection_pos;
search_offsets_ = null; // try other search order search_offsets_ = null; // try other search order
++no_fluid_found_counter_; ++no_fluid_found_counter_;
return false; return false;
} }
public void tick() public void tick() {
{ if ((level.isClientSide) || (--tick_timer_ > 0)) return;
if((level.isClientSide) || (--tick_timer_ > 0)) return;
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
collection_timer_ += TICK_INTERVAL; collection_timer_ += TICK_INTERVAL;
final BlockState funnel_state = level.getBlockState(worldPosition); final BlockState funnel_state = level.getBlockState(worldPosition);
if(!(funnel_state.getBlock() instanceof FluidFunnelBlock)) return; if (!(funnel_state.getBlock() instanceof FluidFunnelBlock)) return;
boolean dirty = false; boolean dirty = false;
// Collection // 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; collection_timer_ = 0;
if(!level.hasNeighborSignal(worldPosition)) { // redstone disable feature if (!level.hasNeighborSignal(worldPosition)) { // redstone disable feature
if(last_pick_pos_==null) last_pick_pos_ = worldPosition.above(); if (last_pick_pos_ == null) last_pick_pos_ = worldPosition.above();
BlockEntity te = with_device_fluid_handler_collection ? (level.getBlockEntity(worldPosition.above())) : (null); 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); IFluidHandler fh = te.getCapability(ForgeCapabilities.FLUID_HANDLER, Direction.DOWN).orElse(null);
if(fh == null) { if (fh == null) {
te = null; te = null;
} else if(tank_.isEmpty()) { } else if (tank_.isEmpty()) {
FluidStack fs = fh.drain(1000, IFluidHandler.FluidAction.EXECUTE); 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; dirty = true;
} else if (!tank_.isFull()) { } 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); tank_.fill(fh.drain(todrain, IFluidHandler.FluidAction.EXECUTE), IFluidHandler.FluidAction.EXECUTE);
dirty = true; dirty = true;
} }
} }
if(te==null) { if (te == null) {
if(try_collect(worldPosition.above())) dirty = true; if (try_collect(worldPosition.above())) dirty = true;
} }
} }
} }
// Gravity fluid transfer // Gravity fluid transfer
if((tank_.getFluidAmount() >= 1000)) { if ((tank_.getFluidAmount() >= 1000)) {
final IFluidHandler fh = Fluidics.handler(level, worldPosition.below(), Direction.UP); final IFluidHandler fh = Fluidics.handler(level, worldPosition.below(), Direction.UP);
if(fh != null) { if (fh != null) {
FluidStack fs = new FluidStack(tank_.getFluid().getFluid(), 1000); FluidStack fs = new FluidStack(tank_.getFluid().getFluid(), 1000);
int nfilled = Mth.clamp(fh.fill(fs, IFluidHandler.FluidAction.EXECUTE), 0, 1000); int nfilled = Mth.clamp(fh.fill(fs, IFluidHandler.FluidAction.EXECUTE), 0, 1000);
tank_.drain(nfilled); tank_.drain(nfilled);
@ -398,9 +412,10 @@ public class EdFluidFunnel
} }
} }
// Block state // Block state
int fill_level = (tank_==null) ? 0 : (Mth.clamp(tank_.getFluidAmount()/1000,0, FluidFunnelBlock.FILL_LEVEL_MAX)); 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 (funnel_state.getValue(FluidFunnelBlock.FILL_LEVEL) != fill_level)
if(dirty) setChanged(); 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; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; 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.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; 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.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour; 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.energy.IEnergyStorage;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler; 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.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class EdFreezer public class EdFreezer {
{ public static void on_config(int consumption, int cooldown_per_second) {
public static void on_config(int consumption, int cooldown_per_second) FreezerTileEntity.on_config(consumption, cooldown_per_second);
{ FreezerTileEntity.on_config(consumption, cooldown_per_second); } }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Block // 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 int PHASE_MAX = 4;
public static final IntegerProperty PHASE = IntegerProperty.create("phase", 0, PHASE_MAX); public static final IntegerProperty PHASE = IntegerProperty.create("phase", 0, PHASE_MAX);
public FreezerBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) public FreezerBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
{ super(config, builder, unrotatedAABB); } super(config, builder, unrotatedAABB);
}
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
{ return Shapes.block(); } return Shapes.block();
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(PHASE); } super.createBlockStateDefinition(builder);
builder.add(PHASE);
}
@Override @Override
@Nullable @Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) public BlockState getStateForPlacement(BlockPlaceContext context) {
{ return super.getStateForPlacement(context).setValue(PHASE, 0); } return super.getStateForPlacement(context).setValue(PHASE, 0);
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state) public boolean hasAnalogOutputSignal(BlockState state) {
{ return true; } return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
{ return Mth.clamp((state.getValue(PHASE)*4), 0, 15); } return Mth.clamp((state.getValue(PHASE) * 4), 0, 15);
}
@Override @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 @Override
public boolean hasDynamicDropList() public boolean hasDynamicDropList() {
{ return true; } return true;
}
@Override @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<>(); final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks; if (world.isClientSide) return stacks;
if(!(te instanceof FreezerTileEntity)) return stacks; if (!(te instanceof FreezerTileEntity)) return stacks;
((FreezerTileEntity)te).reset_process(); ((FreezerTileEntity) te).reset_process();
stacks.add(new ItemStack(this, 1)); stacks.add(new ItemStack(this, 1));
return stacks; return stacks;
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
{ if (player.isShiftKeyDown()) return InteractionResult.PASS;
if(player.isShiftKeyDown()) return InteractionResult.PASS; if (world.isClientSide()) return InteractionResult.SUCCESS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
FreezerTileEntity te = getTe(world, pos); FreezerTileEntity te = getTe(world, pos);
if(te==null) return InteractionResult.FAIL; if (te == null) return InteractionResult.FAIL;
final ItemStack stack = player.getItemInHand(hand); final ItemStack stack = player.getItemInHand(hand);
boolean dirty = false; 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); world.playSound(null, pos, SoundEvents.BUCKET_EMPTY, SoundSource.BLOCKS, 0.5f, 1.4f);
return InteractionResult.CONSUME; return InteractionResult.CONSUME;
} }
if(stack.getItem()==Items.WATER_BUCKET) { if (stack.getItem() == Items.WATER_BUCKET) {
return InteractionResult.CONSUME; // would be already handled return InteractionResult.CONSUME; // would be already handled
} else if(stack.isEmpty()) { } else if (stack.isEmpty()) {
ItemStack ice = te.getIceItem(true); ItemStack ice = te.getIceItem(true);
if(!ice.isEmpty()) { if (!ice.isEmpty()) {
player.addItem(ice); player.addItem(ice);
world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 0.3f, 1.1f); world.playSound(null, pos, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 0.3f, 1.1f);
} else { } else {
@ -150,25 +156,27 @@ public class EdFreezer
} }
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } return false;
}
@Override @Override
@OnlyIn(Dist.CLIENT) @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 @Nullable
private FreezerTileEntity getTe(Level world, BlockPos pos) private FreezerTileEntity getTe(Level world, BlockPos pos) {
{ final BlockEntity te=world.getBlockEntity(pos); return (!(te instanceof FreezerTileEntity)) ? (null) : ((FreezerTileEntity)te); } final BlockEntity te = world.getBlockEntity(pos);
return (!(te instanceof FreezerTileEntity)) ? (null) : ((FreezerTileEntity) te);
}
} }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Tile entity // 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 TICK_INTERVAL = 20;
public static final int MAX_FLUID_LEVEL = 2000; public static final int MAX_FLUID_LEVEL = 2000;
public static final int MAX_ENERGY_BUFFER = 32000; 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 energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static int cooldown_rate = DEFAULT_COOLDOWN_RATE; private static int cooldown_rate = DEFAULT_COOLDOWN_RATE;
private static int reheat_rate = 1; 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 tick_timer_;
private int energy_stored_; private int energy_stored_;
private int progress_; private int progress_;
private boolean force_block_update_; 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); energy_consumption = Mth.clamp(consumption, 8, 4096);
cooldown_rate = Mth.clamp(cooldown_per_second, 1, 5); 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."); ModConfig.log("Config freezer energy consumption:" + energy_consumption + "rf/t, cooldown-rate: " + cooldown_rate + "%/s.");
} }
public FreezerTileEntity(BlockPos pos, BlockState state) public int progress() {
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); } return progress_;
}
public int progress() public int phase() {
{ return progress_; } if (tank_.getFluidAmount() < 1000) return PHASE_EMPTY;
if (progress_ >= 100) return PHASE_BLUEICE;
public int phase() if (progress_ >= 70) return PHASE_PACKEDICE;
{ if (progress_ >= 30) return PHASE_ICE;
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; return PHASE_WATER;
} }
public ItemStack getIceItem(boolean extract) public ItemStack getIceItem(boolean extract) {
{
ItemStack stack; ItemStack stack;
switch(phase()) { switch (phase()) {
case PHASE_ICE: stack = new ItemStack(Items.ICE); break; case PHASE_ICE:
case PHASE_PACKEDICE: stack = new ItemStack(Items.PACKED_ICE); break; stack = new ItemStack(Items.ICE);
case PHASE_BLUEICE: stack = new ItemStack(Items.BLUE_ICE); break; break;
default: return ItemStack.EMPTY; 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; return stack;
} }
public int comparator_signal() public int comparator_signal() {
{ return phase() * 4; } return phase() * 4;
}
protected void reset_process() // BlockEntity ------------------------------------------------------------------------------
{
protected void reset_process() {
force_block_update_ = true; force_block_update_ = true;
tank_.drain(1000); tank_.drain(1000);
tick_timer_ = 0; tick_timer_ = 0;
progress_ = 0; progress_ = 0;
} }
public void readnbt(CompoundTag nbt) public void readnbt(CompoundTag nbt) {
{
energy_stored_ = nbt.getInt("energy"); energy_stored_ = nbt.getInt("energy");
progress_ = nbt.getInt("progress"); progress_ = nbt.getInt("progress");
tank_.load(nbt); tank_.load(nbt);
} }
protected void writenbt(CompoundTag nbt) protected void writenbt(CompoundTag nbt) {
{ nbt.putInt("energy", Mth.clamp(energy_stored_, 0, MAX_ENERGY_BUFFER));
nbt.putInt("energy", Mth.clamp(energy_stored_,0 , MAX_ENERGY_BUFFER)); nbt.putInt("progress", Mth.clamp(progress_, 0, 100));
nbt.putInt("progress", Mth.clamp(progress_,0 , 100));
tank_.save(nbt); tank_.save(nbt);
} }
// BlockEntity ------------------------------------------------------------------------------ // IItemHandler --------------------------------------------------------------------------------
@Override @Override
public void load(CompoundTag nbt) public void load(CompoundTag nbt) {
{ super.load(nbt); readnbt(nbt); } super.load(nbt);
readnbt(nbt);
}
@Override @Override
protected void saveAdditional(CompoundTag nbt) protected void saveAdditional(CompoundTag nbt) {
{ super.saveAdditional(nbt); writenbt(nbt); } super.saveAdditional(nbt);
writenbt(nbt);
}
// IFluidHandler --------------------------------------------------------------------------------
@Override @Override
public void setRemoved() public void setRemoved() {
{
super.setRemoved(); super.setRemoved();
energy_handler_.invalidate(); energy_handler_.invalidate();
fluid_handler_.invalidate(); fluid_handler_.invalidate();
item_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 ---------------------------------------------------------------------------- // IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> this); @Override
public boolean canExtract() {
return false;
}
@Override @Override
public boolean canExtract() public boolean canReceive() {
{ return false; } return true;
}
@Override @Override
public boolean canReceive() public int getMaxEnergyStored() {
{ return true; } return MAX_ENERGY_BUFFER;
}
@Override @Override
public int getMaxEnergyStored() public int getEnergyStored() {
{ return MAX_ENERGY_BUFFER; } return energy_stored_;
}
@Override @Override
public int getEnergyStored() public int extractEnergy(int maxExtract, boolean simulate) {
{ return energy_stored_; } return 0;
}
@Override @Override
public int extractEnergy(int maxExtract, boolean simulate) public int receiveEnergy(int maxReceive, boolean simulate) {
{ return 0; } if (energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
@Override
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_)); int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER; if (n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; setChanged(); } if (!simulate) {
energy_stored_ += n;
setChanged();
}
return n; 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 ---------------------------------------------------------------------------- // Capability export ----------------------------------------------------------------------------
@Override @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) public void tick() {
{ if (level.isClientSide) return;
if(capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast(); if (--tick_timer_ > 0) return;
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast(); tick_timer_ = TICK_INTERVAL;
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast(); BlockState state = level.getBlockState(worldPosition);
return super.getCapability(capability, facing); 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 ------------------------------------------------------------------------------------ // ITickable ------------------------------------------------------------------------------------
protected static class FreezerItemHandler implements IItemHandler {
private final FreezerTileEntity te;
FreezerItemHandler(FreezerTileEntity te) {
this.te = te;
}
@Override @Override
public void tick() public int getSlots() {
{ return 1;
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) { @Override
level.playSound(null, worldPosition, SoundEvents.SAND_FALL, SoundSource.BLOCKS, 0.2f, 0.7f); public int getSlotLimit(int index) {
} else if(new_phase < last_phase) { return 1;
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))) { @Override
state = state.setValue(FreezerBlock.PHASE, new_phase); public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
level.setBlock(worldPosition, state,3|16); return false;
level.updateNeighborsAt(getBlockPos(), state.getBlock()); }
force_block_update_ = 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; 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.core.Direction;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.item.DyeColor; 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.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
public class EdGlassBlock extends StainedGlassBlock implements StandardBlocks.IStandardBlock public class EdGlassBlock extends StainedGlassBlock implements StandardBlocks.IStandardBlock {
{ public EdGlassBlock(long config, BlockBehaviour.Properties properties) {
public EdGlassBlock(long config, BlockBehaviour.Properties properties) super(DyeColor.BLACK, properties);
{ super(DyeColor.BLACK, properties); } }
@Override @Override
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
{ Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); } Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
}
@Override @Override
public StandardBlocks.IStandardBlock.RenderTypeHint getRenderTypeHint() public StandardBlocks.IStandardBlock.RenderTypeHint getRenderTypeHint() {
{ return StandardBlocks.IStandardBlock.RenderTypeHint.TRANSLUCENT; } return StandardBlocks.IStandardBlock.RenderTypeHint.TRANSLUCENT;
}
@Override @Override
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) {
{ return (adjacentBlockState.getBlock()==this) || (super.skipRendering(state, adjacentBlockState, side)); } return (adjacentBlockState.getBlock() == this) || (super.skipRendering(state, adjacentBlockState, side));
}
@Override @Override
public boolean isPossibleToRespawnInThis() public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
{ return false; } return false;
}
} }

View file

@ -8,6 +8,8 @@
*/ */
package dev.zontreck.engineerdecor.blocks; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents; 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.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader; 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.Block;
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState; 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.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; 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 OPEN = BlockStateProperties.OPEN;
public static final BooleanProperty POWERED = BlockStateProperties.POWERED; public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
protected final List<VoxelShape> vshapes_open; protected final List<VoxelShape> vshapes_open;
public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABBClosed, final AABB unrotatedAABBOpen) public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABBClosed, final AABB unrotatedAABBOpen) {
{ super(config, builder, unrotatedAABBClosed);
super(config, builder, unrotatedAABBClosed); vshapes_open = makeHorizontalShapeLookup(new AABB[]{unrotatedAABBOpen}); vshapes_open = makeHorizontalShapeLookup(new AABB[]{unrotatedAABBOpen});
registerDefaultState(super.defaultBlockState().setValue(OPEN, false).setValue(POWERED, false)); registerDefaultState(super.defaultBlockState().setValue(OPEN, false).setValue(POWERED, false));
} }
public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBsClosed, final AABB[] unrotatedAABBsOpen) public EdHatchBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBsClosed, final AABB[] unrotatedAABBsOpen) {
{ super(config, builder, unrotatedAABBsClosed); vshapes_open = makeHorizontalShapeLookup(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( return List.of(
Shapes.block(), Shapes.block(),
Shapes.block(), Shapes.block(),
@ -70,71 +71,77 @@ public class EdHatchBlock extends StandardBlocks.HorizontalWaterLoggable
} }
@Override @Override
public RenderTypeHint getRenderTypeHint() public RenderTypeHint getRenderTypeHint() {
{ return RenderTypeHint.CUTOUT; } return RenderTypeHint.CUTOUT;
}
@Override @Override
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext 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); } return state.getValue(OPEN) ? vshapes_open.get((state.getValue(HORIZONTAL_FACING)).get3DDataValue()) : super.getShape(state, source, pos, selectionContext);
}
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) public VoxelShape getCollisionShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
{ return getShape(state, source, pos, selectionContext); } return getShape(state, source, pos, selectionContext);
}
@Override @Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
{ return state.getValue(OPEN); } return state.getValue(OPEN);
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) {
{ return !state.getValue(OPEN); } return !state.getValue(OPEN);
}
@Override @Override
public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity) public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity) {
{ if (!state.getValue(OPEN)) return false;
if(!state.getValue(OPEN)) return false;
{ {
final BlockState up_state = world.getBlockState(pos.above()); final BlockState up_state = world.getBlockState(pos.above());
if(up_state.is(this) && (up_state.getValue(OPEN))) return true; if (up_state.is(this) && (up_state.getValue(OPEN))) return true;
if(up_state.isLadder(world, pos.above(), entity)) return true; if (up_state.isLadder(world, pos.above(), entity)) return true;
} }
{ {
final BlockState down_state = world.getBlockState(pos.below()); final BlockState down_state = world.getBlockState(pos.below());
if(down_state.is(this) && (down_state.getValue(OPEN))) return true; if (down_state.is(this) && (down_state.getValue(OPEN))) return true;
if(down_state.isLadder(world, pos.below(), entity)) return true; if (down_state.isLadder(world, pos.below(), entity)) return true;
} }
return false; return false;
} }
@Override @Override
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
{ return false; } return false;
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(OPEN, POWERED); } super.createBlockStateDefinition(builder);
builder.add(OPEN, POWERED);
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
{ if (world.isClientSide()) return InteractionResult.SUCCESS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
boolean open = !state.getValue(OPEN); boolean open = !state.getValue(OPEN);
world.setBlock(pos, state.setValue(OPEN, open), 1|2); 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.playSound(null, pos, open ? SoundEvents.IRON_DOOR_OPEN : SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, 0.7f, 1.4f);
return InteractionResult.CONSUME; return InteractionResult.CONSUME;
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) {
{ if ((world.isClientSide) || (!(state.getBlock() instanceof EdHatchBlock))) return;
if((world.isClientSide) || (!(state.getBlock() instanceof EdHatchBlock))) return;
boolean powered = world.hasNeighborSignal(pos); boolean powered = world.hasNeighborSignal(pos);
if(powered == state.getValue(POWERED)) return; 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); if (powered != state.getValue(OPEN))
world.setBlock(pos, state.setValue(OPEN, powered).setValue(POWERED, powered), 1|2); 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 @Override
@ -150,21 +157,21 @@ public class EdHatchBlock extends StandardBlocks.HorizontalWaterLoggable
} }
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } return false;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
{ if ((!state.getValue(OPEN)) || (!(entity instanceof final Player player))) return;
if((!state.getValue(OPEN)) || (!(entity instanceof final Player player))) return; if (player.isSteppingCarefully()) return;
if(player.isSteppingCarefully()) return; if (entity.getLookAngle().y() > -0.75) return;
if(entity.getLookAngle().y() > -0.75) return; if (player.getDirection() != state.getValue(HORIZONTAL_FACING)) return;
if(player.getDirection() != state.getValue(HORIZONTAL_FACING)) return;
Vec3 ppos = player.position(); Vec3 ppos = player.position();
Vec3 centre = Vec3.atBottomCenterOf(pos); Vec3 centre = Vec3.atBottomCenterOf(pos);
Vec3 v = centre.subtract(ppos); 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); v = v.scale(0.2);
player.push(v.x, -0.1, v.z); 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; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents; 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.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraft.world.phys.shapes.VoxelShape;
import dev.zontreck.engineerdecor.ModContent; 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 javax.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
@ -85,8 +85,9 @@ public class EdHorizontalSupportBlock extends StandardBlocks.WaterLoggable
{ return RenderTypeHint.CUTOUT; } { return RenderTypeHint.CUTOUT; }
@Override @Override
public boolean isPossibleToRespawnInThis() public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
{ return false; } return false;
}
@Override @Override
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) 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; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component; 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.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; 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 javax.annotation.Nullable;
import java.util.List; 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 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_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)); 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)); protected static final VoxelShape EDLADDER_NORTH_AABB = Shapes.create(Auxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.NORTH, false));
private static boolean without_speed_boost_ = 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; without_speed_boost_ = without_speed_boost;
ModConfig.log("Config ladder: without-speed-boost:" + without_speed_boost_); ModConfig.log("Config ladder: without-speed-boost:" + without_speed_boost_);
} }
public EdLadderBlock(long config, BlockBehaviour.Properties builder) // Player update event, forwarded from the main mod instance.
{ super(builder); } 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 @Override
public RenderTypeHint getRenderTypeHint() public RenderTypeHint getRenderTypeHint() {
{ return RenderTypeHint.CUTOUT; } return RenderTypeHint.CUTOUT;
}
@Override @Override
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
{ Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); } Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
}
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos) public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos) {
{ return switch (state.getValue(FACING)) {
return switch(state.getValue(FACING)) {
case NORTH -> EDLADDER_NORTH_AABB; case NORTH -> EDLADDER_NORTH_AABB;
case SOUTH -> EDLADDER_SOUTH_AABB; case SOUTH -> EDLADDER_SOUTH_AABB;
case WEST -> EDLADDER_WEST_AABB; case WEST -> EDLADDER_WEST_AABB;
@ -80,44 +105,24 @@ public class EdLadderBlock extends LadderBlock implements StandardBlocks.IStanda
} }
@Override @Override
public boolean isPossibleToRespawnInThis() public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
{ return false; } return false;
}
@Override @Override
public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType<?> entityType) {
{ return false; } return false;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public PushReaction getPistonPushReaction(BlockState state) public PushReaction getPistonPushReaction(BlockState state) {
{ return PushReaction.NORMAL; } return PushReaction.NORMAL;
}
@Override @Override
public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity) public boolean isLadder(BlockState state, LevelReader world, BlockPos pos, LivingEntity entity) {
{ return true; } 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));
}
} }
} }

View file

@ -8,7 +8,10 @@
*/ */
package dev.zontreck.engineerdecor.blocks; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; 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.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader; 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.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour; 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.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import wile.engineersdecor.libmc.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
@ -62,34 +63,31 @@ import java.util.Map.Entry;
import java.util.UUID; import java.util.UUID;
public class EdMilker public class EdMilker {
{
public static final int BUCKET_SIZE = 1000; public static final int BUCKET_SIZE = 1000;
public static final int TICK_INTERVAL = 80; public static final int TICK_INTERVAL = 80;
public static final int PROCESSING_TICK_INTERVAL = 20; public static final int PROCESSING_TICK_INTERVAL = 20;
public static final int TANK_CAPACITY = BUCKET_SIZE * 12; 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 FILLED_INDICATION_THRESHOLD = BUCKET_SIZE;
public static final int MAX_ENERGY_BUFFER = 16000; public static final int MAX_ENERGY_BUFFER = 16000;
public static final int MAX_ENERGY_TRANSFER = 512; public static final int MAX_ENERGY_TRANSFER = 512;
public static final int DEFAULT_ENERGY_CONSUMPTION = 0; public static final int DEFAULT_ENERGY_CONSUMPTION = 0;
public static final int DEFAULT_MILKING_DELAY_PER_COW = 4000; public static final int DEFAULT_MILKING_DELAY_PER_COW = 4000;
private static final FluidStack NO_MILK_FLUID = new FluidStack(Fluids.WATER, 1000); 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 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 int energy_consumption_ = DEFAULT_ENERGY_CONSUMPTION;
private static long min_milking_delay_per_cow_ticks_ = DEFAULT_MILKING_DELAY_PER_COW; 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); 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); 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); ResourceLocation milk_rl = ForgeRegistries.FLUIDS.getKeys().stream().filter(rl -> rl.getPath().equals("milk")).findFirst().orElse(null);
if(milk_rl != null) { if (milk_rl != null) {
Fluid milk = ForgeRegistries.FLUIDS.getValue(milk_rl); 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( ModConfig.log(
"Config milker: energy consumption:" + energy_consumption_ + "rf/t" "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 // 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 FILLED = BooleanProperty.create("filled");
public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); 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); 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 @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(ACTIVE); builder.add(FILLED); } super.createBlockStateDefinition(builder);
builder.add(ACTIVE);
builder.add(FILLED);
}
@Override @Override
@Nullable @Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) public BlockState getStateForPlacement(BlockPlaceContext context) {
{ return super.getStateForPlacement(context).setValue(FILLED, false).setValue(ACTIVE, false); } 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);
} }
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) @SuppressWarnings("deprecation")
{ return false; } public boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
{
if(world.isClientSide()) return InteractionResult.SUCCESS;
MilkerTileEntity te = getTe(world, 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 in_stack = player.getItemInHand(hand);
final ItemStack out_stack = MilkerTileEntity.milk_filled_container_item(in_stack); final ItemStack out_stack = MilkerTileEntity.milk_filled_container_item(in_stack);
if(in_stack.isEmpty()) { if (in_stack.isEmpty()) {
te.state_message(player); te.state_message(player);
return InteractionResult.CONSUME; 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; return Fluidics.manualFluidHandlerInteraction(player, hand, te.fluid_handler()) ? InteractionResult.CONSUME : InteractionResult.FAIL;
} else { } else {
boolean drained = false; boolean drained = false;
IItemHandler player_inventory = Inventories.itemhandler(player); 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(); final ItemStack insert_stack = out_stack.copy();
ItemStack remainder = ItemHandlerHelper.insertItemStacked(player_inventory, insert_stack, false); 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); te.drain(BUCKET_SIZE);
in_stack.shrink(1); in_stack.shrink(1);
drained = true; drained = true;
if(remainder.getCount() > 0) { if (remainder.getCount() > 0) {
final ItemEntity ei = new ItemEntity(world, player.position().x(), player.position().y()+0.5, player.position().z(), remainder); final ItemEntity ei = new ItemEntity(world, player.position().x(), player.position().y() + 0.5, player.position().z(), remainder);
ei.setPickUpDelay(40); ei.setPickUpDelay(40);
ei.setDeltaMovement(0,0,0); ei.setDeltaMovement(0, 0, 0);
world.addFreshEntity(ei); world.addFreshEntity(ei);
} }
} }
} }
if(drained) { if (drained) {
world.playSound(null, pos, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 0.8f, 1f); world.playSound(null, pos, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 0.8f, 1f);
} }
} }
@ -186,8 +187,10 @@ public class EdMilker
} }
@Nullable @Nullable
private MilkerTileEntity getTe(Level world, BlockPos pos) private MilkerTileEntity getTe(Level world, BlockPos pos) {
{ final BlockEntity te=world.getBlockEntity(pos); return (!(te instanceof MilkerTileEntity)) ? (null) : ((MilkerTileEntity)te); } 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 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 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 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 int tick_timer_;
private UUID tracked_cow_ = null; private UUID tracked_cow_ = null;
private MilkingState state_ = MilkingState.IDLE; private MilkingState state_ = MilkingState.IDLE;
private int state_timeout_ = 0; private int state_timeout_ = 0;
private int state_timer_ = 0; private int state_timer_ = 0;
private BlockPos tracked_cow_original_position_ = null; 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); 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(); fluid_handler_ = tank_.createOutputFluidHandler();
battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0); battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0);
energy_handler_ = battery_.createEnergyHandler(); energy_handler_ = battery_.createEnergyHandler();
reset(); 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(); tank_.clear();
battery_.clear(); battery_.clear();
tick_timer_ = 0; tick_timer_ = 0;
@ -230,115 +234,115 @@ public class EdMilker
state_timeout_ = 0; state_timeout_ = 0;
} }
public CompoundTag destroy_getnbt() public CompoundTag destroy_getnbt() {
{
final UUID cowuid = tracked_cow_; final UUID cowuid = tracked_cow_;
CompoundTag nbt = new CompoundTag(); CompoundTag nbt = new CompoundTag();
writenbt(nbt, false); reset(); writenbt(nbt, false);
if(cowuid == null) return nbt; reset();
level.getEntitiesOfClass(Cow.class, new AABB(worldPosition).inflate(16, 16, 16), e->e.getUUID().equals(cowuid)).forEach(e->e.setNoAi(false)); 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; return nbt;
} }
public void readnbt(CompoundTag nbt, boolean update_packet) public void readnbt(CompoundTag nbt, boolean update_packet) {
{
battery_.load(nbt); battery_.load(nbt);
tank_.load(nbt); tank_.load(nbt);
} }
protected void writenbt(CompoundTag nbt, boolean update_packet) protected void writenbt(CompoundTag nbt, boolean update_packet) {
{
tank_.save(nbt); tank_.save(nbt);
if(!battery_.isEmpty()) battery_.save(nbt); if (!battery_.isEmpty()) battery_.save(nbt);
} }
private boolean has_milk_fluid() private boolean has_milk_fluid() {
{ return !(NO_MILK_FLUID.isFluidEqual(milk_fluid_)); } return !(NO_MILK_FLUID.isFluidEqual(milk_fluid_));
}
private IFluidHandler fluid_handler() private IFluidHandler fluid_handler() {
{ return fluid_handler_.orElse(null); } return fluid_handler_.orElse(null);
}
private int fluid_level() private int fluid_level() {
{ return tank_.getFluidAmount(); } return tank_.getFluidAmount();
}
private FluidStack drain(int amount) private FluidStack drain(int amount) {
{ return tank_.drain(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));
} }
// BlockEntity ------------------------------------------------------------------------------ // BlockEntity ------------------------------------------------------------------------------
@Override public void state_message(Player player) {
public void load(CompoundTag nbt) Component rf = (energy_consumption_ <= 0) ? (Component.empty()) : (Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status.rf", battery_.getEnergyStored()));
{ super.load(nbt); readnbt(nbt, false); } Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status", tank_.getFluidAmount(), rf));
}
@Override @Override
protected void saveAdditional(CompoundTag nbt) public void load(CompoundTag nbt) {
{ super.saveAdditional(nbt); writenbt(nbt, false); } super.load(nbt);
readnbt(nbt, false);
}
@Override @Override
public void setRemoved() protected void saveAdditional(CompoundTag nbt) {
{ super.saveAdditional(nbt);
super.setRemoved(); writenbt(nbt, false);
energy_handler_.invalidate();
fluid_handler_.invalidate();
} }
// ICapabilityProvider --------------------------------------------------------------------------- // ICapabilityProvider ---------------------------------------------------------------------------
@Override @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) public void setRemoved() {
{ super.setRemoved();
if((capability == ForgeCapabilities.FLUID_HANDLER) && has_milk_fluid()) return fluid_handler_.cast(); energy_handler_.invalidate();
if((capability == ForgeCapabilities.ENERGY) && (energy_consumption_>0)) return energy_handler_.cast(); fluid_handler_.invalidate();
return super.getCapability(capability, facing);
} }
// ITickable ------------------------------------------------------------------------------------ // 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) private void log(String s) {
{} // println("Milker|" + s); may be enabled with config, for dev was println } // println("Milker|" + s); may be enabled with config, for dev was println
private static ItemStack milk_filled_container_item(ItemStack stack) private boolean fill_adjacent_inventory_item_containers(Direction block_facing) {
{ 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)
{
// Check inventory existence, back to down is preferred, otherwise sort back into same inventory. // 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 src = Inventories.itemhandler(level, worldPosition.relative(block_facing), block_facing.getOpposite());
IItemHandler dst = Inventories.itemhandler(level, worldPosition.below(), Direction.UP); IItemHandler dst = Inventories.itemhandler(level, worldPosition.below(), Direction.UP);
if(src==null) { src = dst; } else if(dst==null) { dst = src; } if (src == null) {
if((src==null) || (dst==null)) return false; src = dst;
} else if (dst == null) {
dst = src;
}
if ((src == null) || (dst == null)) return false;
boolean dirty = false; boolean dirty = false;
while((tank_.getFluidAmount() >= BUCKET_SIZE)) { while ((tank_.getFluidAmount() >= BUCKET_SIZE)) {
boolean inserted = false; boolean inserted = false;
for(Entry<ItemStack,ItemStack> e:milk_containers_.entrySet()) { for (Entry<ItemStack, ItemStack> e : milk_containers_.entrySet()) {
if(Inventories.extract(src, e.getKey(), 1, true).isEmpty()) continue; if (Inventories.extract(src, e.getKey(), 1, true).isEmpty()) continue;
if(!Inventories.insert(dst, e.getValue().copy(), false).isEmpty()) continue; if (!Inventories.insert(dst, e.getValue().copy(), false).isEmpty()) continue;
Inventories.extract(src, e.getKey(), 1, false); Inventories.extract(src, e.getKey(), 1, false);
tank_.drain(BUCKET_SIZE); tank_.drain(BUCKET_SIZE);
inserted = true; inserted = true;
dirty = true; dirty = true;
break; break;
} }
if(!inserted) break; if (!inserted) break;
} }
return dirty; return dirty;
} }
private boolean fill_adjacent_tank() private boolean fill_adjacent_tank() {
{ if ((fluid_level() <= 0) || (!has_milk_fluid())) return false;
if((fluid_level()<=0) || (!has_milk_fluid())) return false;
final FluidStack fs = new FluidStack(milk_fluid_, Math.max(fluid_level(), BUCKET_SIZE)); 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); int amount = Fluidics.fill(getLevel(), getBlockPos().relative(dir), dir.getOpposite(), fs);
if(amount > 0) { if (amount > 0) {
tank_.drain(amount); tank_.drain(amount);
return true; return true;
} }
@ -346,14 +350,13 @@ public class EdMilker
return false; return false;
} }
private void release_cow(Cow cow) private void release_cow(Cow cow) {
{
log("release cow"); log("release cow");
if(cow != null) { if (cow != null) {
cow.setNoAi(false); cow.setNoAi(false);
SingleMoveGoal.abortFor(cow); SingleMoveGoal.abortFor(cow);
tracked_cows_.remove(cow.getId()); 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); tracked_cows_.remove(id);
} }
} }
@ -362,44 +365,54 @@ public class EdMilker
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
} }
private boolean milking_process() private boolean milking_process() {
{ if ((tracked_cow_ == null) && (fluid_level() >= MAX_MILKING_TANK_LEVEL)) return false; // nothing to do
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 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; Cow cow = null;
{ {
AABB aabb = new AABB(worldPosition.relative(facing, 3)).inflate(4, 2, 4); AABB aabb = new AABB(worldPosition.relative(facing, 3)).inflate(4, 2, 4);
final long t = level.getGameTime(); final long t = level.getGameTime();
final List<Cow> cows = level.getEntitiesOfClass(Cow.class, aabb, final List<Cow> cows = level.getEntitiesOfClass(Cow.class, aabb,
e-> { e -> {
if(e.getUUID().equals(tracked_cow_)) return true; if (e.getUUID().equals(tracked_cow_)) return true;
if((tracked_cow_!=null) || e.isBaby() || e.isInLove() || e.isVehicle()) return false; if ((tracked_cow_ != null) || e.isBaby() || e.isInLove() || e.isVehicle()) return false;
if(!e.getNavigation().isDone()) 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; if (Math.abs(tracked_cows_.getOrDefault(e.getId(), 0L) - t) < min_milking_delay_per_cow_ticks_)
return false;
return true; return true;
} }
); );
if(cows.size() == 1) { if (cows.size() == 1) {
cow = cows.get(0); // tracked or only one cow = cows.get(0); // tracked or only one
} else if(cows.size() > 1) { } else if (cows.size() > 1) {
cow = cows.get(level.random.nextInt(cows.size()-1)); // pick one 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 ((state_ != MilkingState.IDLE) && ((state_timeout_ -= PROCESSING_TICK_INTERVAL) <= 0)) {
if((cow == null) || (!cow.isAlive())) { release_cow(cow); cow = null; } release_cow(cow);
if(tracked_cow_ == null) state_ = MilkingState.IDLE; log("Cow motion timeout");
if(cow == null) { log("Init: No cow"); return false; } // retry next cycle 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; tick_timer_ = PROCESSING_TICK_INTERVAL;
state_timer_ -= PROCESSING_TICK_INTERVAL; state_timer_ -= PROCESSING_TICK_INTERVAL;
if(state_timer_ > 0) return false; if (state_timer_ > 0) return false;
switch(state_) { // Let's do this the old school FSA sequencing way ... switch (state_) { // Let's do this the old school FSA sequencing way ...
case IDLE -> { case IDLE -> {
final List<LivingEntity> blocking_entities = level.getEntitiesOfClass(LivingEntity.class, new AABB(worldPosition.relative(facing)).inflate(0.5, 0.5, 0.5)); 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; tick_timer_ = TICK_INTERVAL;
log("Idle: Position blocked"); 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); BlockPos p = getBlockPos().relative(facing, 2);
log("Idle: Shove off"); log("Idle: Shove off");
blocker.setNoAi(false); blocker.setNoAi(false);
@ -407,7 +420,7 @@ public class EdMilker
} }
return false; 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; return false;
tracked_cows_.put(cow.getId(), cow.getCommandSenderWorld().getGameTime()); tracked_cows_.put(cow.getId(), cow.getCommandSenderWorld().getGameTime());
tracked_cow_ = cow.getUUID(); tracked_cow_ = cow.getUUID();
@ -433,11 +446,11 @@ public class EdMilker
return false; return false;
} }
case COMING -> { case COMING -> {
if(target_pos.distanceToSqr(cow.position()) <= 1) { if (target_pos.distanceToSqr(cow.position()) <= 1) {
log("Coming: position reached"); log("Coming: position reached");
state_ = MilkingState.POSITIONING; state_ = MilkingState.POSITIONING;
state_timeout_ = 100; // 5s state_timeout_ = 100; // 5s
} else if((!SingleMoveGoal.isActiveFor(cow))) { } else if ((!SingleMoveGoal.isActiveFor(cow))) {
release_cow(cow); release_cow(cow);
log("Coming: aborted"); log("Coming: aborted");
} else { } else {
@ -480,7 +493,7 @@ public class EdMilker
case WAITING -> { case WAITING -> {
// wait for the timeout to kick in until starting with the next. // wait for the timeout to kick in until starting with the next.
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
if(state_timer_ < 40) { if (state_timer_ < 40) {
tracked_cow_ = null; tracked_cow_ = null;
release_cow(null); release_cow(null);
} }
@ -493,52 +506,49 @@ public class EdMilker
} }
@Override @Override
public void tick() public void tick() {
{ if ((level.isClientSide) || ((--tick_timer_ > 0))) return;
if((level.isClientSide) || ((--tick_timer_ > 0))) return;
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
boolean dirty = false; boolean dirty = false;
final BlockState block_state = level.getBlockState(worldPosition); final BlockState block_state = level.getBlockState(worldPosition);
if(!(block_state.getBlock() instanceof MilkerBlock)) return; if (!(block_state.getBlock() instanceof MilkerBlock)) return;
if(!level.hasNeighborSignal(worldPosition) || (state_ != MilkingState.IDLE)) { if (!level.hasNeighborSignal(worldPosition) || (state_ != MilkingState.IDLE)) {
if((energy_consumption_ > 0) && (!battery_.draw(energy_consumption_))) return; if ((energy_consumption_ > 0) && (!battery_.draw(energy_consumption_))) return;
// Track and milk cows // Track and milk cows
if(milking_process()) dirty = true; if (milking_process()) dirty = true;
// Fluid transfer // Fluid transfer
if(has_milk_fluid() && (!tank_.isEmpty())) { if (has_milk_fluid() && (!tank_.isEmpty())) {
log("Fluid transfer"); 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()); 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); final FluidStack fs = tank_.drain(BUCKET_SIZE, IFluidHandler.FluidAction.SIMULATE);
int nfilled = fh.fill(fs, IFluidHandler.FluidAction.EXECUTE); int nfilled = fh.fill(fs, IFluidHandler.FluidAction.EXECUTE);
if(nfilled <= 0) continue; if (nfilled <= 0) continue;
tank_.drain(nfilled, IFluidHandler.FluidAction.EXECUTE); tank_.drain(nfilled, IFluidHandler.FluidAction.EXECUTE);
dirty = true; dirty = true;
break; break;
} }
} }
// Adjacent inventory update, only done just after milking to prevent waste of server cpu. // 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"); 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 // State update
BlockState new_state = block_state.setValue(MilkerBlock.FILLED, fluid_level()>=FILLED_INDICATION_THRESHOLD).setValue(MilkerBlock.ACTIVE, state_==MilkingState.MILKING); 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 (block_state != new_state) level.setBlock(worldPosition, new_state, 1 | 2 | 16);
if(dirty) setChanged(); if (dirty) setChanged();
}
} }
public static class SingleMoveGoal extends MoveToBlockGoal private enum MilkingState {IDLE, PICKED, COMING, POSITIONING, MILKING, LEAVING, WAITING}
{ }
@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);
public static class SingleMoveGoal extends MoveToBlockGoal {
private static final HashMap<Integer, SingleMoveGoal> tracked_entities_ = new HashMap<>(); 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 aborted_;
private boolean in_position_; private boolean in_position_;
private boolean was_aborted_; private boolean was_aborted_;
@ -546,9 +556,7 @@ public class EdMilker
private TargetPositionInValidCheck abort_condition_; private TargetPositionInValidCheck abort_condition_;
private StrollEvent on_target_position_reached_; private StrollEvent on_target_position_reached_;
private StrollEvent on_aborted_; 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); super(creature, speed, 32, 32);
abort_condition_ = abort_condition; abort_condition_ = abort_condition;
on_target_position_reached_ = on_position_reached; on_target_position_reached_ = on_position_reached;
@ -561,18 +569,21 @@ public class EdMilker
target_pos_ = pos; target_pos_ = pos;
} }
public static void startFor(PathfinderMob entity, BlockPos target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition) private static void log(String s) {
{ startFor(entity, new Vec3(target_pos.getX(),target_pos.getY(),target_pos.getZ()), priority, speed, abort_condition, null, null); } } // 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) 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);
synchronized(tracked_entities_) { }
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); SingleMoveGoal goal = tracked_entities_.getOrDefault(entity.getId(), null);
if(goal != null) { if (goal != null) {
if(!goal.aborted()) return false; // that is still running. if (!goal.aborted()) return false; // that is still running.
entity.goalSelector.removeGoal(goal); 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); goal = new SingleMoveGoal(entity, target_pos, speed, abort_condition, on_position_reached, on_aborted);
tracked_entities_.put(entity.getId(), goal); tracked_entities_.put(entity.getId(), goal);
entity.goalSelector.addGoal(priority, goal); entity.goalSelector.addGoal(priority, goal);
@ -580,39 +591,42 @@ public class EdMilker
} }
} }
public static boolean isActiveFor(PathfinderMob entity) public static boolean isActiveFor(PathfinderMob entity) {
{ return (entity != null) && (entity.goalSelector.getRunningGoals().anyMatch( return (entity != null) && (entity.goalSelector.getRunningGoals().anyMatch(
g->((g.getGoal()) instanceof SingleMoveGoal) && (!((SingleMoveGoal)(g.getGoal())).aborted()) g -> ((g.getGoal()) instanceof SingleMoveGoal) && (!((SingleMoveGoal) (g.getGoal())).aborted())
)); } ));
}
public static void abortFor(PathfinderMob entity) public static void abortFor(PathfinderMob entity) {
{ log("::abort(" + entity.getId() + ")");
log("::abort("+entity.getId()+")"); if (entity.isAlive()) {
if(entity.isAlive()) { entity.goalSelector.getRunningGoals().filter(g -> (g.getGoal()) instanceof SingleMoveGoal).forEach(g -> ((SingleMoveGoal) g.getGoal()).abort());
entity.goalSelector.getRunningGoals().filter(g->(g.getGoal()) instanceof SingleMoveGoal).forEach(g->((SingleMoveGoal)g.getGoal()).abort());
} }
final Level world = entity.getCommandSenderWorld(); final Level world = entity.getCommandSenderWorld();
if(world != null) { if (world != null) {
// @todo: check nicer way to filter a map. // @todo: check nicer way to filter a map.
List<Integer> to_remove = tracked_entities_.keySet().stream().filter(i->(world.getEntity(i) == null)).toList(); List<Integer> to_remove = tracked_entities_.keySet().stream().filter(i -> (world.getEntity(i) == null)).toList();
for(int id:to_remove)tracked_entities_.remove(id); for (int id : to_remove) tracked_entities_.remove(id);
} }
} }
public Vec3 getTargetPosition() public Vec3 getTargetPosition() {
{ return target_pos_; } return target_pos_;
}
public PathfinderMob getCreature() public PathfinderMob getCreature() {
{ return mob; } return mob;
}
public synchronized void abort() public synchronized void abort() {
{ aborted_ = true; } aborted_ = true;
}
public synchronized boolean aborted() public synchronized boolean aborted() {
{ return 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; abort_condition_ = abort_condition;
on_target_position_reached_ = on_position_reached; on_target_position_reached_ = on_position_reached;
on_aborted_ = on_aborted; on_aborted_ = on_aborted;
@ -626,28 +640,33 @@ public class EdMilker
} }
@Override @Override
public void stop() public void stop() {
{ nextStartTick = 0; tryTicks = 0; } nextStartTick = 0;
tryTicks = 0;
}
@Override @Override
public double acceptedDistance() public double acceptedDistance() {
{ return 0.7; } return 0.7;
}
@Override @Override
public boolean shouldRecalculatePath() public boolean shouldRecalculatePath() {
{ return (!aborted()) && (tryTicks & 0x7) == 0; } return (!aborted()) && (tryTicks & 0x7) == 0;
}
@Override @Override
public boolean canUse() public boolean canUse() {
{ if (aborted_) {
if(aborted_) { if ((!was_aborted_) && (on_aborted_ != null)) on_aborted_.apply(this, mob.level(), target_pos_);
if((!was_aborted_) && (on_aborted_!=null)) on_aborted_.apply(this, mob.level, target_pos_);
was_aborted_ = true; was_aborted_ = true;
return false; return false;
} else if(!isValidTarget(mob.level, blockPos)) { } else if (!isValidTarget(mob.level(), blockPos)) {
synchronized(this) { aborted_ = true; } synchronized (this) {
aborted_ = true;
}
return false; return false;
} else if(--nextStartTick > 0) { } else if (--nextStartTick > 0) {
return false; return false;
} else { } else {
nextStartTick = 10; nextStartTick = 10;
@ -656,10 +675,9 @@ public class EdMilker
} }
@Override @Override
public void start() public void start() {
{
tryTicks = 0; 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(); abort();
log("startExecuting() -> abort, no path"); log("startExecuting() -> abort, no path");
} else { } else {
@ -667,24 +685,23 @@ public class EdMilker
} }
} }
public boolean canContinueToUse() public boolean canContinueToUse() {
{ if (aborted()) {
if(aborted()) {
log("shouldContinueExecuting() -> already aborted"); log("shouldContinueExecuting() -> already aborted");
return false; return false;
} else if(mob.getNavigation().isDone()) { } else if (mob.getNavigation().isDone()) {
if((!mob.getNavigation().moveTo(mob.getNavigation().createPath(target_pos_.x(), target_pos_.y(), target_pos_.z(), 0), speedModifier))) { if ((!mob.getNavigation().moveTo(mob.getNavigation().createPath(target_pos_.x(), target_pos_.y(), target_pos_.z(), 0), speedModifier))) {
log("shouldContinueExecuting() -> abort, no path"); log("shouldContinueExecuting() -> abort, no path");
abort(); abort();
return false; return false;
} else { } else {
return true; return true;
} }
} else if(tryTicks > motion_timeout) { } else if (tryTicks > motion_timeout) {
log("shouldContinueExecuting() -> abort, timeout"); log("shouldContinueExecuting() -> abort, timeout");
abort(); abort();
return false; return false;
} else if(!isValidTarget(mob.level, blockPos)) { } else if (!isValidTarget(mob.level(), blockPos)) {
log("shouldContinueExecuting() -> abort, !shouldMoveTo()"); log("shouldContinueExecuting() -> abort, !shouldMoveTo()");
abort(); abort();
return false; return false;
@ -695,9 +712,8 @@ public class EdMilker
} }
@Override @Override
protected boolean isValidTarget(LevelReader world, BlockPos pos) protected boolean isValidTarget(LevelReader world, BlockPos pos) {
{ if (abort_condition_.test(this, world, pos)) {
if(abort_condition_.test(this, world, pos)) {
log("shouldMoveTo() -> abort_condition"); log("shouldMoveTo() -> abort_condition");
return false; return false;
} else { } else {
@ -706,16 +722,15 @@ public class EdMilker
} }
@Override @Override
public void tick() public void tick() {
{ final BlockPos testpos = new BlockPos((int) target_pos_.x(), (int) mob.position().y(), (int) target_pos_.z());
final BlockPos testpos = new BlockPos(target_pos_.x(), mob.position().y(), target_pos_.z()); if (!testpos.closerToCenterThan(mob.position(), acceptedDistance())) {
if(!testpos.closerToCenterThan(mob.position(), acceptedDistance())) { if ((++tryTicks > motion_timeout)) {
if((++tryTicks > motion_timeout)) {
log("tick() -> abort, timeoutCounter"); log("tick() -> abort, timeoutCounter");
abort(); abort();
return; 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()"); log("tick() -> abort, !tryMoveToXYZ()");
abort(); abort();
} }
@ -723,8 +738,19 @@ public class EdMilker
log("tick() -> abort, in position)"); log("tick() -> abort, in position)");
in_position_ = true; in_position_ = true;
abort(); 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; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleOptions; 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.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; 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.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity; 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.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.IItemHandler; 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 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 class EdMineralSmelter {
{ public static void on_config(int consumption, int heatup_per_second) {
public static void on_config(int consumption, int heatup_per_second) MineralSmelterTileEntity.on_config(consumption, heatup_per_second);
{ MineralSmelterTileEntity.on_config(consumption, heatup_per_second); } }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Block // 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 int PHASE_MAX = 3;
public static final IntegerProperty PHASE = IntegerProperty.create("phase", 0, PHASE_MAX); public static final IntegerProperty PHASE = IntegerProperty.create("phase", 0, PHASE_MAX);
public MineralSmelterBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) public MineralSmelterBlock(long config, BlockBehaviour.Properties builder, final AABB unrotatedAABB) {
{ super(config, builder, unrotatedAABB); } super(config, builder, unrotatedAABB);
}
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
{ return Shapes.block(); } return Shapes.block();
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(PHASE); } super.createBlockStateDefinition(builder);
builder.add(PHASE);
}
@Override @Override
@Nullable @Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) public BlockState getStateForPlacement(BlockPlaceContext context) {
{ return super.getStateForPlacement(context).setValue(PHASE, 0); } return super.getStateForPlacement(context).setValue(PHASE, 0);
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state) public boolean hasAnalogOutputSignal(BlockState state) {
{ return true; } return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) {
{ return Mth.clamp((state.getValue(PHASE)*5), 0, 15); } return Mth.clamp((state.getValue(PHASE) * 5), 0, 15);
}
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } return false;
}
@Override @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 @Override
public boolean hasDynamicDropList() public boolean hasDynamicDropList() {
{ return true; } return true;
}
@Override @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<>(); final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks; if (world.isClientSide) return stacks;
if(!(te instanceof MineralSmelterTileEntity)) return stacks; if (!(te instanceof MineralSmelterTileEntity)) return stacks;
((MineralSmelterTileEntity)te).reset_process(); ((MineralSmelterTileEntity) te).reset_process();
stacks.add(new ItemStack(this, 1)); stacks.add(new ItemStack(this, 1));
return stacks; return stacks;
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
{ if (player.isShiftKeyDown()) return InteractionResult.PASS;
if(player.isShiftKeyDown()) return InteractionResult.PASS; if (world.isClientSide()) return InteractionResult.SUCCESS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
MineralSmelterTileEntity te = getTe(world, pos); MineralSmelterTileEntity te = getTe(world, pos);
if(te==null) return InteractionResult.FAIL; if (te == null) return InteractionResult.FAIL;
final ItemStack stack = player.getItemInHand(hand); final ItemStack stack = player.getItemInHand(hand);
boolean dirty = false; boolean dirty = false;
if(te.accepts_lava_container(stack)) { if (te.accepts_lava_container(stack)) {
if(stack.sameItemStackIgnoreDurability(MineralSmelterTileEntity.BUCKET_STACK)) { // check how this works with item capabilities or so if (stack.is(MineralSmelterTileEntity.BUCKET_STACK.getItem())) { // check how this works with item capabilities or so
if(te.bucket_extraction_possible()) { if (te.bucket_extraction_possible()) {
if(stack.getCount() > 1) { if (stack.getCount() > 1) {
int target_stack_index = -1; int target_stack_index = -1;
for(int i=0; i<player.getInventory().getContainerSize(); ++i) { for (int i = 0; i < player.getInventory().getContainerSize(); ++i) {
if(player.getInventory().getItem(i).isEmpty()) { if (player.getInventory().getItem(i).isEmpty()) {
target_stack_index = i; target_stack_index = i;
break; break;
} }
} }
if(target_stack_index >= 0) { if (target_stack_index >= 0) {
te.reset_process(); te.reset_process();
stack.shrink(1); stack.shrink(1);
player.setItemInHand(hand, stack); 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); final ItemStack istack = te.extract(true);
if(te.phase() > MineralSmelterTileEntity.PHASE_WARMUP) player.setSecondsOnFire(1); if (te.phase() > MineralSmelterTileEntity.PHASE_WARMUP) player.setSecondsOnFire(1);
if(!istack.isEmpty()) { if (!istack.isEmpty()) {
player.setItemInHand(hand, te.extract(false)); player.setItemInHand(hand, te.extract(false));
dirty = true; dirty = true;
} }
} else if(te.insert(stack,false)) { } else if (te.insert(stack, false)) {
stack.shrink(1); stack.shrink(1);
dirty = true; dirty = true;
} }
if(dirty) player.getInventory().setChanged(); if (dirty) player.getInventory().setChanged();
return InteractionResult.CONSUME; return InteractionResult.CONSUME;
} }
@Override @Override
@OnlyIn(Dist.CLIENT) @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) {
{ if (state.getBlock() != this) return;
if(state.getBlock()!=this) return;
ParticleOptions particle = ParticleTypes.SMOKE; ParticleOptions particle = ParticleTypes.SMOKE;
switch(state.getValue(PHASE)) { switch (state.getValue(PHASE)) {
case MineralSmelterTileEntity.PHASE_WARMUP: case MineralSmelterTileEntity.PHASE_WARMUP:
return; return;
case MineralSmelterTileEntity.PHASE_HOT: case MineralSmelterTileEntity.PHASE_HOT:
if(rnd.nextInt(10) > 4) return; if (rnd.nextInt(10) > 4) return;
break; break;
case MineralSmelterTileEntity.PHASE_MAGMABLOCK: case MineralSmelterTileEntity.PHASE_MAGMABLOCK:
if(rnd.nextInt(10) > 7) return; if (rnd.nextInt(10) > 7) return;
particle = ParticleTypes.LARGE_SMOKE; particle = ParticleTypes.LARGE_SMOKE;
break; break;
case MineralSmelterTileEntity.PHASE_LAVA: case MineralSmelterTileEntity.PHASE_LAVA:
if(rnd.nextInt(10) > 2) return; if (rnd.nextInt(10) > 2) return;
particle = ParticleTypes.LAVA; particle = ParticleTypes.LAVA;
break; break;
default: default:
return; return;
} }
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ(); 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; 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); world.addParticle(particle, x + xr, y + yr, z + zr, 0.0, 0.0, 0.0);
} }
@Nullable @Nullable
private MineralSmelterTileEntity getTe(Level world, BlockPos pos) private MineralSmelterTileEntity getTe(Level world, BlockPos pos) {
{ final BlockEntity te=world.getBlockEntity(pos); return (!(te instanceof MineralSmelterTileEntity)) ? (null) : ((MineralSmelterTileEntity)te); } final BlockEntity te = world.getBlockEntity(pos);
return (!(te instanceof MineralSmelterTileEntity)) ? (null) : ((MineralSmelterTileEntity) te);
}
} }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Tile entity // 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 NUM_OF_SLOTS = 2;
public static final int TICK_INTERVAL = 20; public static final int TICK_INTERVAL = 20;
public static final int MAX_FLUID_LEVEL = 2000; 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 energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static int heatup_rate = DEFAULT_HEATUP_RATE; private static int heatup_rate = DEFAULT_HEATUP_RATE;
private static int cooldown_rate = 1; private static int cooldown_rate = 1;
private int tick_timer_;
private int progress_; static {
private boolean force_block_update_; accepted_lava_contrainers.add(Items.BUCKET);
}
private final RfEnergy.Battery battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0); private final RfEnergy.Battery battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0);
private final LazyOptional<IEnergyStorage> energy_handler_ = battery_.createEnergyHandler(); 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 LazyOptional<? extends IFluidHandler> fluid_handler_ = tank_.createOutputFluidHandler();
private final Inventories.StorageInventory main_inventory_; private final Inventories.StorageInventory main_inventory_;
private final LazyOptional<? extends IItemHandler> item_handler_; private final LazyOptional<? extends IItemHandler> item_handler_;
private int tick_timer_;
private int progress_;
private boolean force_block_update_;
static { public MineralSmelterTileEntity(BlockPos pos, BlockState state) {
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)
{
super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
main_inventory_ = (new Inventories.StorageInventory(this, NUM_OF_SLOTS, 1)).setStackLimit(1); main_inventory_ = (new Inventories.StorageInventory(this, NUM_OF_SLOTS, 1)).setStackLimit(1);
item_handler_ = Inventories.MappedItemHandler.createGenericHandler( item_handler_ = Inventories.MappedItemHandler.createGenericHandler(
main_inventory_, main_inventory_,
(index,stack)->((index==1) && (phase()!=PHASE_LAVA)), (index, stack) -> ((index == 1) && (phase() != PHASE_LAVA)),
(index,stack)->((index==0) && (progress_==0) && accepts_input(stack)), (index, stack) -> ((index == 0) && (progress_ == 0) && accepts_input(stack)),
(index,stack)->{}, (index, stack) -> {
(index,stack)->{ if(index!=0) reset_process(); } },
(index, stack) -> {
if (index != 0) reset_process();
}
); );
} }
public int progress() public static void on_config(int consumption, int heatup_per_second) {
{ return progress_; } 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() public int progress() {
{ return progress_;
if(progress_ >= 100) return PHASE_LAVA; }
if(progress_ >= 90) return PHASE_MAGMABLOCK;
if(progress_ >= 5) return PHASE_HOT; public int phase() {
if (progress_ >= 100) return PHASE_LAVA;
if (progress_ >= 90) return PHASE_MAGMABLOCK;
if (progress_ >= 5) return PHASE_HOT;
return PHASE_WARMUP; return PHASE_WARMUP;
} }
public boolean bucket_extraction_possible() public boolean bucket_extraction_possible() {
{ return tank_.getFluidAmount() >= MAX_BUCKET_EXTRACT_FLUID_LEVEL; } return tank_.getFluidAmount() >= MAX_BUCKET_EXTRACT_FLUID_LEVEL;
}
public int comparator_signal() public int comparator_signal() {
{ return phase() * 5; } return phase() * 5;
}
private boolean accepts_lava_container(ItemStack stack) private boolean accepts_lava_container(ItemStack stack) {
{ return accepted_lava_contrainers.contains(stack.getItem()); } return accepted_lava_contrainers.contains(stack.getItem());
}
private boolean accepts_input(ItemStack stack) private boolean accepts_input(ItemStack stack) {
{ if (!main_inventory_.isEmpty()) {
if(!main_inventory_.isEmpty()) {
return false; return false;
} else if(bucket_extraction_possible()) { } else if (bucket_extraction_possible()) {
return accepts_lava_container(stack); return accepts_lava_container(stack);
} else { } else {
return (accepted_minerals.contains(stack.getItem())) || (Auxiliaries.isInItemTag(stack.getItem(), new ResourceLocation(Auxiliaries.modid(), "accepted_mineral_smelter_input"))); 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) public boolean insert(final ItemStack stack, boolean simulate) {
{ if (stack.isEmpty() || (!accepts_input(stack))) return false;
if(stack.isEmpty() || (!accepts_input(stack))) return false; if (!simulate) {
if(!simulate) {
final ItemStack st = stack.copy(); final ItemStack st = stack.copy();
st.setCount(1); st.setCount(1);
main_inventory_.setItem(0, st); main_inventory_.setItem(0, st);
if(!accepts_lava_container(stack)) progress_ = 0; if (!accepts_lava_container(stack)) progress_ = 0;
force_block_update_ = true; force_block_update_ = true;
} }
return true; return true;
} }
public ItemStack extract(boolean simulate) public ItemStack extract(boolean simulate) {
{
final ItemStack stack = main_inventory_.getItem(1).copy(); final ItemStack stack = main_inventory_.getItem(1).copy();
if(stack.isEmpty()) return ItemStack.EMPTY; if (stack.isEmpty()) return ItemStack.EMPTY;
if(!simulate) reset_process(); if (!simulate) reset_process();
return stack; return stack;
} }
protected void reset_process() protected void reset_process() {
{
main_inventory_.setItem(0, ItemStack.EMPTY); main_inventory_.setItem(0, ItemStack.EMPTY);
main_inventory_.setItem(1, ItemStack.EMPTY); main_inventory_.setItem(1, ItemStack.EMPTY);
tank_.clear(); tank_.clear();
@ -340,35 +345,36 @@ public class EdMineralSmelter
progress_ = 0; progress_ = 0;
} }
public void readnbt(CompoundTag nbt) public void readnbt(CompoundTag nbt) {
{
main_inventory_.load(nbt); main_inventory_.load(nbt);
battery_.load(nbt); battery_.load(nbt);
tank_.load(nbt); tank_.load(nbt);
progress_ = nbt.getInt("progress"); progress_ = nbt.getInt("progress");
} }
protected void writenbt(CompoundTag nbt) protected void writenbt(CompoundTag nbt) {
{
main_inventory_.save(nbt); main_inventory_.save(nbt);
battery_.save(nbt); battery_.save(nbt);
tank_.save(nbt); tank_.save(nbt);
nbt.putInt("progress", Mth.clamp(progress_,0 , 100)); nbt.putInt("progress", Mth.clamp(progress_, 0, 100));
} }
// BlockEntity ------------------------------------------------------------------------------ // BlockEntity ------------------------------------------------------------------------------
@Override @Override
public void load(CompoundTag nbt) public void load(CompoundTag nbt) {
{ super.load(nbt); readnbt(nbt); } super.load(nbt);
readnbt(nbt);
}
@Override @Override
protected void saveAdditional(CompoundTag nbt) protected void saveAdditional(CompoundTag nbt) {
{ super.saveAdditional(nbt); writenbt(nbt); } super.saveAdditional(nbt);
writenbt(nbt);
}
@Override @Override
public void setRemoved() public void setRemoved() {
{
super.setRemoved(); super.setRemoved();
energy_handler_.invalidate(); energy_handler_.invalidate();
fluid_handler_.invalidate(); fluid_handler_.invalidate();
@ -378,45 +384,43 @@ public class EdMineralSmelter
// Capability export ---------------------------------------------------------------------------- // Capability export ----------------------------------------------------------------------------
@Override @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) 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.ITEM_HANDLER) return item_handler_.cast(); if (capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast();
if(capability == ForgeCapabilities.FLUID_HANDLER) return fluid_handler_.cast(); if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing); return super.getCapability(capability, facing);
} }
// ITickable ------------------------------------------------------------------------------------ // ITickable ------------------------------------------------------------------------------------
@Override @Override
public void tick() public void tick() {
{ if (--tick_timer_ > 0) return;
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
BlockState state = level.getBlockState(worldPosition); BlockState state = level.getBlockState(worldPosition);
if(!(state.getBlock() instanceof MineralSmelterBlock)) return; if (!(state.getBlock() instanceof MineralSmelterBlock)) return;
boolean dirty = false; boolean dirty = false;
final int last_phase = phase(); final int last_phase = phase();
final ItemStack istack = main_inventory_.getItem(0); 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; progress_ = 0;
tank_.clear(); tank_.clear();
main_inventory_.clearContent(); main_inventory_.clearContent();
} else if((battery_.isEmpty()) || (level.hasNeighborSignal(worldPosition))) { } else if ((battery_.isEmpty()) || (level.hasNeighborSignal(worldPosition))) {
progress_ = Mth.clamp(progress_-cooldown_rate, 0,100); progress_ = Mth.clamp(progress_ - cooldown_rate, 0, 100);
} else if(progress_ >= 100) { } else if (progress_ >= 100) {
progress_ = 100; progress_ = 100;
if(!battery_.draw(energy_consumption*TICK_INTERVAL/20)) battery_.clear(); if (!battery_.draw(energy_consumption * TICK_INTERVAL / 20)) battery_.clear();
} else if((phase()>=PHASE_LAVA) || (!istack.isEmpty())) { } else if ((phase() >= PHASE_LAVA) || (!istack.isEmpty())) {
if(!battery_.draw(energy_consumption*TICK_INTERVAL)) battery_.clear(); if (!battery_.draw(energy_consumption * TICK_INTERVAL)) battery_.clear();
progress_ = Mth.clamp(progress_+heatup_rate, 0, 100); progress_ = Mth.clamp(progress_ + heatup_rate, 0, 100);
} }
final int new_phase = phase(); 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. // That stays in the slot until its extracted or somone takes it out.
if(istack.sameItem(BUCKET_STACK)) { if (istack.is(BUCKET_STACK.getItem())) {
if(!main_inventory_.getItem(1).sameItem(LAVA_BUCKET_STACK)) { if (!main_inventory_.getItem(1).is(LAVA_BUCKET_STACK.getItem())) {
if(bucket_extraction_possible()) { if (bucket_extraction_possible()) {
reset_process(); reset_process();
main_inventory_.setItem(1, LAVA_BUCKET_STACK); main_inventory_.setItem(1, LAVA_BUCKET_STACK);
level.playSound(null, worldPosition, SoundEvents.BUCKET_FILL_LAVA, SoundSource.BLOCKS, 0.2f, 1.3f); 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()); main_inventory_.setItem(1, istack.copy());
// Out stack -> Somehow the filled container or container with fluid+fluid_level(). // 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. // Heat-up to next phase happened.
switch(new_phase) { switch (new_phase) {
case PHASE_LAVA -> { case PHASE_LAVA -> {
tank_.fill(new FluidStack(Fluids.LAVA, 1000), IFluidHandler.FluidAction.EXECUTE); tank_.fill(new FluidStack(Fluids.LAVA, 1000), IFluidHandler.FluidAction.EXECUTE);
main_inventory_.setItem(1, ItemStack.EMPTY); 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); 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. // Cool-down to prev phase happened.
switch(new_phase) { switch (new_phase) {
case PHASE_MAGMABLOCK -> { case PHASE_MAGMABLOCK -> {
if(tank_.getFluidAmount() < MAX_BUCKET_EXTRACT_FLUID_LEVEL) { if (tank_.getFluidAmount() < MAX_BUCKET_EXTRACT_FLUID_LEVEL) {
reset_process(); reset_process();
} else { } else {
main_inventory_.setItem(0, MAGMA_STACK.copy()); main_inventory_.setItem(0, MAGMA_STACK.copy());
@ -463,7 +467,7 @@ public class EdMineralSmelter
dirty = true; dirty = true;
} }
case PHASE_HOT -> { case PHASE_HOT -> {
if(istack.sameItem(MAGMA_STACK)) { if (istack.is(MAGMA_STACK.getItem())) {
main_inventory_.setItem(1, new ItemStack(Blocks.OBSIDIAN)); main_inventory_.setItem(1, new ItemStack(Blocks.OBSIDIAN));
} else { } else {
main_inventory_.setItem(1, new ItemStack(Blocks.COBBLESTONE)); 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); level.playSound(null, worldPosition, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, 0.3f, 0.7f);
} }
} }
} else if(phase()>=PHASE_LAVA) { } else if (phase() >= PHASE_LAVA) {
if(tank_.getFluidAmount()<=0) { if (tank_.getFluidAmount() <= 0) {
reset_process(); reset_process();
level.playSound(null, worldPosition, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, 0.3f, 0.7f); level.playSound(null, worldPosition, SoundEvents.LAVA_EXTINGUISH, SoundSource.BLOCKS, 0.3f, 0.7f);
} else { } else {
// Phase unchanged, fluid transfer check. // Phase unchanged, fluid transfer check.
FluidStack fs = tank_.getFluid().copy(); 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); final int n = Fluidics.fill(level, getBlockPos().below(), Direction.UP, fs);
if(n > 0) { if (n > 0) {
tank_.drain(n); tank_.drain(n);
if(tank_.isEmpty()) { if (tank_.isEmpty()) {
final ItemStack prev = main_inventory_.getItem(0); final ItemStack prev = main_inventory_.getItem(0);
reset_process(); reset_process();
main_inventory_.setItem(0, prev); main_inventory_.setItem(0, prev);
@ -496,13 +500,13 @@ public class EdMineralSmelter
} }
} }
// Block state // 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); state = state.setValue(MineralSmelterBlock.PHASE, new_phase);
level.setBlock(worldPosition, state,3|16); level.setBlock(worldPosition, state, 3 | 16);
level.updateNeighborsAt(getBlockPos(), state.getBlock()); level.updateNeighborsAt(getBlockPos(), state.getBlock());
force_block_update_ = false; force_block_update_ = false;
} }
if(dirty) setChanged(); if (dirty) setChanged();
} }
} }
} }

View file

@ -9,6 +9,11 @@
*/ */
package dev.zontreck.engineerdecor.blocks; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.Mth; 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.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; 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.Block;
import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity; 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.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler; 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.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class EdPipeValve public class EdPipeValve {
{
public static final int CFG_CHECK_VALVE = 0x1; public static final int CFG_CHECK_VALVE = 0x1;
public static final int CFG_ANALOG_VALVE = 0x2; public static final int CFG_ANALOG_VALVE = 0x2;
public static final int CFG_REDSTONE_CONTROLLED_VALVE = 0x4; 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.fluid_maxflow_mb = Mth.clamp(container_size_decl, 1, 10000);
PipeValveTileEntity.redstone_flow_slope_mb = Mth.clamp(redstone_slope, 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."); 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 // 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_N = BooleanProperty.create("rs_n");
public static final BooleanProperty RS_CN_S = BooleanProperty.create("rs_s"); public static final BooleanProperty RS_CN_S = BooleanProperty.create("rs_s");
public static final BooleanProperty RS_CN_E = BooleanProperty.create("rs_e"); 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 static final BooleanProperty RS_CN_D = BooleanProperty.create("rs_d");
public final int valve_config; public final int valve_config;
public PipeValveBlock(long config, int valve_config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) public PipeValveBlock(long config, int valve_config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
{ super(config, builder, unrotatedAABB); this.valve_config = valve_config; } 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);
} }
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) @Nullable
{ return false; } public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
final BlockEntityType<?> tet = ModContent.getBlockEntityTypeOfBlock("straight_pipe_valve");
return (tet == null) ? null : tet.create(pos, state);
}
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return Shapes.block(); } return false;
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
{ super.createBlockStateDefinition(builder); builder.add(RS_CN_N, RS_CN_S, RS_CN_E, RS_CN_W, RS_CN_U, RS_CN_D); } 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 @Override
@Nullable @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) 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); .setValue(RS_CN_W, false).setValue(RS_CN_U, false).setValue(RS_CN_D, false);
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
{ return get_rsconnector_state(state, world, pos, null); } return get_rsconnector_state(state, world, pos, null);
}
@Override @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) {
{ world.updateNeighborsAt(pos,this); } world.updateNeighborsAt(pos, this);
}
@Override @Override
public BlockState rotate(BlockState state, LevelAccessor world, BlockPos pos, Rotation direction) public BlockState rotate(BlockState state, LevelAccessor world, BlockPos pos, Rotation direction) {
{ return get_rsconnector_state(state, world, pos, null); } // don't rotate at all return get_rsconnector_state(state, world, pos, null);
} // don't rotate at all
@Override @Override
public boolean hasSignalConnector(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) public boolean hasSignalConnector(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) {
{ return (side!=null) && (side!=state.getValue(FACING)) && (side!=state.getValue(FACING).getOpposite()); } return (side != null) && (side != state.getValue(FACING)) && (side != state.getValue(FACING).getOpposite());
}
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } 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; }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) // public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) { return true; }
{ return 0; } public boolean isSignalSource(BlockState p_60571_) {
return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
{ return 0; } return 0;
}
private BlockState get_rsconnector_state(BlockState state, LevelAccessor world, BlockPos pos, @Nullable BlockPos fromPos) @Override
{ @SuppressWarnings("deprecation")
if((valve_config & (CFG_REDSTONE_CONTROLLED_VALVE))==0) return state; 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(); Direction.Axis bfa = state.getValue(FACING).getAxis();
for(Direction f:Direction.values()) { for (Direction f : Direction.values()) {
boolean cn = (f.getAxis() != bfa); boolean cn = (f.getAxis() != bfa);
if(cn) { if (cn) {
BlockPos nbp = pos.relative(f); 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); 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) { switch (f) {
case NORTH -> state = state.setValue(RS_CN_N, cn); case NORTH -> state = state.setValue(RS_CN_N, cn);
@ -169,54 +180,49 @@ public class EdPipeValve
// Tile entity // 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 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 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 boolean filling_ = false;
private int valve_config_; private int valve_config_;
public PipeValveTileEntity(BlockPos pos, BlockState state) public PipeValveTileEntity(BlockPos pos, BlockState state) {
{ super(ModContent.getBlockEntityTypeOfBlock("straight_pipe_valve"), pos, 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_;
} }
// BlockEntity ----------------------------------------------------------------------------- // 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 @Override
public void setRemoved() public void setRemoved() {
{
super.setRemoved(); super.setRemoved();
back_flow_handler_.invalidate(); back_flow_handler_.invalidate();
fluid_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 @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
{ if (capability == ForgeCapabilities.FLUID_HANDLER) {
if(capability == ForgeCapabilities.FLUID_HANDLER) {
Direction bf = block_facing(); Direction bf = block_facing();
if(facing == bf) return back_flow_handler_.cast(); if (facing == bf) return back_flow_handler_.cast();
if(facing == bf.getOpposite()) return fluid_handler_.cast(); if (facing == bf.getOpposite()) return fluid_handler_.cast();
return LazyOptional.empty(); return LazyOptional.empty();
} }
return super.getCapability(capability, facing); return super.getCapability(capability, facing);
@ -225,38 +231,64 @@ public class EdPipeValve
// IFluidHandlers // IFluidHandlers
@Nullable @Nullable
private IFluidHandler forward_fluid_handler() private IFluidHandler forward_fluid_handler() {
{
final BlockEntity te = level.getBlockEntity(worldPosition.relative(block_facing())); 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); return te.getCapability(ForgeCapabilities.FLUID_HANDLER, block_facing().getOpposite()).orElse(null);
} }
// Forward flow handler -- // Forward flow handler --
private static class MainFlowHandler implements IFluidHandler private static class MainFlowHandler implements IFluidHandler {
{
private final PipeValveTileEntity te; 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) public MainFlowHandler(PipeValveTileEntity te) {
{ this.te = te;
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);
@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; te.filling_ = true;
int n_filled = fh.fill(res, action); int n_filled = fh.fill(res, action);
te.filling_ = false; te.filling_ = false;
@ -266,15 +298,41 @@ public class EdPipeValve
// Back flow prevention handler -- // Back flow prevention handler --
private static class BackFlowHandler implements IFluidHandler private static class BackFlowHandler implements IFluidHandler {
{ @Override
@Override public int getTanks() { return 1; } public int getTanks() {
@Override public FluidStack getFluidInTank(int tank) { return FluidStack.EMPTY; } return 1;
@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
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; } public FluidStack getFluidInTank(int tank) {
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; } 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; package dev.zontreck.engineerdecor.blocks;
import com.mojang.blaze3d.vertex.PoseStack; import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.libmc.*; import dev.zontreck.libzontreck.edlibmc.*;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; 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.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; 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.Block;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SoundType; 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.common.util.LazyOptional;
import net.minecraftforge.fluids.IFluidBlock; import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import dev.zontreck.engineerdecor.ModContent;
import wile.engineersdecor.libmc.*;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@ -63,120 +62,125 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
public class EdPlacer public class EdPlacer {
{ public static void on_config() {
public static void on_config() }
{}
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Block // Block
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
public static class PlacerBlock extends StandardBlocks.Directed implements StandardEntityBlocks.IStandardEntityBlock<PlacerTileEntity> public static class PlacerBlock extends StandardBlocks.Directed implements StandardEntityBlocks.IStandardEntityBlock<PlacerTileEntity> {
{ public PlacerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
public PlacerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) super(config, builder, unrotatedAABB);
{ super(config, builder, unrotatedAABB); } }
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
{ return Shapes.block(); } return Shapes.block();
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean hasAnalogOutputSignal(BlockState state) public boolean hasAnalogOutputSignal(BlockState state) {
{ return true; } return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getAnalogOutputSignal(BlockState blockState, Level world, BlockPos pos) public int getAnalogOutputSignal(BlockState blockState, Level world, BlockPos pos) {
{ return (world.getBlockEntity(pos) instanceof EdPlacer.PlacerTileEntity te) ? RsSignals.fromContainer(te.inventory_) : 0; } return (world.getBlockEntity(pos) instanceof EdPlacer.PlacerTileEntity te) ? RsSignals.fromContainer(te.inventory_) : 0;
}
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } return false;
}
@Override @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) {
{ if (world.isClientSide) return;
if(world.isClientSide) return; if ((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundTag te_nbt = stack.getTag().getCompound("tedata"); CompoundTag te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return; if (te_nbt.isEmpty()) return;
if(!(world.getBlockEntity(pos) instanceof final PlacerTileEntity te)) return; if (!(world.getBlockEntity(pos) instanceof final PlacerTileEntity te)) return;
te.readnbt(te_nbt, false); te.readnbt(te_nbt, false);
te.reset_rtstate(); te.reset_rtstate();
te.setChanged(); te.setChanged();
} }
@Override @Override
public boolean hasDynamicDropList() public boolean hasDynamicDropList() {
{ return true; } return true;
}
@Override @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<>(); final List<ItemStack> stacks = new ArrayList<>();
if(world.isClientSide) return stacks; if (world.isClientSide) return stacks;
if(!(te instanceof PlacerTileEntity)) return stacks; if (!(te instanceof PlacerTileEntity)) return stacks;
if(!explosion) { if (!explosion) {
ItemStack stack = new ItemStack(this, 1); ItemStack stack = new ItemStack(this, 1);
CompoundTag te_nbt = ((PlacerTileEntity) te).clear_getnbt(); CompoundTag te_nbt = ((PlacerTileEntity) te).clear_getnbt();
if(!te_nbt.isEmpty()) { if (!te_nbt.isEmpty()) {
CompoundTag nbt = new CompoundTag(); CompoundTag nbt = new CompoundTag();
nbt.put("tedata", te_nbt); nbt.put("tedata", te_nbt);
stack.setTag(nbt); stack.setTag(nbt);
} }
stacks.add(stack); stacks.add(stack);
} else { } else {
for(ItemStack stack: ((PlacerTileEntity)te).inventory_) { for (ItemStack stack : ((PlacerTileEntity) te).inventory_) {
if(!stack.isEmpty()) stacks.add(stack); if (!stack.isEmpty()) stacks.add(stack);
} }
((PlacerTileEntity)te).reset_rtstate(); ((PlacerTileEntity) te).reset_rtstate();
} }
return stacks; return stacks;
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) {
{ return useOpenGui(state, world, pos, player); } 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();
} }
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean isSignalSource(BlockState state) public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) {
{ return true; } if (!(world instanceof Level) || (world.isClientSide)) return;
BlockEntity te = world.getBlockEntity(pos);
if (!(te instanceof PlacerTileEntity)) return;
((PlacerTileEntity) te).block_updated();
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) public boolean isSignalSource(BlockState state) {
{ return 0; } return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
{ return 0; } return 0;
}
@Override
@SuppressWarnings("deprecation")
public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) {
return 0;
}
} }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Tile entity // 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 TICK_INTERVAL = 40;
public static final int NUM_OF_SLOTS = 18; public static final int NUM_OF_SLOTS = 18;
public static final int NUM_OF_FIELDS = 3; 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_INVERTED = 0x01;
public static final int LOGIC_CONTINUOUS = 0x02; public static final int LOGIC_CONTINUOUS = 0x02;
public static final int LOGIC_IGNORE_EXT = 0x04; 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 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 Inventories.StorageInventory inventory_ = new Inventories.StorageInventory(this, NUM_OF_SLOTS, 1);
private final LazyOptional<IItemHandler> item_handler_; 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); super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
item_handler_ = Inventories.MappedItemHandler.createGenericHandler(inventory_, item_handler_ = Inventories.MappedItemHandler.createGenericHandler(inventory_,
(stack, slot) -> true, (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(); CompoundTag nbt = new CompoundTag();
writenbt(nbt, false); writenbt(nbt, false);
inventory_.clearContent(); inventory_.clearContent();
@ -213,188 +244,164 @@ public class EdPlacer
return nbt; return nbt;
} }
public void reset_rtstate() public void reset_rtstate() {
{
block_power_signal_ = false; block_power_signal_ = false;
block_power_updated_ = false; block_power_updated_ = false;
} }
public void readnbt(CompoundTag nbt, boolean update_packet) public void readnbt(CompoundTag nbt, boolean update_packet) {
{
inventory_.load(nbt); inventory_.load(nbt);
block_power_signal_ = nbt.getBoolean("powered"); block_power_signal_ = nbt.getBoolean("powered");
current_slot_index_ = nbt.getInt("act_slot_index"); current_slot_index_ = nbt.getInt("act_slot_index");
logic_ = nbt.getInt("logic"); logic_ = nbt.getInt("logic");
} }
protected void writenbt(CompoundTag nbt, boolean update_packet) // BlockEntity ------------------------------------------------------------------------------
{
protected void writenbt(CompoundTag nbt, boolean update_packet) {
inventory_.save(nbt); inventory_.save(nbt);
nbt.putBoolean("powered", block_power_signal_); nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("act_slot_index", current_slot_index_); nbt.putInt("act_slot_index", current_slot_index_);
nbt.putInt("logic", logic_); nbt.putInt("logic", logic_);
} }
public void block_updated() public void block_updated() {
{
boolean powered = level.hasNeighborSignal(worldPosition); 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; block_power_signal_ = powered;
if(block_power_updated_) { if (block_power_updated_) {
tick_timer_ = 1; tick_timer_ = 1;
} else if(tick_timer_ > 4) { } else if (tick_timer_ > 4) {
tick_timer_ = 4; tick_timer_ = 4;
} }
} }
// BlockEntity ------------------------------------------------------------------------------
@Override @Override
public void load(CompoundTag nbt) public void load(CompoundTag nbt) {
{ super.load(nbt); readnbt(nbt, false); } 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();
} }
// Namable ----------------------------------------------------------------------------------------------- // Namable -----------------------------------------------------------------------------------------------
@Override @Override
public Component getName() protected void saveAdditional(CompoundTag nbt) {
{ return Auxiliaries.localizable(getBlockState().getBlock().getDescriptionId()); } super.saveAdditional(nbt);
writenbt(nbt, false);
}
@Override @Override
public boolean hasCustomName() public void setRemoved() {
{ return false; } super.setRemoved();
item_handler_.invalidate();
}
@Override @Override
public Component getCustomName() public Component getName() {
{ return getName(); } return Auxiliaries.localizable(getBlockState().getBlock().getDescriptionId());
}
// INamedContainerProvider ------------------------------------------------------------------------------ // INamedContainerProvider ------------------------------------------------------------------------------
@Override @Override
public Component getDisplayName() public boolean hasCustomName() {
{ return Nameable.super.getDisplayName(); } return false;
}
@Override @Override
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player ) public Component getCustomName() {
{ return new PlacerContainer(id, inventory, inventory_, ContainerLevelAccess.create(level, worldPosition), fields); } return getName();
}
// Fields ----------------------------------------------------------------------------------------------- // Fields -----------------------------------------------------------------------------------------------
protected final ContainerData fields = new ContainerData()
{
@Override @Override
public int getCount() public Component getDisplayName() {
{ return PlacerTileEntity.NUM_OF_FIELDS; } return Nameable.super.getDisplayName();
@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);
}
}
};
// Capability export ------------------------------------------------------------------------------------ // Capability export ------------------------------------------------------------------------------------
@Override @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
{ return new PlacerContainer(id, inventory, inventory_, ContainerLevelAccess.create(level, worldPosition), fields);
if(capability == ForgeCapabilities.ITEM_HANDLER) return item_handler_.cast();
return super.getCapability(capability, facing);
} }
// ITickable and aux methods ---------------------------------------------------------------------------- // ITickable and aux methods ----------------------------------------------------------------------------
private static int next_slot(int i) @Override
{ return (i<NUM_OF_SLOTS-1) ? (i+1) : 0; } 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) private boolean spit_out(Direction facing) {
{ return spit_out(facing, false); } 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 stack = inventory_.getItem(current_slot_index_);
ItemStack drop = stack.copy(); ItemStack drop = stack.copy();
if(!all) { if (!all) {
stack.shrink(1); stack.shrink(1);
inventory_.setItem(current_slot_index_, stack); inventory_.setItem(current_slot_index_, stack);
drop.setCount(1); drop.setCount(1);
} else { } else {
inventory_.setItem(current_slot_index_, ItemStack.EMPTY); 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); BlockPos p = worldPosition.relative(facing, i);
if(!level.isEmptyBlock(p)) continue; if (!level.isEmptyBlock(p)) continue;
level.addFreshEntity(new ItemEntity(level, (p.getX()+0.5), (p.getY()+0.5), (p.getZ()+0.5), drop)); 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); level.playSound(null, p, SoundEvents.ITEM_PICKUP, SoundSource.BLOCKS, 0.7f, 0.8f);
break; break;
} }
return true; return true;
} }
private boolean try_place(Direction facing, boolean triggered) private boolean try_place(Direction facing, boolean triggered) {
{ if (level.isClientSide()) return false;
if(level.isClientSide()) return false;
BlockPos placement_pos = worldPosition.relative(facing); 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; ItemStack current_stack = ItemStack.EMPTY;
for(int i=0; i<NUM_OF_SLOTS; ++i) { for (int i = 0; i < NUM_OF_SLOTS; ++i) {
if(current_slot_index_ >= NUM_OF_SLOTS) current_slot_index_ = 0; if (current_slot_index_ >= NUM_OF_SLOTS) current_slot_index_ = 0;
current_stack = inventory_.getItem(current_slot_index_); 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_); 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; boolean no_space = false;
final Item item = current_stack.getItem(); final Item item = current_stack.getItem();
Block block = Block.byItem(item); Block block = Block.byItem(item);
if(block == Blocks.AIR) { if (block == Blocks.AIR) {
if(item != null) { if (item != null) {
if(debug_) Auxiliaries.logInfo("Placer spit: No block for item " + Auxiliaries.getResourceLocation(item)); if (debug_)
Auxiliaries.logInfo("Placer spit: No block for item " + Auxiliaries.getResourceLocation(item));
return spit_out(facing); // Item not accepted return spit_out(facing); // Item not accepted
} }
} else if(block instanceof IPlantable) { } else if (block instanceof IPlantable) {
if(level.isEmptyBlock(placement_pos)) { if (level.isEmptyBlock(placement_pos)) {
// plant here, block below has to be valid soil. // plant here, block below has to be valid soil.
BlockState soilstate = level.getBlockState(placement_pos.below()); 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; block = Blocks.AIR;
} }
} else { } else {
// adjacent block is the soil, plant above if the soil is valid. // adjacent block is the soil, plant above if the soil is valid.
BlockState soilstate = level.getBlockState(placement_pos); BlockState soilstate = level.getBlockState(placement_pos);
if(soilstate.getBlock() == block) { if (soilstate.getBlock() == block) {
// The plant is already planted from the case above. // The plant is already planted from the case above.
block = Blocks.AIR; block = Blocks.AIR;
no_space = true; 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. // If this is the soil an air block is needed above, if that is blocked we can't plant.
block = Blocks.AIR; block = Blocks.AIR;
no_space = true; 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. // Would be space above, but it's not the right soil for the plant.
block = Blocks.AIR; block = Blocks.AIR;
} else { } else {
@ -404,19 +411,20 @@ public class EdPlacer
} }
} else { } else {
final BlockState current_placement_pos_state = level.getBlockState(placement_pos); final BlockState current_placement_pos_state = level.getBlockState(placement_pos);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation") final boolean replacable = (current_placement_pos_state.getBlock().canBeReplaced(current_placement_pos_state, Fluids.EMPTY)) && (
final boolean replacable = (current_placement_pos_state.getBlock().canBeReplaced(current_placement_pos_state, Fluids.EMPTY)) && (
level.isEmptyBlock(placement_pos) || level.isEmptyBlock(placement_pos) ||
(current_placement_pos_state.getBlock() instanceof IFluidBlock) || (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) || ( if ((!replacable) || (
(!level.getEntitiesOfClass(Entity.class, new AABB(placement_pos), (Entity e)->{ (!level.getEntitiesOfClass(Entity.class, new AABB(placement_pos), (Entity e) -> {
if(e.isPickable()) return true; if (e.isPickable()) return true;
if(triggered) return false; if (triggered) return false;
if((e instanceof ItemEntity)) { if ((e instanceof ItemEntity)) {
if((e.getDeltaMovement().y() > 0) || (e.getDeltaMovement().y() < -0.5)) return true; // not falling or falling by if ((e.getDeltaMovement().y() > 0) || (e.getDeltaMovement().y() < -0.5))
if(Math.abs(e.getDeltaMovement().x())+Math.abs(e.getDeltaMovement().z()) > 0) return true; // not straight 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; return false;
}).isEmpty()) }).isEmpty())
@ -426,86 +434,92 @@ public class EdPlacer
} }
} }
// println("PLACE " + current_stack + " --> " + block + " at " + placement_pos.subtract(pos) + "( item=" + item + ")"); // println("PLACE " + current_stack + " --> " + block + " at " + placement_pos.subtract(pos) + "( item=" + item + ")");
if(block != Blocks.AIR) { if (block != Blocks.AIR) {
try { try {
BlockPlaceContext use_context = null; BlockPlaceContext use_context = null;
{ {
final FakePlayer placer = net.minecraftforge.common.util.FakePlayerFactory.getMinecraft((ServerLevel)level); final FakePlayer placer = net.minecraftforge.common.util.FakePlayerFactory.getMinecraft((ServerLevel) level);
if(placer != null) { if (placer != null) {
ItemStack placement_stack = current_stack.copy(); ItemStack placement_stack = current_stack.copy();
placement_stack.setCount(1); placement_stack.setCount(1);
ItemStack held = placer.getItemInHand(InteractionHand.MAIN_HAND); ItemStack held = placer.getItemInHand(InteractionHand.MAIN_HAND);
placer.setItemInHand(InteractionHand.MAIN_HAND, placement_stack); placer.setItemInHand(InteractionHand.MAIN_HAND, placement_stack);
List<Direction> directions = new ArrayList<>(Arrays.asList(Direction.UP, facing.getOpposite())); 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 : Direction.values()) if (!directions.contains(d)) directions.add(d);
for(Direction d:directions) { for (Direction d : directions) {
Vec3 v = Vec3.atCenterOf(placement_pos).subtract(Vec3.atLowerCornerOf(d.getNormal())); 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))); 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 (block.getStateForPlacement(use_context) == null) use_context = null;
if(use_context!=null) break; if (use_context != null) break;
} }
placer.setItemInHand(InteractionHand.MAIN_HAND, held); placer.setItemInHand(InteractionHand.MAIN_HAND, held);
} }
} }
BlockState placement_state = (use_context==null) ? (block.defaultBlockState()) : (block.getStateForPlacement(use_context)); BlockState placement_state = (use_context == null) ? (block.defaultBlockState()) : (block.getStateForPlacement(use_context));
if(placement_state == null) { if (placement_state == null) {
if(debug_) Auxiliaries.logInfo("Placer spit: No valid placement state for item " + Auxiliaries.getResourceLocation(item)); if (debug_)
Auxiliaries.logInfo("Placer spit: No valid placement state for item " + Auxiliaries.getResourceLocation(item));
return spit_out(facing); return spit_out(facing);
} else if((use_context!=null) && (item instanceof BlockItem)) { } else if ((use_context != null) && (item instanceof BlockItem)) {
if(((BlockItem)item).place(use_context) != InteractionResult.FAIL) { if (((BlockItem) item).place(use_context) != InteractionResult.FAIL) {
SoundType stype = block.getSoundType(placement_state, level, worldPosition, null); 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 { } 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); 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 { } 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); 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); current_stack.shrink(1);
inventory_.setItem(current_slot_index_, current_stack); inventory_.setItem(current_slot_index_, current_stack);
return true; return true;
} catch(Throwable e) { } catch (Throwable e) {
// The block really needs a player or other issues happened during placement. // 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 // A hard crash should not be fired here, instead spit out the item to indicated that this
// block is not compatible. // 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 { try {
level.removeBlock(placement_pos, false); level.removeBlock(placement_pos, false);
} catch(Throwable e1) { } catch (Throwable e1) {
Auxiliaries.logger().error("Exception while removing failed block placement " + ((block==null)?(""):(""+block)) + ", spitting out. Exception is: " + e1); Auxiliaries.logger().error("Exception while removing failed block placement " + ((block == null) ? ("") : ("" + block)) + ", spitting out. Exception is: " + e1);
} }
return spit_out(facing, true); 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. // 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_); 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; return false;
} }
@Override @Override
public void tick() public void tick() {
{
// Tick cycle pre-conditions // Tick cycle pre-conditions
if(level.isClientSide) return; if (level.isClientSide) return;
if(--tick_timer_ > 0) return; if (--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
// Cycle init // Cycle init
final BlockState state = level.getBlockState(worldPosition); 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 updated = block_power_updated_;
final boolean rssignal = ((logic_ & LOGIC_IGNORE_EXT)!=0) || ((logic_ & LOGIC_INVERTED)!=0)==(!block_power_signal_); 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 trigger = ((logic_ & LOGIC_IGNORE_EXT) != 0) || (rssignal && ((updated) || ((logic_ & LOGIC_CONTINUOUS) != 0)));
final Direction placer_facing = state.getValue(PlacerBlock.FACING); final Direction placer_facing = state.getValue(PlacerBlock.FACING);
boolean dirty = updated; boolean dirty = updated;
// Trigger edge detection for next cycle // Trigger edge detection for next cycle
@ -513,12 +527,12 @@ public class EdPlacer
boolean tr = level.hasNeighborSignal(worldPosition); boolean tr = level.hasNeighborSignal(worldPosition);
block_power_updated_ = (block_power_signal_ != tr); block_power_updated_ = (block_power_signal_ != tr);
block_power_signal_ = tr; block_power_signal_ = tr;
if(block_power_updated_) dirty = true; if (block_power_updated_) dirty = true;
} }
// Placing // Placing
if(trigger && try_place(placer_facing, rssignal && updated)) dirty = true; if (trigger && try_place(placer_facing, rssignal && updated)) dirty = true;
if(dirty) setChanged(); if (dirty) setChanged();
if(trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL; if (trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL;
} }
} }
@ -526,8 +540,7 @@ public class EdPlacer
// Container // 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"; protected static final String QUICK_MOVE_ALL = "quick-move-all";
private static final int PLAYER_INV_START_SLOTNO = PlacerTileEntity.NUM_OF_SLOTS; private static final int PLAYER_INV_START_SLOTNO = PlacerTileEntity.NUM_OF_SLOTS;
private final Player player_; private final Player player_;
@ -537,13 +550,11 @@ public class EdPlacer
private final Inventories.InventoryRange player_inventory_range_; private final Inventories.InventoryRange player_inventory_range_;
private final Inventories.InventoryRange block_storage_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) private PlacerContainer(int cid, Inventory player_inventory, Container block_inventory, ContainerLevelAccess wpc, ContainerData fields) {
{ 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)
{
super(ModContent.getMenuType("factory_placer"), cid); // @todo: class mapping super(ModContent.getMenuType("factory_placer"), cid); // @todo: class mapping
fields_ = fields; fields_ = fields;
wpc_ = wpc; wpc_ = wpc;
@ -551,53 +562,58 @@ public class EdPlacer
inventory_ = block_inventory; inventory_ = block_inventory;
block_storage_range_ = new Inventories.InventoryRange(inventory_, 0, PlacerTileEntity.NUM_OF_SLOTS); block_storage_range_ = new Inventories.InventoryRange(inventory_, 0, PlacerTileEntity.NUM_OF_SLOTS);
player_inventory_range_ = Inventories.InventoryRange.fromPlayerInventory(player_); player_inventory_range_ = Inventories.InventoryRange.fromPlayerInventory(player_);
int i=-1; int i = -1;
// device slots (stacks 0 to 17) // device slots (stacks 0 to 17)
for(int y=0; y<3; ++y) { for (int y = 0; y < 3; ++y) {
for(int x=0; x<6; ++x) { for (int x = 0; x < 6; ++x) {
int xpos = 11+x*18, ypos = 9+y*17; int xpos = 11 + x * 18, ypos = 9 + y * 17;
addSlot(new Slot(inventory_, ++i, xpos, ypos)); addSlot(new Slot(inventory_, ++i, xpos, ypos));
} }
} }
// player slots // player slots
for(int x=0; x<9; ++x) { for (int x = 0; x < 9; ++x) {
addSlot(new Slot(player_inventory, x, 9+x*18, 129)); // player slots: 0..8 addSlot(new Slot(player_inventory, x, 9 + x * 18, 129)); // player slots: 0..8
} }
for(int y=0; y<3; ++y) { for (int y = 0; y < 3; ++y) {
for(int x=0; x<9; ++x) { 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 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 this.addDataSlots(fields_); // === Add reference holders
} }
@Override public final int field(int index) {
public boolean stillValid(Player player) return fields_.get(index);
{ return inventory_.stillValid(player); } }
@Override @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); 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 slot_stack = slot.getItem();
ItemStack transferred = slot_stack.copy(); ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) { if ((index >= 0) && (index < PLAYER_INV_START_SLOTNO)) {
// Device slots // Device slots
if(!moveItemStackTo(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY; if (!moveItemStackTo(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO + 36, false))
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) { return ItemStack.EMPTY;
} else if ((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO + 36)) {
// Player slot // 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 { } else {
// invalid slot // invalid slot
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
if(slot_stack.isEmpty()) { if (slot_stack.isEmpty()) {
slot.set(ItemStack.EMPTY); slot.set(ItemStack.EMPTY);
} else { } else {
slot.setChanged(); 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); slot.onTake(player, slot_stack);
return transferred; return transferred;
} }
@ -605,37 +621,36 @@ public class EdPlacer
// INetworkSynchronisableContainer --------------------------------------------------------- // INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundTag nbt) public void onGuiAction(CompoundTag nbt) {
{ Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt); } Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt);
}
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value) public void onGuiAction(String key, int value) {
{
CompoundTag nbt = new CompoundTag(); CompoundTag nbt = new CompoundTag();
nbt.putInt(key, value); nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt); Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt);
} }
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void onGuiAction(String message, CompoundTag nbt) public void onGuiAction(String message, CompoundTag nbt) {
{
nbt.putString("action", message); nbt.putString("action", message);
Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt); Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt);
} }
@Override @Override
public void onServerPacketReceived(int windowId, CompoundTag nbt) public void onServerPacketReceived(int windowId, CompoundTag nbt) {
{} }
@Override @Override
public void onClientPacketReceived(int windowId, Player player, CompoundTag nbt) public void onClientPacketReceived(int windowId, Player player, CompoundTag nbt) {
{ if (!(inventory_ instanceof Inventories.StorageInventory)) return;
if(!(inventory_ instanceof Inventories.StorageInventory)) return; if (!((((Inventories.StorageInventory) inventory_).getBlockEntity()) instanceof PlacerTileEntity te))
if(!((((Inventories.StorageInventory)inventory_).getBlockEntity()) instanceof PlacerTileEntity te)) return; return;
if(nbt.contains("action")) { if (nbt.contains("action")) {
final int slotId = nbt.contains("slot") ? nbt.getInt("slot") : -1; final int slotId = nbt.contains("slot") ? nbt.getInt("slot") : -1;
boolean changed = false; boolean changed = false;
switch(nbt.getString("action")) { switch (nbt.getString("action")) {
case QUICK_MOVE_ALL -> { case QUICK_MOVE_ALL -> {
if ((slotId >= 0) && (slotId < PLAYER_INV_START_SLOTNO) && (getSlot(slotId).hasItem())) { 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); 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(); inventory_.setChanged();
player.getInventory().setChanged(); player.getInventory().setChanged();
broadcastChanges(); broadcastChanges();
} }
} else { } else {
if(nbt.contains("logic")) te.logic_ = nbt.getInt("logic"); 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("manual_trigger") && (nbt.getInt("manual_trigger") != 0)) {
te.block_power_signal_ = true;
te.block_power_updated_ = true;
te.tick_timer_ = 1;
}
te.setChanged(); te.setChanged();
} }
@ -663,57 +682,54 @@ public class EdPlacer
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public static class PlacerGui extends Guis.ContainerGui<PlacerContainer> public static class PlacerGui extends Guis.ContainerGui<PlacerContainer> {
{ public PlacerGui(PlacerContainer container, Inventory player_inventory, Component title) {
public PlacerGui(PlacerContainer container, Inventory player_inventory, Component title) super(container, player_inventory, title, "textures/gui/factory_placer_gui.png");
{ super(container, player_inventory, title,"textures/gui/factory_placer_gui.png"); } }
@Override @Override
public void init() public void init() {
{
super.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 String prefix = block.getDescriptionId() + ".tooltips.";
final int x0 = getGuiLeft(), y0 = getGuiTop(); final int x0 = getGuiLeft(), y0 = getGuiTop();
tooltip_.init( tooltip_.init(
new TooltipDisplay.TipRange(x0+133, y0+49, 9, 9, Component.translatable(prefix + "rssignal")), 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 + 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 + 159, y0 + 49, 9, 9, Component.translatable(prefix + "triggermode"))
); );
} }
} }
@Override @Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
{
tooltip_.resetTimer(); tooltip_.resetTimer();
PlacerContainer container = getMenu(); PlacerContainer container = getMenu();
int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5); int mx = (int) (mouseX - getGuiLeft() + .5), my = (int) (mouseY - getGuiTop() + .5);
if((!isHovering(126, 1, 49, 60, mouseX, mouseY))) { if ((!isHovering(126, 1, 49, 60, mouseX, mouseY))) {
return super.mouseClicked(mouseX, mouseY, mouseButton); 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); container.onGuiAction("manual_trigger", 1);
} else if(isHovering(145, 49, 9, 9, mouseX, mouseY)) { } 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 mask = (PlacerTileEntity.LOGIC_INVERTED | PlacerTileEntity.LOGIC_IGNORE_EXT | PlacerTileEntity.LOGIC_NOT_INVERTED);
final int logic = switch((container.field(0) & mask)) { final int logic = switch ((container.field(0) & mask)) {
case PlacerTileEntity.LOGIC_NOT_INVERTED -> PlacerTileEntity.LOGIC_INVERTED; case PlacerTileEntity.LOGIC_NOT_INVERTED -> PlacerTileEntity.LOGIC_INVERTED;
case PlacerTileEntity.LOGIC_INVERTED -> PlacerTileEntity.LOGIC_IGNORE_EXT; case PlacerTileEntity.LOGIC_INVERTED -> PlacerTileEntity.LOGIC_IGNORE_EXT;
case PlacerTileEntity.LOGIC_IGNORE_EXT -> PlacerTileEntity.LOGIC_NOT_INVERTED; case PlacerTileEntity.LOGIC_IGNORE_EXT -> PlacerTileEntity.LOGIC_NOT_INVERTED;
default -> PlacerTileEntity.LOGIC_IGNORE_EXT; default -> PlacerTileEntity.LOGIC_IGNORE_EXT;
}; };
container.onGuiAction("logic", (container.field(0) & (~mask)) | logic); 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); container.onGuiAction("logic", container.field(0) ^ PlacerTileEntity.LOGIC_CONTINUOUS);
} }
return true; return true;
} }
@Override @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(); 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(); CompoundTag nbt = new CompoundTag();
nbt.putInt("slot", slotId); nbt.putInt("slot", slotId);
menu.onGuiAction(PlacerContainer.QUICK_MOVE_ALL, nbt); menu.onGuiAction(PlacerContainer.QUICK_MOVE_ALL, nbt);
@ -723,31 +739,30 @@ public class EdPlacer
} }
@Override @Override
protected void renderBgWidgets(PoseStack mx, float partialTicks, int mouseX, int mouseY) protected void renderBgWidgets(GuiGraphics mx, float partialTicks, int mouseX, int mouseY) {
{ final int x0 = getGuiLeft(), y0 = getGuiTop(), w = getXSize(), h = getYSize();
final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize();
PlacerContainer container = getMenu(); PlacerContainer container = getMenu();
// active slot // active slot
{ {
int slot_index = container.field(2); int slot_index = container.field(2);
if((slot_index < 0) || (slot_index >= PlacerTileEntity.NUM_OF_SLOTS)) slot_index = 0; if ((slot_index < 0) || (slot_index >= PlacerTileEntity.NUM_OF_SLOTS)) slot_index = 0;
int x = (x0+10+((slot_index % 6) * 18)); int x = (x0 + 10 + ((slot_index % 6) * 18));
int y = (y0+8+((slot_index / 6) * 17)); int y = (y0 + 8 + ((slot_index / 6) * 17));
blit(mx, x, y, 200, 8, 18, 18); mx.blit(getBackgroundImage(), x, y, 200, 8, 18, 18);
} }
// redstone input // redstone input
{ {
if(container.field(1) != 0) { if (container.field(1) != 0) {
blit(mx, x0+133, y0+49, 217, 49, 9, 9); mx.blit(getBackgroundImage(), x0 + 133, y0 + 49, 217, 49, 9, 9);
} }
} }
// trigger logic // trigger logic
{ {
int inverter_offset_x = ((container.field(0) & PlacerTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0; 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; 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); 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; 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 + 159, y0 + 49, 199 + pulse_mode_offset, 49, 9, 9);
} }
} }
} }

View file

@ -8,6 +8,8 @@
*/ */
package dev.zontreck.engineerdecor.blocks; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext; 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.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; 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<StairsShape> SHAPE = BlockStateProperties.STAIRS_SHAPE;
public static final EnumProperty<Half> HALF = BlockStateProperties.HALF; public static final EnumProperty<Half> HALF = BlockStateProperties.HALF;
private final VoxelShape[][][] shape_cache_; private final VoxelShape[][][] shape_cache_;
public EdRoofBlock(long config, BlockBehaviour.Properties properties) public EdRoofBlock(long config, BlockBehaviour.Properties properties) {
{ this(config, properties.dynamicShape(), Shapes.empty(), Shapes.empty()); } this(config, properties.dynamicShape(), Shapes.empty(), Shapes.empty());
}
public EdRoofBlock(long config, BlockBehaviour.Properties properties, VoxelShape add, VoxelShape cut) public EdRoofBlock(long config, BlockBehaviour.Properties properties, VoxelShape add, VoxelShape cut) {
{ super(config, properties, Auxiliaries.getPixeledAABB(0, 0, 0, 16, 8, 16));
super(config, properties, Auxiliaries.getPixeledAABB(0, 0,0,16, 8, 16));
registerDefaultState(super.defaultBlockState().setValue(HORIZONTAL_FACING, Direction.NORTH).setValue(SHAPE, StairsShape.STRAIGHT)); registerDefaultState(super.defaultBlockState().setValue(HORIZONTAL_FACING, Direction.NORTH).setValue(SHAPE, StairsShape.STRAIGHT));
shape_cache_ = makeShapes(add, cut); shape_cache_ = makeShapes(add, cut);
} }
@Override private static boolean isRoofBlock(BlockState state) {
@SuppressWarnings("deprecation") return (state.getBlock() instanceof EdRoofBlock);
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 private static boolean isOtherRoofState(BlockState state, BlockGetter world, BlockPos pos, Direction facing) {
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)
{
BlockState st = world.getBlockState(pos.relative(facing)); BlockState st = world.getBlockState(pos.relative(facing));
return (!isRoofBlock(st)) || (st.getValue(HORIZONTAL_FACING) != state.getValue(HORIZONTAL_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]; VoxelShape[][][] shapes = new VoxelShape[2][6][5];
for(int half_index=0; half_index<Half.values().length; ++half_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 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 stairs_shape_index = 0; stairs_shape_index < StairsShape.values().length; ++stairs_shape_index) {
VoxelShape shape = makeShape(half_index, direction_index, stairs_shape_index); VoxelShape shape = makeShape(half_index, direction_index, stairs_shape_index);
try { try {
// Only in case something changes and this fails, log but do not prevent the game from starting. // 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. // Roof shapes are not the most important thing in the world.
if(!add.isEmpty()) shape = Shapes.joinUnoptimized(shape, add, BooleanOp.OR); if (!add.isEmpty()) shape = Shapes.joinUnoptimized(shape, add, BooleanOp.OR);
if(!cut.isEmpty()) shape = Shapes.joinUnoptimized(shape, cut, BooleanOp.ONLY_FIRST); if (!cut.isEmpty()) shape = Shapes.joinUnoptimized(shape, cut, BooleanOp.ONLY_FIRST);
} catch(Throwable ex) { } catch (Throwable ex) {
Auxiliaries.logError("Failed to cut shape using Boolean function. This is bug."); Auxiliaries.logError("Failed to cut shape using Boolean function. This is bug.");
} }
shapes[half_index][direction_index][stairs_shape_index] = shape; shapes[half_index][direction_index][stairs_shape_index] = shape;
@ -166,28 +82,27 @@ public class EdRoofBlock extends StandardBlocks.HorizontalWaterLoggable
return shapes; 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[]{ AABB[] straight = new AABB[]{
Auxiliaries.getPixeledAABB( 0, 0, 0, 16, 4, 16), Auxiliaries.getPixeledAABB(0, 0, 0, 16, 4, 16),
Auxiliaries.getPixeledAABB( 4, 4, 0, 16, 8, 16), Auxiliaries.getPixeledAABB(4, 4, 0, 16, 8, 16),
Auxiliaries.getPixeledAABB( 8, 8, 0, 16, 12, 16), Auxiliaries.getPixeledAABB(8, 8, 0, 16, 12, 16),
Auxiliaries.getPixeledAABB(12, 12, 0, 16, 16, 16) Auxiliaries.getPixeledAABB(12, 12, 0, 16, 16, 16)
}; };
AABB[] pyramid = new AABB[]{ AABB[] pyramid = new AABB[]{
Auxiliaries.getPixeledAABB( 0, 0, 0, 16, 4, 16), Auxiliaries.getPixeledAABB(0, 0, 0, 16, 4, 16),
Auxiliaries.getPixeledAABB( 4, 4, 4, 16, 8, 16), Auxiliaries.getPixeledAABB(4, 4, 4, 16, 8, 16),
Auxiliaries.getPixeledAABB( 8, 8, 8, 16, 12, 16), Auxiliaries.getPixeledAABB(8, 8, 8, 16, 12, 16),
Auxiliaries.getPixeledAABB(12, 12, 12, 16, 16, 16) Auxiliaries.getPixeledAABB(12, 12, 12, 16, 16, 16)
}; };
final Half half = Half.values()[half_index]; final Half half = Half.values()[half_index];
if(half==Half.TOP) { if (half == Half.TOP) {
straight = Auxiliaries.getMirroredAABB(straight, Direction.Axis.Y); straight = Auxiliaries.getMirroredAABB(straight, Direction.Axis.Y);
pyramid = Auxiliaries.getMirroredAABB(pyramid, Direction.Axis.Y); pyramid = Auxiliaries.getMirroredAABB(pyramid, Direction.Axis.Y);
} }
Direction direction = Direction.from3DDataValue(direction_index); Direction direction = Direction.from3DDataValue(direction_index);
if((direction==Direction.UP) || (direction==Direction.DOWN)) return Shapes.block(); if ((direction == Direction.UP) || (direction == Direction.DOWN)) return Shapes.block();
direction_index = (direction.get2DDataValue()+1) & 0x03; // ref NORTH -> EAST for stairs compliancy. direction_index = (direction.get2DDataValue() + 1) & 0x03; // ref NORTH -> EAST for stairs compliancy.
final StairsShape stairs = StairsShape.values()[stairs_shape_index]; final StairsShape stairs = StairsShape.values()[stairs_shape_index];
return switch (stairs) { return switch (stairs) {
case STRAIGHT -> Auxiliaries.getUnionShape(Auxiliaries.getYRotatedAABB(straight, direction_index)); 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); Direction direction = state.getValue(HORIZONTAL_FACING);
{ {
BlockState ns = world.getBlockState(pos.relative(direction)); 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); 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; return (nf == direction.getCounterClockWise()) ? StairsShape.OUTER_LEFT : StairsShape.OUTER_RIGHT;
} }
} }
} }
{ {
BlockState ns = world.getBlockState(pos.relative(direction.getOpposite())); 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); 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 (nf == direction.getCounterClockWise()) ? StairsShape.INNER_LEFT : StairsShape.INNER_RIGHT;
} }
} }
} }
return StairsShape.STRAIGHT; 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; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -16,8 +19,8 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.LightLayer; 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.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour; 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.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage; 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 javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class EdSolarPanel public class EdSolarPanel {
{
public static final int DEFAULT_PEAK_POWER = 40; public static final int DEFAULT_PEAK_POWER = 40;
private static int peak_power_per_tick_ = DEFAULT_PEAK_POWER; private static int peak_power_per_tick_ = DEFAULT_PEAK_POWER;
private static int max_power_storage_ = 64000; private static int max_power_storage_ = 64000;
private static int max_feed_power = 4096; private static int max_feed_power = 4096;
private static int feeding_threshold = max_power_storage_/5; private static int feeding_threshold = max_power_storage_ / 5;
private static int balancing_threshold = max_power_storage_/10; 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; final int t = SolarPanelTileEntity.TICK_INTERVAL;
peak_power_per_tick_ = Mth.clamp(peak_power_per_tick, 12, 8192); peak_power_per_tick_ = Mth.clamp(peak_power_per_tick, 12, 8192);
feeding_threshold = Math.max(max_power_storage_/5, 1000); feeding_threshold = Math.max(max_power_storage_ / 5, 1000);
balancing_threshold = Math.max(max_power_storage_/10, 1000); balancing_threshold = Math.max(max_power_storage_ / 10, 1000);
max_power_storage_ = battery_capacity; max_power_storage_ = battery_capacity;
max_feed_power = max_feed_in_power * t; 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 // 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 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); super(config, builder, unrotatedAABB);
registerDefaultState(super.defaultBlockState().setValue(EXPOSITION, 1)); registerDefaultState(super.defaultBlockState().setValue(EXPOSITION, 1));
} }
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(EXPOSITION); } super.createBlockStateDefinition(builder);
builder.add(EXPOSITION);
}
@Override @Override
@SuppressWarnings("deprecation") @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) {
{ if (world.isClientSide()) return InteractionResult.SUCCESS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
BlockEntity te = world.getBlockEntity(pos); 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; return InteractionResult.CONSUME;
} }
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } return false;
}
} }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Tile entity // 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 TICK_INTERVAL = 4;
public static final int ACCUMULATION_INTERVAL = 8; 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 tick_timer_ = 0;
private int recalc_timer_ = 0; private int recalc_timer_ = 0;
private int current_production_ = 0; private int current_production_ = 0;
private int current_feedin_ = 0; private int current_feedin_ = 0;
private boolean output_enabled_ = false; 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) public SolarPanelTileEntity(BlockPos pos, BlockState state) {
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); } super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state);
}
public void readnbt(CompoundTag nbt, boolean update_packet) public void readnbt(CompoundTag nbt, boolean update_packet) {
{ battery_.load(nbt); } battery_.load(nbt);
}
protected void writenbt(CompoundTag nbt, boolean update_packet) protected void writenbt(CompoundTag nbt, boolean update_packet) {
{ battery_.save(nbt); } battery_.save(nbt);
}
public void state_message(Player player) public void state_message(Player player) {
{ String soc = Integer.toString(Mth.clamp((battery_.getEnergyStored() * 100 / max_power_storage_), 0, 100));
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_)); Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_solar_panel.status", soc, max_power_storage_, current_production_, current_feedin_));
} }
// ICapabilityProvider --------------------------------------------------------------------- // ICapabilityProvider ---------------------------------------------------------------------
@Override @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
{ if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing); return super.getCapability(capability, facing);
} }
// BlockEntity ------------------------------------------------------------------------------ // BlockEntity ------------------------------------------------------------------------------
@Override @Override
public void load(CompoundTag nbt) public void load(CompoundTag nbt) {
{ super.load(nbt); readnbt(nbt, false); } super.load(nbt);
readnbt(nbt, false);
}
@Override @Override
protected void saveAdditional(CompoundTag nbt) protected void saveAdditional(CompoundTag nbt) {
{ super.saveAdditional(nbt); writenbt(nbt, false); } super.saveAdditional(nbt);
writenbt(nbt, false);
}
@Override @Override
public void setRemoved() public void setRemoved() {
{
super.setRemoved(); super.setRemoved();
energy_handler_.invalidate(); energy_handler_.invalidate();
} }
@Override @Override
public void tick() public void tick() {
{ if ((level.isClientSide) || (--tick_timer_ > 0)) return;
if((level.isClientSide) || (--tick_timer_ > 0)) return;
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
BlockState state = level.getBlockState(worldPosition); BlockState state = level.getBlockState(worldPosition);
if(!(state.getBlock() instanceof SolarPanelBlock)) return; if (!(state.getBlock() instanceof SolarPanelBlock)) return;
current_feedin_ = 0; current_feedin_ = 0;
final List<SolarPanelTileEntity> adjacent_panels = new ArrayList<>(); final List<SolarPanelTileEntity> adjacent_panels = new ArrayList<>();
if(output_enabled_) { if (output_enabled_) {
for(int i=0; (i<transfer_directions_.length) && (!battery_.isEmpty()); ++i) { for (int i = 0; (i < transfer_directions_.length) && (!battery_.isEmpty()); ++i) {
final Direction f = transfer_directions_[i]; final Direction f = transfer_directions_[i];
BlockEntity te = level.getBlockEntity(worldPosition.relative(f)); 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); IEnergyStorage es = te.getCapability(ForgeCapabilities.ENERGY, f.getOpposite()).orElse(null);
if(es==null) continue; if (es == null) continue;
if(!es.canReceive()) { if (!es.canReceive()) {
if(!(te instanceof SolarPanelTileEntity)) continue; if (!(te instanceof SolarPanelTileEntity)) continue;
adjacent_panels.add((SolarPanelTileEntity)te); adjacent_panels.add((SolarPanelTileEntity) te);
continue; 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); final int fed = es.receiveEnergy(Math.min(battery_.getEnergyStored(), feed_power * TICK_INTERVAL), false);
battery_.draw(fed); battery_.draw(fed);
current_feedin_ += fed; current_feedin_ += fed;
} }
} }
current_feedin_ /= TICK_INTERVAL; current_feedin_ /= TICK_INTERVAL;
if((current_feedin_ <= 0) && ((battery_.getEnergyStored() >= balancing_threshold) || (current_production_ <= 0))) { if ((current_feedin_ <= 0) && ((battery_.getEnergyStored() >= balancing_threshold) || (current_production_ <= 0))) {
for(SolarPanelTileEntity panel: adjacent_panels) { for (SolarPanelTileEntity panel : adjacent_panels) {
if(panel.battery_.getEnergyStored() >= (battery_.getEnergyStored()-balancing_threshold)) continue; if (panel.battery_.getEnergyStored() >= (battery_.getEnergyStored() - balancing_threshold))
continue;
panel.battery_.setEnergyStored(panel.battery_.getEnergyStored() + balancing_threshold); panel.battery_.setEnergyStored(panel.battery_.getEnergyStored() + balancing_threshold);
battery_.setEnergyStored(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; tick_timer_ = TICK_INTERVAL * 10;
current_production_ = 0; current_production_ = 0;
if((!battery_.isEmpty())) output_enabled_ = true; if ((!battery_.isEmpty())) output_enabled_ = true;
if(state.getValue((SolarPanelBlock.EXPOSITION))!=2) level.setBlockAndUpdate(worldPosition, state.setValue(SolarPanelBlock.EXPOSITION, 2)); if (state.getValue((SolarPanelBlock.EXPOSITION)) != 2)
level.setBlockAndUpdate(worldPosition, state.setValue(SolarPanelBlock.EXPOSITION, 2));
return; return;
} }
if(battery_.isEmpty()) output_enabled_ = false; if (battery_.isEmpty()) output_enabled_ = false;
if(--recalc_timer_ > 0) return; if (--recalc_timer_ > 0) return;
recalc_timer_ = ACCUMULATION_INTERVAL + ((int)(Math.random()+.5)); recalc_timer_ = ACCUMULATION_INTERVAL + ((int) (Math.random() + .5));
int theta = ((((int)(level.getSunAngle(1f) * (180.0/Math.PI)))+90) % 360); int theta = ((((int) (level.getSunAngle(1f) * (180.0 / Math.PI))) + 90) % 360);
int e = 2; int e = 2;
if(theta > 340) e = 2; if (theta > 340) e = 2;
else if(theta < 45) e = 0; else if (theta < 45) e = 0;
else if(theta < 80) e = 1; else if (theta < 80) e = 1;
else if(theta < 100) e = 2; else if (theta < 100) e = 2;
else if(theta < 135) e = 3; else if (theta < 135) e = 3;
else if(theta < 190) e = 4; else if (theta < 190) e = 4;
BlockState nstate = state.setValue(SolarPanelBlock.EXPOSITION, e); BlockState nstate = state.setValue(SolarPanelBlock.EXPOSITION, e);
if(nstate != state) level.setBlock(worldPosition, nstate, 1|2); 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 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 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)); 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_); 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_)); battery_.setEnergyStored(Math.min(battery_.getEnergyStored() + (current_production_ * (TICK_INTERVAL * ACCUMULATION_INTERVAL)), max_power_storage_));
if(battery_.getEnergyStored() >= (feeding_threshold)) output_enabled_ = true; if (battery_.getEnergyStored() >= (feeding_threshold)) output_enabled_ = true;
} }
} }
} }

View file

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

View file

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

View file

@ -8,7 +8,13 @@
*/ */
package dev.zontreck.engineerdecor.blocks; package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.engineerdecor.ModConfig;
import dev.zontreck.engineerdecor.ModContent;
import dev.zontreck.engineerdecor.detail.TreeCutting; 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.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes; 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.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; 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.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockBehaviour; 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.capabilities.ForgeCapabilities;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage; 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 javax.annotation.Nullable;
import java.util.Random; import java.util.Random;
public class EdTreeCutter {
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 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 // 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 static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public TreeCutterBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) public TreeCutterBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABB) {
{ super(config, builder, unrotatedAABB); } super(config, builder, unrotatedAABB);
}
@Override @Override
public boolean isBlockEntityTicking(Level world, BlockState state) public boolean isBlockEntityTicking(Level world, BlockState state) {
{ return true; } return true;
}
@Override @Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
{ super.createBlockStateDefinition(builder); builder.add(ACTIVE); } super.createBlockStateDefinition(builder);
builder.add(ACTIVE);
}
@Override @Override
@Nullable @Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) public BlockState getStateForPlacement(BlockPlaceContext context) {
{ return super.getStateForPlacement(context).setValue(ACTIVE, false); } return super.getStateForPlacement(context).setValue(ACTIVE, false);
}
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) {
{ if ((state.getBlock() != this) || (!state.getValue(ACTIVE))) return;
if((state.getBlock()!=this) || (!state.getValue(ACTIVE))) return;
// Sound // 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); world.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), SoundEvents.WOOD_HIT, SoundSource.BLOCKS, 0.1f, 1.0f, false);
} }
// Particles // Particles
{ {
final double rv = rnd.nextDouble(); final double rv = rnd.nextDouble();
if(rv < 0.8) { if (rv < 0.8) {
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ(); 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); 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)) { switch (state.getValue(HORIZONTAL_FACING)) {
case WEST -> world.addParticle(ParticleTypes.SMOKE, x - xc, yr, z + xr, 0.0, 0.0, 0.0); 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 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); 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 @Override
@SuppressWarnings("deprecation") @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) {
{ if (world.isClientSide()) return InteractionResult.SUCCESS;
if(world.isClientSide()) return InteractionResult.SUCCESS;
BlockEntity te = world.getBlockEntity(pos); 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; return InteractionResult.CONSUME;
} }
@Override @Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) public boolean shouldCheckWeakPower(BlockState state, SignalGetter level, BlockPos pos, Direction side) {
{ return false; } return false;
}
} }
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// Tile entity // 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 IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5; public static final int TICK_INTERVAL = 5;
public static final int BOOST_FACTOR = 6; 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 energy_max = DEFAULT_BOOST_ENERGY * 20;
private static int cutting_time_needed = 20 * DEFAULT_CUTTING_TIME_NEEDED; private static int cutting_time_needed = 20 * DEFAULT_CUTTING_TIME_NEEDED;
private static boolean requires_power = false; private static boolean requires_power = false;
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> this);
private int tick_timer_; private int tick_timer_;
private int active_timer_; private int active_timer_;
private int proc_time_elapsed_; private int proc_time_elapsed_;
private int energy_; 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); boost_energy_consumption = TICK_INTERVAL * Mth.clamp(boost_energy_per_tick, 4, 4096);
energy_max = Math.max(boost_energy_consumption * 10, 10000); energy_max = Math.max(boost_energy_consumption * 10, 10000);
cutting_time_needed = 20 * Mth.clamp(cutting_time_seconds, 10, 240); cutting_time_needed = 20 * Mth.clamp(cutting_time_seconds, 10, 240);
requires_power = power_required; 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) public void readnbt(CompoundTag nbt) {
{ super(ModContent.getBlockEntityTypeOfBlock(state.getBlock()), pos, state); } energy_ = nbt.getInt("energy");
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));
} }
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 ------------------------------------------------------------------------------ // BlockEntity ------------------------------------------------------------------------------
@Override public void state_message(Player player) {
public void load(CompoundTag nbt) String progress = "0";
{ super.load(nbt); readnbt(nbt); } 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 @Override
protected void saveAdditional(CompoundTag nbt) public void load(CompoundTag nbt) {
{ super.saveAdditional(nbt); writenbt(nbt); } super.load(nbt);
readnbt(nbt);
}
@Override @Override
public void setRemoved() protected void saveAdditional(CompoundTag nbt) {
{ super.saveAdditional(nbt);
super.setRemoved(); writenbt(nbt);
energy_handler_.invalidate();
} }
// IEnergyStorage ---------------------------------------------------------------------------- // IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> this); @Override
public void setRemoved() {
super.setRemoved();
energy_handler_.invalidate();
}
@Override @Override
public boolean canExtract() public boolean canExtract() {
{ return false; } return false;
}
@Override @Override
public boolean canReceive() public boolean canReceive() {
{ return true; } return true;
}
@Override @Override
public int getMaxEnergyStored() public int getMaxEnergyStored() {
{ return boost_energy_consumption*2; } return boost_energy_consumption * 2;
}
@Override @Override
public int getEnergyStored() public int getEnergyStored() {
{ return energy_; } return energy_;
}
@Override @Override
public int extractEnergy(int maxExtract, boolean simulate) public int extractEnergy(int maxExtract, boolean simulate) {
{ return 0; } return 0;
}
@Override @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)); maxReceive = Mth.clamp(maxReceive, 0, Math.max((energy_max) - energy_, 0));
if(!simulate) energy_ += maxReceive; if (!simulate) energy_ += maxReceive;
return maxReceive; return maxReceive;
} }
// Capability export ---------------------------------------------------------------------------- // Capability export ----------------------------------------------------------------------------
@Override @Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing) {
{ if (capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
if(capability == ForgeCapabilities.ENERGY) return energy_handler_.cast();
return super.getCapability(capability, facing); return super.getCapability(capability, facing);
} }
// ITickable ------------------------------------------------------------------------------------ // ITickable ------------------------------------------------------------------------------------
@Override @Override
public void tick() public void tick() {
{ if (--tick_timer_ > 0) return;
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL; tick_timer_ = TICK_INTERVAL;
final BlockState device_state = level.getBlockState(worldPosition); 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 BlockPos tree_pos = worldPosition.relative(device_state.getValue(TreeCutterBlock.HORIZONTAL_FACING));
final BlockState tree_state = level.getBlockState(tree_pos); final BlockState tree_state = level.getBlockState(tree_pos);
if(!TreeCutting.canChop(level, tree_state, tree_pos) || (level.hasNeighborSignal(worldPosition))) { 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 (device_state.getValue(TreeCutterBlock.ACTIVE))
level.setBlock(worldPosition, device_state.setValue(TreeCutterBlock.ACTIVE, false), 1 | 2);
proc_time_elapsed_ = 0; proc_time_elapsed_ = 0;
active_timer_ = 0; active_timer_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL; tick_timer_ = IDLE_TICK_INTERVAL;
return; return;
} }
proc_time_elapsed_ += TICK_INTERVAL; proc_time_elapsed_ += TICK_INTERVAL;
if(energy_ >= boost_energy_consumption) { if (energy_ >= boost_energy_consumption) {
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; active_timer_ = 2;
} else if(!requires_power) { } else if (!requires_power) {
active_timer_ = 1024; active_timer_ = 1024;
} else if(active_timer_ > 0) { } else if (active_timer_ > 0) {
--active_timer_; --active_timer_;
} }
boolean active = (active_timer_ > 0); boolean active = (active_timer_ > 0);
if(requires_power && !active) { if (requires_power && !active) {
proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL); 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; proc_time_elapsed_ = 0;
TreeCutting.chopTree(level, tree_state, tree_pos, 512, false); 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); level.playSound(null, worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), SoundEvents.WOOD_BREAK, SoundSource.BLOCKS, 1.0f, 1.0f);
active = false; active = false;
} }
if(device_state.getValue(TreeCutterBlock.ACTIVE) != active) { if (device_state.getValue(TreeCutterBlock.ACTIVE) != active) {
level.setBlock(worldPosition, device_state.setValue(TreeCutterBlock.ACTIVE, active), 1|2); level.setBlock(worldPosition, device_state.setValue(TreeCutterBlock.ACTIVE, active), 1 | 2);
} }
} }
} }

View file

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

View file

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

View file

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

View file

@ -8,6 +8,7 @@
*/ */
package dev.zontreck.engineerdecor.blocks; package dev.zontreck.engineerdecor.blocks;
import dev.zontreck.libzontreck.edlibmc.StandardBlocks;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand; 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.AABB;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import dev.zontreck.engineerdecor.libmc.StandardBlocks;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@ -34,27 +34,28 @@ import java.util.Collections;
import java.util.List; import java.util.List;
public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWaterLoggable public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWaterLoggable {
{ public EdgeAlignedRailingBlock(long config, BlockBehaviour.Properties properties, final AABB base_aabb, final AABB railing_aabb) {
public EdgeAlignedRailingBlock(long config, BlockBehaviour.Properties properties, final AABB base_aabb, final AABB railing_aabb) super(config, properties, base_aabb, railing_aabb, 0);
{ super(config, properties, base_aabb, railing_aabb, 0); } }
@Override @Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
{ return true; } return true;
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) public boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) {
{ return (useContext.getItemInHand().getItem() == asItem()) || super.canBeReplaced(state, useContext); } return (useContext.getItemInHand().getItem() == asItem()) || super.canBeReplaced(state, useContext);
}
@Override @Override
@Nullable @Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) public BlockState getStateForPlacement(BlockPlaceContext context) {
{ if (context.getClickedFace() != Direction.UP) return null;
if(context.getClickedFace() != Direction.UP) return null;
BlockState state = context.getLevel().getBlockState(context.getClickedPos()); 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())); final Vec3 rhv = context.getClickLocation().subtract(Vec3.atCenterOf(context.getClickedPos()));
BooleanProperty side = getDirectionProperty(Direction.getNearest(rhv.x, 0, rhv.z)); BooleanProperty side = getDirectionProperty(Direction.getNearest(rhv.x, 0, rhv.z));
return state.setValue(side, true); return state.setValue(side, true);
@ -62,17 +63,17 @@ public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWat
@Override @Override
@SuppressWarnings("deprecation") @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) {
{ if (player.getItemInHand(hand).getItem() != asItem()) return InteractionResult.PASS;
if(player.getItemInHand(hand).getItem() != asItem()) return InteractionResult.PASS;
Direction face = hit.getDirection(); 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())); 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); BooleanProperty railing = getDirectionProperty(face);
boolean add = (!state.getValue(railing)); boolean add = (!state.getValue(railing));
state = state.setValue(railing, add); 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()); state = (world.getFluidState(pos).getType() == Fluids.WATER) ? Blocks.WATER.defaultBlockState() : (Blocks.AIR.defaultBlockState());
EdCatwalkBlock.place_consume(state, world, pos, player, hand, add ? 1 : -1); EdCatwalkBlock.place_consume(state, world, pos, player, hand, add ? 1 : -1);
} else { } else {
@ -84,15 +85,15 @@ public class EdgeAlignedRailingBlock extends StandardBlocks.HorizontalFourWayWat
// -- IDecorBlock // -- IDecorBlock
@Override @Override
public boolean hasDynamicDropList() public boolean hasDynamicDropList() {
{ return true; } return true;
}
@Override @Override
public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) public List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) {
{ if (world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY);
List<ItemStack> drops = new ArrayList<>(); 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))); drops.add(new ItemStack(state.getBlock().asItem(), Math.max(n, 1)));
return drops; 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; import net.minecraftforge.api.distmarker.OnlyIn;
public class ModRenderers public class ModRenderers {
{
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
// InvisibleEntityRenderer // InvisibleEntityRenderer
//-------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT) @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(); private final Minecraft mc = Minecraft.getInstance();
public InvisibleEntityRenderer(EntityRendererProvider.Context context) public InvisibleEntityRenderer(EntityRendererProvider.Context context) {
{ super(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) public Vec3 getRenderOffset(T entity, float partialTicks) {
{ return Vec3.ZERO; } return Vec3.ZERO;
}
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public ResourceLocation getTextureLocation(T entity) public ResourceLocation getTextureLocation(T entity) {
{ return TextureAtlas.LOCATION_BLOCKS; } return TextureAtlas.LOCATION_BLOCKS;
}
protected boolean shouldShowName(T entity) protected boolean shouldShowName(T entity) {
{ return false; } 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; package dev.zontreck.engineerdecor.detail;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import dev.zontreck.libzontreck.edlibmc.Auxiliaries;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i; import net.minecraft.core.Vec3i;
import net.minecraft.resources.ResourceLocation; 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.VineBlock;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import dev.zontreck.engineerdecor.libmc.Auxiliaries;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class TreeCutting public class TreeCutting {
{
private static final Set<Block> universal_logs_ = new HashSet<>(); 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(); universal_logs_.clear();
if(universal_logs.isEmpty()) return; if (universal_logs.isEmpty()) return;
try { try {
universal_logs.forEach(rls->{ universal_logs.forEach(rls -> {
final ResourceLocation rl = ResourceLocation.tryParse(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)); universal_logs_.add(ForgeRegistries.BLOCKS.getValue(rl));
}); });
} catch(Throwable ex) { } catch (Throwable ex) {
Auxiliaries.logError("Unexpected exception parsing universal log blocks: " + ex.getMessage()); 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()) + "."); 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( public static boolean canChop(Level world, BlockState state, BlockPos pos) {
new Vec3i( 1,0, 0), new Vec3i( 1,0, 1), new Vec3i( 0,0, 1), return isLog(state) || (universal_logs_.contains(state.getBlock()) && isLog(world.getBlockState(pos.above())));
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));
} }
private static boolean isLeaves(BlockState state) private static boolean isLog(BlockState state) {
{ return (state.is(BlockTags.LOGS));
if(state.getBlock() instanceof LeavesBlock) return true; }
if(state.is(BlockTags.LEAVES)) return true;
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; 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<>(); ArrayList<BlockPos> to_decay = new ArrayList<>();
for(int y=-1; y<=1; ++y) { for (int y = -1; y <= 1; ++y) {
final BlockPos layer = centerPos.offset(0,y,0); final BlockPos layer = centerPos.offset(0, y, 0);
for(Vec3i v:hoffsets) { for (Vec3i v : hoffsets) {
BlockPos pos = layer.offset(v); 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); checked.add(pos);
to_decay.add(pos); to_decay.add(pos);
if(recursion_left > 0) { if (recursion_left > 0) {
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, recursion_left-1)); to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, recursion_left - 1));
} }
} }
} }
@ -95,17 +91,16 @@ public class TreeCutting
return to_decay; 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); 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) 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(world.isClientSide) return 0; if (universal_logs_.contains(broken_state.getBlock()))
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. 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; if (!isLog(broken_state)) return 0;
final long ymin = startPos.getY(); final long ymin = startPos.getY();
final long max_leaf_distance = 8; final long max_leaf_distance = 8;
Set<BlockPos> checked = new HashSet<>(); Set<BlockPos> checked = new HashSet<>();
@ -120,33 +115,33 @@ public class TreeCutting
queue.add(startPos); queue.add(startPos);
int cutlevel = 0; int cutlevel = 0;
int steps_left = 128; int steps_left = 128;
while(!queue.isEmpty() && (--steps_left >= 0)) { while (!queue.isEmpty() && (--steps_left >= 0)) {
final BlockPos pos = queue.removeFirst(); final BlockPos pos = queue.removeFirst();
// Vertical search // Vertical search
final BlockPos uppos = pos.above(); final BlockPos uppos = pos.above();
final BlockState upstate = world.getBlockState(uppos); final BlockState upstate = world.getBlockState(uppos);
if(!checked.contains(uppos)) { if (!checked.contains(uppos)) {
checked.add(uppos); checked.add(uppos);
if(isSameLog(upstate, broken_state)) { if (isSameLog(upstate, broken_state)) {
// Up is log // Up is log
upqueue.add(uppos); upqueue.add(uppos);
to_break.add(uppos); to_break.add(uppos);
steps_left = 128; steps_left = 128;
} else { } else {
boolean isleaf = isLeaves(upstate); boolean isleaf = isLeaves(upstate);
if(isleaf || world.isEmptyBlock(uppos) || (upstate.getBlock() instanceof VineBlock)) { if (isleaf || world.isEmptyBlock(uppos) || (upstate.getBlock() instanceof VineBlock)) {
if(isleaf) to_decay.add(uppos); if (isleaf) to_decay.add(uppos);
// Up is air, check adjacent for diagonal up (e.g. Accacia) // 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); final BlockPos p = uppos.offset(v);
if(checked.contains(p)) continue; if (checked.contains(p)) continue;
checked.add(p); checked.add(p);
final BlockState st = world.getBlockState(p); final BlockState st = world.getBlockState(p);
final Block bl = st.getBlock(); final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) { if (isSameLog(st, broken_state)) {
queue.add(p); queue.add(p);
to_break.add(p); to_break.add(p);
} else if(isLeaves(st)) { } else if (isLeaves(st)) {
to_decay.add(p); to_decay.add(p);
} }
} }
@ -154,22 +149,23 @@ public class TreeCutting
} }
} }
// Lateral search // Lateral search
for(Vec3i v:hoffsets) { for (Vec3i v : hoffsets) {
final BlockPos p = pos.offset(v); final BlockPos p = pos.offset(v);
if(checked.contains(p)) continue; if (checked.contains(p)) continue;
checked.add(p); 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 BlockState st = world.getBlockState(p);
final Block bl = st.getBlock(); final Block bl = st.getBlock();
if(isSameLog(st, broken_state)) { if (isSameLog(st, broken_state)) {
queue.add(p); queue.add(p);
to_break.add(p); to_break.add(p);
} else if(isLeaves(st)) { } else if (isLeaves(st)) {
queue.add(p); queue.add(p);
to_decay.add(p); to_decay.add(p);
} }
} }
if(queue.isEmpty() && (!upqueue.isEmpty())) { if (queue.isEmpty() && (!upqueue.isEmpty())) {
queue = upqueue; queue = upqueue;
upqueue = new LinkedList<>(); upqueue = new LinkedList<>();
++cutlevel; ++cutlevel;
@ -178,31 +174,31 @@ public class TreeCutting
} }
{ {
// Determine lose logs between the leafs // Determine lose logs between the leafs
for(BlockPos pos:to_decay) { for (BlockPos pos : to_decay) {
int dist = 1; int dist = 1;
to_break.addAll(findBlocksAround(world, pos, broken_state, checked, dist)); 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 BlockState leaf_type_state = world.getBlockState(to_decay.get(0));
final ArrayList<BlockPos> leafs = to_decay; final ArrayList<BlockPos> leafs = to_decay;
to_decay = new ArrayList<>(); to_decay = new ArrayList<>();
for(BlockPos pos:leafs) { for (BlockPos pos : leafs) {
int dist = 3; int dist = 3;
to_decay.add(pos); to_decay.add(pos);
to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, dist)); to_decay.addAll(findBlocksAround(world, pos, leaf_type_state, checked, dist));
} }
} }
if(without_target_block) { if (without_target_block) {
checked.remove(startPos); checked.remove(startPos);
} else { } else {
to_break.add(startPos); to_break.add(startPos);
} }
for(BlockPos pos:to_break) breakBlock(world, pos); for (BlockPos pos : to_break) breakBlock(world, pos);
for(BlockPos pos:to_decay) breakBlock(world, pos); for (BlockPos pos : to_decay) breakBlock(world, pos);
{ {
// And now the bill. // 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; package dev.zontreck.engineerdecor.eapi.jei;
public class JEIPlugin {} public class JEIPlugin {
}
/* /*
import mezz.jei.api.constants.RecipeTypes; import mezz.jei.api.constants.RecipeTypes;

View file

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