Souls and flames

- Fix lit soul blaze burner providing smoking instead of haunting
- Fix horses displaying soul particles even when not being haunted
- Add hauntable item attribute
- Re-add right clicking lit blaze burner with shovel to extinguish it
- Move most fan type functionality to abstract methods in the enum
constant
- Rework FurnaceEngineModifiers
This commit is contained in:
PepperCode1 2022-01-09 14:00:55 -08:00
parent 04c76bb6f0
commit a666f24ee0
26 changed files with 464 additions and 337 deletions

View file

@ -531,21 +531,21 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
f33899d90db924319a1b99065bf1faff1aa40d6a assets/create/lang/en_ud.json
748d2635a4f8c97cee2392c1c08c4716f7424202 assets/create/lang/en_us.json
d5eed56ff394835dae0f514f9317b83f7fd3954c assets/create/lang/unfinished/de_de.json
b44cb66962677538209a02fdafc2e62541542d64 assets/create/lang/unfinished/es_cl.json
617f9f1a37b46066b8f6a14f22cbeec8179ce0cd assets/create/lang/unfinished/es_es.json
91d391799b6579914ef35cf8ebe917684b25b9df assets/create/lang/unfinished/fr_fr.json
787470a30ca417e8cf1da6b47ac40879bb274237 assets/create/lang/unfinished/it_it.json
00f079aaebfe906b84b71903f80b0be4127e8cc7 assets/create/lang/unfinished/ja_jp.json
75a8b1e3ead980456ff4a4607b1e28197d9de2e8 assets/create/lang/unfinished/ko_kr.json
6c7f81042ee0cc25e0ababea6cc254b72557aac9 assets/create/lang/unfinished/nl_nl.json
7a3670aa1d488f637a4787c37419a25ace4813bc assets/create/lang/unfinished/pl_pl.json
2c30f012946ab67f44514e987e9be87535eb5c5d assets/create/lang/unfinished/pt_br.json
d466d2f81d81296313375de4766d4e36d7a5e3e4 assets/create/lang/unfinished/pt_pt.json
516e0f0149f814ceec3b15cfb2d46c3c4c8a877c assets/create/lang/unfinished/ru_ru.json
d9b421597a5b0b3ae662a12a94c833d853b24fe5 assets/create/lang/unfinished/zh_cn.json
68b91bb8f3822d2b0798a6ec8a85d7d188c5c4d1 assets/create/lang/unfinished/zh_tw.json
88272181311c543ee6790c7b2d1d434570a5fbad assets/create/lang/en_us.json
1b43ebff99b4a65873acc84996b221d17808da82 assets/create/lang/unfinished/de_de.json
01f3f59f6007c352addcb6e26afc6c29990e577d assets/create/lang/unfinished/es_cl.json
a225447219328491bb5a27c8a4013a627949d86e assets/create/lang/unfinished/es_es.json
6b68c9da5fe9b499621e4cfc39c1161d59ceffe1 assets/create/lang/unfinished/fr_fr.json
5c1858916d9390961f43d0b0304253e7615d1f60 assets/create/lang/unfinished/it_it.json
4e09507f40d2c8c31bc9f0efa105c92a68f091dc assets/create/lang/unfinished/ja_jp.json
c3079836f5899cbb39f95e1278cfa1e9b16e2f6c assets/create/lang/unfinished/ko_kr.json
2b7bbe3efddf575b13d13944877aff1b9c16bb0a assets/create/lang/unfinished/nl_nl.json
51ff37d88dfab3dcc9bd269a651a53c98e5f9fc8 assets/create/lang/unfinished/pl_pl.json
23eefb78c4dfd085ad24b48f24203fdd337e221d assets/create/lang/unfinished/pt_br.json
b82282978c9213e42b78d5ed86cab3cdc63cb53f assets/create/lang/unfinished/pt_pt.json
9b5958c6c7065ff41e9ed74cbe0934910742d39d assets/create/lang/unfinished/ru_ru.json
05c401cdcbace483e56e754123922e73ef7e474d assets/create/lang/unfinished/zh_cn.json
368a87626c80ddc8aee6aa681e6479fbc06f3716 assets/create/lang/unfinished/zh_tw.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json

View file

@ -1165,6 +1165,8 @@
"create.item_attributes.furnace_fuel.inverted": "is not furnace fuel",
"create.item_attributes.washable": "can be Washed",
"create.item_attributes.washable.inverted": "cannot be Washed",
"create.item_attributes.hauntable": "can be Haunted",
"create.item_attributes.hauntable.inverted": "cannot be Haunted",
"create.item_attributes.crushable": "can be Crushed",
"create.item_attributes.crushable.inverted": "cannot be Crushed",
"create.item_attributes.smeltable": "can be Smelted",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1322",
"_": "Missing Localizations: 1324",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "ist nicht Brennstoff",
"create.item_attributes.washable": "kann gewaschen werden",
"create.item_attributes.washable.inverted": "kann nicht gewaschen werden",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "kann zerkleinert werden",
"create.item_attributes.crushable.inverted": "kann nicht zerkleinert werden",
"create.item_attributes.smeltable": "kann geschmolzen werden",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 333",
"_": "Missing Localizations: 335",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "no es cumbustible",
"create.item_attributes.washable": "puede Lavarse",
"create.item_attributes.washable.inverted": "no puede Lavarse",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "puede ser Triturado",
"create.item_attributes.crushable.inverted": "no puede ser Triturado",
"create.item_attributes.smeltable": "puede ser Derretido",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 333",
"_": "Missing Localizations: 335",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "no es combustible para hornos",
"create.item_attributes.washable": "se puede lavar",
"create.item_attributes.washable.inverted": "no se puede lavar",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "puede ser molido",
"create.item_attributes.crushable.inverted": "no puede ser molido",
"create.item_attributes.smeltable": "se puede fundir",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1584",
"_": "Missing Localizations: 1586",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "n'est pas un combustible",
"create.item_attributes.washable": "peut être lavé",
"create.item_attributes.washable.inverted": "ne peut pas être lavé",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "peut être concassé",
"create.item_attributes.crushable.inverted": "ne peut pas être concassé",
"create.item_attributes.smeltable": "peut être fondu",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1273",
"_": "Missing Localizations: 1275",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "non è un combustibile per fornace",
"create.item_attributes.washable": "può essere lavato",
"create.item_attributes.washable.inverted": "non può essere lavato",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "può essere frantumato",
"create.item_attributes.crushable.inverted": "non può essere frantumato",
"create.item_attributes.smeltable": "può essere fuso",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 3",
"_": "Missing Localizations: 5",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "かまどの燃料でないか",
"create.item_attributes.washable": "洗浄できるかか",
"create.item_attributes.washable.inverted": "洗浄できないか",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "粉砕できるかか",
"create.item_attributes.crushable.inverted": "粉砕できないか",
"create.item_attributes.smeltable": "精錬できるかか",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 5",
"_": "Missing Localizations: 7",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "화로 연료로 쓸 수 없음",
"create.item_attributes.washable": "세척될 수 있음",
"create.item_attributes.washable.inverted": "세척될 수 없음",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "분쇄될 수 있음",
"create.item_attributes.crushable.inverted": "분쇄될 수 없음",
"create.item_attributes.smeltable": "구워질 수 있음",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1937",
"_": "Missing Localizations: 1939",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel",
"create.item_attributes.washable": "UNLOCALIZED: can be Washed",
"create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "UNLOCALIZED: can be Crushed",
"create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed",
"create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 372",
"_": "Missing Localizations: 374",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "nie jest paliwem dla pieca",
"create.item_attributes.washable": "może zostać opłukany",
"create.item_attributes.washable.inverted": "nie może zostać opłukany",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "może być rozkruszony",
"create.item_attributes.crushable.inverted": "nie może być rozkruszony",
"create.item_attributes.smeltable": "może zostać przepalony",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1556",
"_": "Missing Localizations: 1558",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel",
"create.item_attributes.washable": "UNLOCALIZED: can be Washed",
"create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "UNLOCALIZED: can be Crushed",
"create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed",
"create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1556",
"_": "Missing Localizations: 1558",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "UNLOCALIZED: is not furnace fuel",
"create.item_attributes.washable": "UNLOCALIZED: can be Washed",
"create.item_attributes.washable.inverted": "UNLOCALIZED: cannot be Washed",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "UNLOCALIZED: can be Crushed",
"create.item_attributes.crushable.inverted": "UNLOCALIZED: cannot be Crushed",
"create.item_attributes.smeltable": "UNLOCALIZED: can be Smelted",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 377",
"_": "Missing Localizations: 379",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "не является топливом",
"create.item_attributes.washable": "можно промыть",
"create.item_attributes.washable.inverted": "нельзя промыть",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "можно измельчить",
"create.item_attributes.crushable.inverted": "нельзя разместить",
"create.item_attributes.smeltable": "можно расплавить",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 3",
"_": "Missing Localizations: 5",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "不可作为燃料",
"create.item_attributes.washable": "可被洗涤",
"create.item_attributes.washable.inverted": "不可被洗涤",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "可被粉碎",
"create.item_attributes.crushable.inverted": "不可被粉碎",
"create.item_attributes.smeltable": "可被熔炉烧制",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 391",
"_": "Missing Localizations: 393",
"_": "->------------------------] Game Elements [------------------------<-",
@ -1166,6 +1166,8 @@
"create.item_attributes.furnace_fuel.inverted": "不是燃料",
"create.item_attributes.washable": "可被篩洗",
"create.item_attributes.washable.inverted": "不可被篩洗",
"create.item_attributes.hauntable": "UNLOCALIZED: can be Haunted",
"create.item_attributes.hauntable.inverted": "UNLOCALIZED: cannot be Haunted",
"create.item_attributes.crushable": "可被粉碎",
"create.item_attributes.crushable.inverted": "不可被粉碎",
"create.item_attributes.smeltable": "可被熔爐融煉",

View file

@ -10,7 +10,7 @@ import com.google.gson.GsonBuilder;
import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
import com.simibubi.create.content.CreateItemGroup;
import com.simibubi.create.content.contraptions.TorquePropagator;
import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineModifiers;
import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineInteractions;
import com.simibubi.create.content.curiosities.weapons.BuiltinPotatoProjectileTypes;
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
import com.simibubi.create.content.palettes.AllPaletteBlocks;
@ -96,8 +96,8 @@ public class Create {
AllInteractionBehaviours.register();
AllWorldFeatures.register();
AllEnchantments.register();
FurnaceEngineModifiers.register();
AllConfigs.register(modLoadingContext);
FurnaceEngineInteractions.registerDefaults();
BlockSpoutingBehaviour.register();
ForgeMod.enableMilkFluid();

View file

@ -22,22 +22,11 @@ import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.animal.horse.Horse;
import net.minecraft.world.entity.animal.horse.SkeletonHorse;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.EnderMan;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
@ -53,11 +42,6 @@ import net.minecraftforge.fml.DistExecutor;
public class AirCurrent {
private static final DamageSource damageSourceFire = new DamageSource("create.fan_fire").setScalesWithDifficulty()
.setIsFire();
private static final DamageSource damageSourceLava = new DamageSource("create.fan_lava").setScalesWithDifficulty()
.setIsFire();
public final IAirCurrentSource source;
public AABB bounds = new AABB(0, 0, 0, 0, 0, 0);
public List<AirCurrentSegment> segments = new ArrayList<>();
@ -134,93 +118,17 @@ public class AirCurrent {
continue;
}
if (entity instanceof ItemEntity) {
InWorldProcessing.spawnParticlesForProcessing(world, entity.position(), processingType);
ItemEntity itemEntity = (ItemEntity) entity;
if (world.isClientSide)
if (entity instanceof ItemEntity itemEntity) {
if (world.isClientSide) {
processingType.spawnParticlesForProcessing(world, entity.position());
continue;
}
if (InWorldProcessing.canProcess(itemEntity, processingType))
InWorldProcessing.applyProcessing(itemEntity, processingType);
continue;
}
if (entity instanceof Horse && world.isClientSide) {
Vec3 p = entity.getPosition(0);
Vec3 v = p.add(0, 0.5f, 0)
.add(VecHelper.offsetRandomly(Vec3.ZERO, world.random, 1)
.multiply(1, 0.2f, 1)
.normalize()
.scale(1f));
world.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v.x, v.y, v.z, 0, 0.1f, 0);
if (world.random.nextInt(3) == 0)
world.addParticle(ParticleTypes.LARGE_SMOKE, p.x, p.y + .5f, p.z,
(world.random.nextFloat() - .5f) * .5f, 0.1f, (world.random.nextFloat() - .5f) * .5f);
}
if (world.isClientSide)
continue;
switch (processingType) {
case BLASTING:
if (!entity.fireImmune()) {
entity.setSecondsOnFire(10);
entity.hurt(damageSourceLava, 4);
}
break;
case SMOKING:
if (!entity.fireImmune()) {
entity.setSecondsOnFire(2);
entity.hurt(damageSourceFire, 2);
}
break;
case HAUNTING:
if (entity instanceof LivingEntity livingEntity) {
livingEntity.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 30, 0, false, false));
livingEntity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1, false, false));
}
if (entity instanceof Horse horse) {
int progress = horse.getPersistentData()
.getInt("CreateHaunting");
if (progress < 100) {
if (progress % 10 == 0) {
world.playSound(null, entity.blockPosition(), SoundEvents.SOUL_ESCAPE, SoundSource.NEUTRAL,
1f, 1.5f * progress / 100f);
}
horse.getPersistentData()
.putInt("CreateHaunting", progress + 1);
continue;
}
world.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE,
SoundSource.NEUTRAL, 1.25f, 0.65f);
SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(world);
CompoundTag serializeNBT = horse.saveWithoutId(new CompoundTag());
serializeNBT.remove("UUID");
if (!horse.getArmor()
.isEmpty())
horse.spawnAtLocation(horse.getArmor());
skeletonHorse.deserializeNBT(serializeNBT);
skeletonHorse.setPos(horse.getPosition(0));
world.addFreshEntity(skeletonHorse);
horse.discard();
}
break;
case SPLASHING:
if (entity instanceof EnderMan || entity.getType() == EntityType.SNOW_GOLEM
|| entity.getType() == EntityType.BLAZE) {
entity.hurt(DamageSource.DROWN, 2);
}
if (!entity.isOnFire())
break;
entity.clearFire();
world.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE, SoundSource.NEUTRAL,
0.7F, 1.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.4F);
break;
default:
break;
}
processingType.affectEntity(entity, world);
}
}
@ -375,10 +283,11 @@ public class AirCurrent {
InWorldProcessing.Type processingType = pair.getRight();
handler.handleProcessingOnAllItems((transported) -> {
InWorldProcessing.spawnParticlesForProcessing(world, handler.getWorldPositionOf(transported),
processingType);
if (world.isClientSide)
if (world.isClientSide) {
if (world != null)
processingType.spawnParticlesForProcessing(world, handler.getWorldPositionOf(transported));
return TransportedResult.doNothing();
}
return InWorldProcessing.applyProcessing(transported, world, processingType);
});
}

View file

@ -33,7 +33,7 @@ public class FurnaceEngineBlock extends EngineBlock implements ITE<FurnaceEngine
@Override
protected boolean isValidBaseBlock(BlockState baseBlock, BlockGetter world, BlockPos pos) {
return FurnaceEngineModifiers.get().getEngineState(baseBlock).isEngine();
return FurnaceEngineInteractions.getHandler(baseBlock).getHeatSource(baseBlock).isValid();
}
@Override

View file

@ -0,0 +1,111 @@
package com.simibubi.create.content.contraptions.components.flywheel.engine;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.world.level.block.AbstractFurnaceBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.IRegistryDelegate;
/**
* Example:
*
* <pre>
* {@code
* FurnaceEngineInteractions.registerHandler(Blocks.REDSTONE_LAMP.delegate, FurnaceEngineInteractions.InteractionHandler.of(
* s -> s.getBlock() instanceof RedstoneLampBlock && s.hasProperty(RedstoneLampBlock.LIT) ?
* (s.getValue(RedstoneLampBlock.LIT) ? HeatSource.ACTIVE : HeatSource.VALID) : HeatSource.EMPTY, s -> 1.5f));
* }
* </pre>
*/
public class FurnaceEngineInteractions {
private static final Map<IRegistryDelegate<Block>, InteractionHandler> HANDLERS = new HashMap<>();
private static final InteractionHandler DEFAULT_HANDLER = new InteractionHandler() {};
public static void registerHandler(IRegistryDelegate<Block> block, InteractionHandler handler) {
HANDLERS.put(block, handler);
}
public static InteractionHandler getHandler(IRegistryDelegate<Block> delegate) {
return HANDLERS.getOrDefault(delegate, DEFAULT_HANDLER);
}
public static InteractionHandler getHandler(BlockState state) {
return getHandler(state.getBlock().delegate);
}
public static void registerDefaults() {
registerHandler(Blocks.BLAST_FURNACE.delegate, InteractionHandler.ofCustomSpeedModifier(state -> 2f));
}
public interface InteractionHandler {
default HeatSource getHeatSource(BlockState state) {
if (state.getBlock() instanceof AbstractFurnaceBlock && state.hasProperty(AbstractFurnaceBlock.LIT)) {
if (state.getValue(AbstractFurnaceBlock.LIT)) {
return HeatSource.ACTIVE;
} else {
return HeatSource.VALID;
}
}
return HeatSource.EMPTY;
}
default float getSpeedModifier(BlockState state) {
return 1f;
};
static InteractionHandler of(Function<BlockState, HeatSource> heatSourceFunc, Function<BlockState, Float> speedModifierFunc) {
return new InteractionHandler() {
@Override
public HeatSource getHeatSource(BlockState state) {
return heatSourceFunc.apply(state);
}
@Override
public float getSpeedModifier(BlockState state) {
return speedModifierFunc.apply(state);
}
};
}
static InteractionHandler ofCustomHeatSource(Function<BlockState, HeatSource> heatSourceFunc) {
return new InteractionHandler() {
@Override
public HeatSource getHeatSource(BlockState state) {
return heatSourceFunc.apply(state);
}
};
}
static InteractionHandler ofCustomSpeedModifier(Function<BlockState, Float> speedModifierFunc) {
return new InteractionHandler() {
@Override
public float getSpeedModifier(BlockState state) {
return speedModifierFunc.apply(state);
}
};
}
}
public enum HeatSource {
EMPTY,
VALID,
ACTIVE;
public boolean isEmpty() {
return this == EMPTY;
}
public boolean isValid() {
return this != EMPTY;
}
public boolean isActive() {
return this == ACTIVE;
}
}
}

View file

@ -1,84 +0,0 @@
package com.simibubi.create.content.contraptions.components.flywheel.engine;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.world.level.block.AbstractFurnaceBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.registries.IRegistryDelegate;
public class FurnaceEngineModifiers {
private final static FurnaceEngineModifiers INSTANCE = new FurnaceEngineModifiers();
protected FurnaceEngineModifiers() {
blockModifiers = new HashMap<>();
blockActivators = new HashMap<>();
}
private final Map<IRegistryDelegate<Block>, Float> blockModifiers;
private final Map<IRegistryDelegate<Block>, Function<BlockState, EngineState>> blockActivators;
public void register(IRegistryDelegate<Block> block, float modifier) {
this.blockModifiers.put(block, modifier);
}
public void register(IRegistryDelegate<Block> block, float modifier, Function<BlockState, EngineState> engineState) {
this.blockModifiers.put(block, modifier);
this.blockActivators.put(block, engineState);
}
private float getModifierOrDefault(BlockState state, float defaultValue) {
return blockModifiers.getOrDefault(state.getBlock().delegate, defaultValue);
}
private Function<BlockState, EngineState> getEngineStateOrDefault(BlockState state, Function<BlockState, EngineState> engineState) {
return blockActivators.getOrDefault(state.getBlock().delegate, engineState);
}
public float getModifier(BlockState state) {
return getModifierOrDefault(state, 1f);
}
public EngineState getEngineState(BlockState state) {
return getEngineStateOrDefault(state,
s -> s.getBlock() instanceof AbstractFurnaceBlock && s.hasProperty(AbstractFurnaceBlock.LIT) ?
(s.getValue(AbstractFurnaceBlock.LIT) ? EngineState.ACTIVE : EngineState.VALID) : EngineState.EMPTY).apply(state);
}
public static void register() {
get().register(Blocks.BLAST_FURNACE.delegate, 2f);
/*
Example:
get().register(Blocks.REDSTONE_LAMP.delegate, 1f,
s -> s.getBlock() instanceof RedstoneLampBlock && s.hasProperty(RedstoneLampBlock.LIT) ?
(s.getValue(RedstoneLampBlock.LIT) ? EngineState.ACTIVE : EngineState.VALID) : EngineState.EMPTY);
*/
}
public static FurnaceEngineModifiers get() {
return INSTANCE;
}
public enum EngineState {
EMPTY,
VALID,
ACTIVE;
public boolean isEngine() {
return this != EMPTY;
}
public boolean isActive() {
return this == ACTIVE;
}
public boolean isEmpty() {
return this == EMPTY;
}
}
}

View file

@ -1,7 +1,8 @@
package com.simibubi.create.content.contraptions.components.flywheel.engine;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineModifiers.EngineState;
import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineInteractions.HeatSource;
import com.simibubi.create.content.contraptions.components.flywheel.engine.FurnaceEngineInteractions.InteractionHandler;
import com.simibubi.create.foundation.block.BlockStressValues;
import net.minecraft.core.BlockPos;
@ -22,12 +23,13 @@ public class FurnaceEngineTileEntity extends EngineTileEntity {
public void updateFurnace() {
BlockState state = level.getBlockState(EngineBlock.getBaseBlockPos(getBlockState(), worldPosition));
EngineState engineState = FurnaceEngineModifiers.get().getEngineState(state);
if (engineState.isEmpty())
InteractionHandler handler = FurnaceEngineInteractions.getHandler(state);
HeatSource heatSource = handler.getHeatSource(state);
if (heatSource.isEmpty())
return;
float modifier = FurnaceEngineModifiers.get().getModifier(state);
boolean active = engineState.isActive();
float modifier = handler.getSpeedModifier(state);
boolean active = heatSource.isActive();
float speed = active ? 16 * modifier : 0;
float capacity =
(float) (active ? BlockStressValues.getCapacity(AllBlocks.FURNACE_ENGINE.get())

View file

@ -1,11 +1,19 @@
package com.simibubi.create.content.contraptions.processing;
import static com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.getHeatLevelOf;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import com.mojang.math.Vector3f;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.content.contraptions.components.fan.HauntingRecipe;
import com.simibubi.create.content.contraptions.components.fan.SplashingRecipe;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.contraptions.processing.burner.LitBlazeBurnerBlock;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.item.ItemHelper;
@ -17,10 +25,25 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.animal.horse.Horse;
import net.minecraft.world.entity.animal.horse.SkeletonHorse;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.EnderMan;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.item.crafting.BlastingRecipe;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.SmeltingRecipe;
import net.minecraft.world.item.crafting.SmokingRecipe;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
@ -34,44 +57,16 @@ import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.RecipeWrapper;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.getHeatLevelOf;
public class InWorldProcessing {
private static final RecipeWrapper WRAPPER = new RecipeWrapper(new ItemStackHandler(1));
private static final DamageSource FIRE_DAMAGE_SOURCE = new DamageSource("create.fan_fire").setScalesWithDifficulty()
.setIsFire();
private static final DamageSource LAVA_DAMAGE_SOURCE = new DamageSource("create.fan_lava").setScalesWithDifficulty()
.setIsFire();
private static final RecipeWrapper RECIPE_WRAPPER = new RecipeWrapper(new ItemStackHandler(1));
private static final SplashingWrapper SPLASHING_WRAPPER = new SplashingWrapper();
private static final HauntingWrapper SOUL_SMOKING_WRAPPER = new HauntingWrapper();
public enum Type {
SMOKING, BLASTING, SPLASHING, HAUNTING, NONE;
public static Type byBlock(BlockGetter reader, BlockPos pos) {
BlockState blockState = reader.getBlockState(pos);
FluidState fluidState = reader.getFluidState(pos);
if (fluidState.getType() == Fluids.WATER || fluidState.getType() == Fluids.FLOWING_WATER)
return Type.SPLASHING;
Block block = blockState.getBlock();
if (block == Blocks.SOUL_FIRE
|| block == Blocks.SOUL_CAMPFIRE && blockState.getOptionalValue(CampfireBlock.LIT)
.orElse(false))
return Type.HAUNTING;
if (block == Blocks.FIRE || AllBlocks.LIT_BLAZE_BURNER.has(blockState)
|| (BlockTags.CAMPFIRES.contains(block) && blockState.getOptionalValue(CampfireBlock.LIT)
.orElse(false))
|| getHeatLevelOf(blockState) == BlazeBurnerBlock.HeatLevel.SMOULDERING)
return Type.SMOKING;
if (block == Blocks.LAVA || getHeatLevelOf(blockState).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING))
return Type.BLASTING;
return Type.NONE;
}
}
private static final HauntingWrapper HAUNTING_WRAPPER = new HauntingWrapper();
public static boolean canProcess(ItemEntity entity, Type type) {
if (entity.getPersistentData()
@ -82,7 +77,7 @@ public class InWorldProcessing {
CompoundTag processing = compound.getCompound("Processing");
if (Type.valueOf(processing.getString("Type")) != type) {
boolean canProcess = canProcess(entity.getItem(), type, entity.level);
boolean canProcess = type.canProcess(entity.getItem(), entity.level);
processing.putString("Type", type.name());
if (!canProcess)
processing.putInt("Time", -1);
@ -93,43 +88,7 @@ public class InWorldProcessing {
return false;
}
}
return canProcess(entity.getItem(), type, entity.level);
}
private static boolean canProcess(ItemStack stack, Type type, Level world) {
if (type == Type.BLASTING) {
WRAPPER.setItem(0, stack);
Optional<SmeltingRecipe> smeltingRecipe = world.getRecipeManager()
.getRecipeFor(RecipeType.SMELTING, WRAPPER, world);
if (smeltingRecipe.isPresent())
return true;
WRAPPER.setItem(0, stack);
Optional<BlastingRecipe> blastingRecipe = world.getRecipeManager()
.getRecipeFor(RecipeType.BLASTING, WRAPPER, world);
if (blastingRecipe.isPresent())
return true;
return !stack.getItem()
.isFireResistant();
}
if (type == Type.SMOKING) {
WRAPPER.setItem(0, stack);
Optional<SmokingRecipe> recipe = world.getRecipeManager()
.getRecipeFor(RecipeType.SMOKING, WRAPPER, world);
return recipe.isPresent();
}
if (type == Type.SPLASHING)
return isWashable(stack, world);
if (type == Type.HAUNTING)
return isSoulSmokeable(stack, world);
return false;
return type.canProcess(entity.getItem(), entity.level);
}
public static boolean isWashable(ItemStack stack, Level world) {
@ -138,9 +97,9 @@ public class InWorldProcessing {
return recipe.isPresent();
}
public static boolean isSoulSmokeable(ItemStack stack, Level world) {
SOUL_SMOKING_WRAPPER.setItem(0, stack);
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(SOUL_SMOKING_WRAPPER, world);
public static boolean isHauntable(ItemStack stack, Level world) {
HAUNTING_WRAPPER.setItem(0, stack);
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world);
return recipe.isPresent();
}
@ -170,7 +129,7 @@ public class InWorldProcessing {
int processingTime =
(int) (AllConfigs.SERVER.kinetics.inWorldProcessingTime.get() * timeModifierForStackSize) + 1;
transported.processingTime = processingTime;
if (!canProcess(transported.stack, type, world))
if (!type.canProcess(transported.stack, world))
transported.processingTime = -1;
return ignore;
}
@ -201,29 +160,29 @@ public class InWorldProcessing {
return null;
}
if (type == Type.HAUNTING) {
SOUL_SMOKING_WRAPPER.setItem(0, stack);
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(SOUL_SMOKING_WRAPPER, world);
HAUNTING_WRAPPER.setItem(0, stack);
Optional<HauntingRecipe> recipe = AllRecipeTypes.HAUNTING.find(HAUNTING_WRAPPER, world);
if (recipe.isPresent())
return applyRecipeOn(stack, recipe.get());
return null;
}
WRAPPER.setItem(0, stack);
RECIPE_WRAPPER.setItem(0, stack);
Optional<SmokingRecipe> smokingRecipe = world.getRecipeManager()
.getRecipeFor(RecipeType.SMOKING, WRAPPER, world);
.getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, world);
if (type == Type.BLASTING) {
if (!smokingRecipe.isPresent()) {
WRAPPER.setItem(0, stack);
RECIPE_WRAPPER.setItem(0, stack);
Optional<SmeltingRecipe> smeltingRecipe = world.getRecipeManager()
.getRecipeFor(RecipeType.SMELTING, WRAPPER, world);
.getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, world);
if (smeltingRecipe.isPresent())
return applyRecipeOn(stack, smeltingRecipe.get());
WRAPPER.setItem(0, stack);
RECIPE_WRAPPER.setItem(0, stack);
Optional<BlastingRecipe> blastingRecipe = world.getRecipeManager()
.getRecipeFor(RecipeType.BLASTING, WRAPPER, world);
.getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, world);
if (blastingRecipe.isPresent())
return applyRecipeOn(stack, blastingRecipe.get());
@ -313,37 +272,220 @@ public class InWorldProcessing {
return stacks;
}
public static void spawnParticlesForProcessing(@Nullable Level world, Vec3 vec, Type type) {
if (world == null || !world.isClientSide)
public enum Type {
SPLASHING {
@Override
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
if (level.random.nextInt(8) != 0)
return;
if (world.random.nextInt(8) != 0)
Vector3f color = new Color(0x0055FF).asVectorF();
level.addParticle(new DustParticleOptions(color, 1), pos.x + (level.random.nextFloat() - .5f) * .5f,
pos.y + .5f, pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
level.addParticle(ParticleTypes.SPIT, pos.x + (level.random.nextFloat() - .5f) * .5f, pos.y + .5f,
pos.z + (level.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
}
@Override
public void affectEntity(Entity entity, Level level) {
if (level.isClientSide)
return;
switch (type) {
case BLASTING:
world.addParticle(ParticleTypes.LARGE_SMOKE, vec.x, vec.y + .25f, vec.z, 0, 1 / 16f, 0);
break;
case SMOKING:
world.addParticle(ParticleTypes.POOF, vec.x, vec.y + .25f, vec.z, 0, 1 / 16f, 0);
break;
case HAUNTING:
vec = vec.add(VecHelper.offsetRandomly(Vec3.ZERO, world.random, 1)
if (entity instanceof EnderMan || entity.getType() == EntityType.SNOW_GOLEM
|| entity.getType() == EntityType.BLAZE) {
entity.hurt(DamageSource.DROWN, 2);
}
if (entity.isOnFire()) {
entity.clearFire();
level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE, SoundSource.NEUTRAL,
0.7F, 1.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.4F);
}
}
@Override
public boolean canProcess(ItemStack stack, Level level) {
return isWashable(stack, level);
}
},
SMOKING {
@Override
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
if (level.random.nextInt(8) != 0)
return;
level.addParticle(ParticleTypes.POOF, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0);
}
@Override
public void affectEntity(Entity entity, Level level) {
if (level.isClientSide)
return;
if (!entity.fireImmune()) {
entity.setSecondsOnFire(2);
entity.hurt(FIRE_DAMAGE_SOURCE, 2);
}
}
@Override
public boolean canProcess(ItemStack stack, Level level) {
RECIPE_WRAPPER.setItem(0, stack);
Optional<SmokingRecipe> recipe = level.getRecipeManager()
.getRecipeFor(RecipeType.SMOKING, RECIPE_WRAPPER, level);
return recipe.isPresent();
}
},
HAUNTING {
@Override
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
if (level.random.nextInt(8) != 0)
return;
pos = pos.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1)
.multiply(1, 0.05f, 1)
.normalize()
.scale(0.15f));
world.addParticle(ParticleTypes.SOUL_FIRE_FLAME, vec.x, vec.y + .45f, vec.z, 0, 0, 0);
if (world.random.nextInt(2) == 0)
world.addParticle(ParticleTypes.SMOKE, vec.x, vec.y + .25f, vec.z, 0, 0, 0);
break;
case SPLASHING:
Vector3f color = new Color(0x0055FF).asVectorF();
world.addParticle(new DustParticleOptions(color, 1), vec.x + (world.random.nextFloat() - .5f) * .5f,
vec.y + .5f, vec.z + (world.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
world.addParticle(ParticleTypes.SPIT, vec.x + (world.random.nextFloat() - .5f) * .5f, vec.y + .5f,
vec.z + (world.random.nextFloat() - .5f) * .5f, 0, 1 / 8f, 0);
break;
default:
break;
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, pos.x, pos.y + .45f, pos.z, 0, 0, 0);
if (level.random.nextInt(2) == 0)
level.addParticle(ParticleTypes.SMOKE, pos.x, pos.y + .25f, pos.z, 0, 0, 0);
}
@Override
public void affectEntity(Entity entity, Level level) {
if (level.isClientSide) {
if (entity instanceof Horse) {
Vec3 p = entity.getPosition(0);
Vec3 v = p.add(0, 0.5f, 0)
.add(VecHelper.offsetRandomly(Vec3.ZERO, level.random, 1)
.multiply(1, 0.2f, 1)
.normalize()
.scale(1f));
level.addParticle(ParticleTypes.SOUL_FIRE_FLAME, v.x, v.y, v.z, 0, 0.1f, 0);
if (level.random.nextInt(3) == 0)
level.addParticle(ParticleTypes.LARGE_SMOKE, p.x, p.y + .5f, p.z,
(level.random.nextFloat() - .5f) * .5f, 0.1f, (level.random.nextFloat() - .5f) * .5f);
}
return;
}
if (entity instanceof LivingEntity livingEntity) {
livingEntity.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 30, 0, false, false));
livingEntity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1, false, false));
}
if (entity instanceof Horse horse) {
int progress = horse.getPersistentData()
.getInt("CreateHaunting");
if (progress < 100) {
if (progress % 10 == 0) {
level.playSound(null, entity.blockPosition(), SoundEvents.SOUL_ESCAPE, SoundSource.NEUTRAL,
1f, 1.5f * progress / 100f);
}
horse.getPersistentData()
.putInt("CreateHaunting", progress + 1);
return;
}
level.playSound(null, entity.blockPosition(), SoundEvents.GENERIC_EXTINGUISH_FIRE,
SoundSource.NEUTRAL, 1.25f, 0.65f);
SkeletonHorse skeletonHorse = EntityType.SKELETON_HORSE.create(level);
CompoundTag serializeNBT = horse.saveWithoutId(new CompoundTag());
serializeNBT.remove("UUID");
if (!horse.getArmor()
.isEmpty())
horse.spawnAtLocation(horse.getArmor());
skeletonHorse.deserializeNBT(serializeNBT);
skeletonHorse.setPos(horse.getPosition(0));
level.addFreshEntity(skeletonHorse);
horse.discard();
}
}
@Override
public boolean canProcess(ItemStack stack, Level level) {
return isHauntable(stack, level);
}
},
BLASTING {
@Override
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
if (level.random.nextInt(8) != 0)
return;
level.addParticle(ParticleTypes.LARGE_SMOKE, pos.x, pos.y + .25f, pos.z, 0, 1 / 16f, 0);
}
@Override
public void affectEntity(Entity entity, Level level) {
if (level.isClientSide)
return;
if (!entity.fireImmune()) {
entity.setSecondsOnFire(10);
entity.hurt(LAVA_DAMAGE_SOURCE, 4);
}
}
@Override
public boolean canProcess(ItemStack stack, Level level) {
RECIPE_WRAPPER.setItem(0, stack);
Optional<SmeltingRecipe> smeltingRecipe = level.getRecipeManager()
.getRecipeFor(RecipeType.SMELTING, RECIPE_WRAPPER, level);
if (smeltingRecipe.isPresent())
return true;
RECIPE_WRAPPER.setItem(0, stack);
Optional<BlastingRecipe> blastingRecipe = level.getRecipeManager()
.getRecipeFor(RecipeType.BLASTING, RECIPE_WRAPPER, level);
if (blastingRecipe.isPresent())
return true;
return !stack.getItem()
.isFireResistant();
}
},
NONE {
@Override
public void spawnParticlesForProcessing(Level level, Vec3 pos) {
}
@Override
public void affectEntity(Entity entity, Level level) {
}
@Override
public boolean canProcess(ItemStack stack, Level level) {
return false;
}
};
public abstract boolean canProcess(ItemStack stack, Level level);
public abstract void spawnParticlesForProcessing(Level level, Vec3 pos);
public abstract void affectEntity(Entity entity, Level level);
public static Type byBlock(BlockGetter reader, BlockPos pos) {
FluidState fluidState = reader.getFluidState(pos);
if (fluidState.getType() == Fluids.WATER || fluidState.getType() == Fluids.FLOWING_WATER)
return Type.SPLASHING;
BlockState blockState = reader.getBlockState(pos);
Block block = blockState.getBlock();
if (block == Blocks.SOUL_FIRE
|| block == Blocks.SOUL_CAMPFIRE && blockState.getOptionalValue(CampfireBlock.LIT)
.orElse(false)
|| AllBlocks.LIT_BLAZE_BURNER.has(blockState) && blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE)
.map(flame -> flame == LitBlazeBurnerBlock.FlameType.SOUL).orElse(false))
return Type.HAUNTING;
if (block == Blocks.FIRE
|| BlockTags.CAMPFIRES.contains(block) && blockState.getOptionalValue(CampfireBlock.LIT)
.orElse(false)
|| AllBlocks.LIT_BLAZE_BURNER.has(blockState) && blockState.getOptionalValue(LitBlazeBurnerBlock.FLAME_TYPE)
.map(flame -> flame == LitBlazeBurnerBlock.FlameType.REGULAR).orElse(false)
|| getHeatLevelOf(blockState) == BlazeBurnerBlock.HeatLevel.SMOULDERING)
return Type.SMOKING;
if (block == Blocks.LAVA || getHeatLevelOf(blockState).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING))
return Type.BLASTING;
return Type.NONE;
}
}

View file

@ -4,6 +4,7 @@ import java.util.Random;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.foundation.utility.Lang;
@ -17,6 +18,7 @@ import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ShovelItem;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
@ -30,9 +32,12 @@ import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.ToolAction;
public class LitBlazeBurnerBlock extends Block implements IWrenchable {
public static final ToolAction EXTINGUISH_FLAME_ACTION = ToolAction.get(Create.asResource("extinguish_flame").toString());
public static final EnumProperty<FlameType> FLAME_TYPE = EnumProperty.create("flame_type", FlameType.class);
public LitBlazeBurnerBlock(Properties properties) {
@ -51,6 +56,15 @@ public class LitBlazeBurnerBlock extends Block implements IWrenchable {
BlockHitResult blockRayTraceResult) {
ItemStack heldItem = player.getItemInHand(hand);
if (heldItem.getItem() instanceof ShovelItem || heldItem.getItem().canPerformAction(heldItem, EXTINGUISH_FLAME_ACTION)) {
world.playSound(player, pos, SoundEvents.GENERIC_EXTINGUISH_FIRE, SoundSource.BLOCKS, 0.5f, 2);
if (world.isClientSide)
return InteractionResult.SUCCESS;
heldItem.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(hand));
world.setBlockAndUpdate(pos, AllBlocks.BLAZE_BURNER.getDefaultState());
return InteractionResult.SUCCESS;
}
if (state.getValue(FLAME_TYPE) == FlameType.REGULAR) {
if (heldItem.is(ItemTags.SOUL_FIRE_BASE_BLOCKS)) {
world.playSound(player, pos, SoundEvents.SOUL_SAND_PLACE, SoundSource.BLOCKS, 1.0f, world.random.nextFloat() * 0.4F + 0.8F);

View file

@ -139,6 +139,7 @@ public interface ItemAttribute {
EQUIPABLE(s -> s.getEquipmentSlot() != null),
FURNACE_FUEL(AbstractFurnaceBlockEntity::isFuel),
WASHABLE(InWorldProcessing::isWashable),
HAUNTABLE(InWorldProcessing::isHauntable),
CRUSHABLE((s, w) -> testRecipe(s, w, AllRecipeTypes.CRUSHING.getType())
|| testRecipe(s, w, AllRecipeTypes.MILLING.getType())),
SMELTABLE((s, w) -> testRecipe(s, w, RecipeType.SMELTING)),

View file

@ -392,6 +392,8 @@
"create.item_attributes.furnace_fuel.inverted": "is not furnace fuel",
"create.item_attributes.washable": "can be Washed",
"create.item_attributes.washable.inverted": "cannot be Washed",
"create.item_attributes.hauntable": "can be Haunted",
"create.item_attributes.hauntable.inverted": "cannot be Haunted",
"create.item_attributes.crushable": "can be Crushed",
"create.item_attributes.crushable.inverted": "cannot be Crushed",
"create.item_attributes.smeltable": "can be Smelted",