Redo a lot of redstone/glowstone logic

This commit is contained in:
quat1024 2023-07-03 03:35:07 -04:00
parent 97de0d1b9c
commit 720e98c30b
4 changed files with 105 additions and 112 deletions

View File

@ -32,12 +32,12 @@ public class SlopeBlock extends TemplateBlock {
super(TemplateBlock.configureSettings(Settings.create()) super(TemplateBlock.configureSettings(Settings.create())
.sounds(BlockSoundGroup.WOOD) .sounds(BlockSoundGroup.WOOD)
.hardness(0.2f)); //TODO: Material.WOOD .hardness(0.2f)); //TODO: Material.WOOD
this.setDefaultState(this.getStateManager().getDefaultState().with(FACING, Direction.NORTH).with(LIGHT, 0).with(REDSTONE, false)); setDefaultState(getDefaultState().with(FACING, Direction.NORTH));
} }
@Override @Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) { protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
builder.add(FACING, LIGHT, REDSTONE); super.appendProperties(builder.add(FACING));
} }
@Override @Override

View File

@ -1,23 +1,25 @@
package io.github.cottonmc.templates.block; package io.github.cottonmc.templates.block;
import io.github.cottonmc.templates.Templates;
import io.github.cottonmc.templates.block.entity.TemplateEntity; import io.github.cottonmc.templates.block.entity.TemplateEntity;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemPlacementContext; import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUsageContext; import net.minecraft.item.ItemUsageContext;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty; import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.IntProperty; import net.minecraft.state.property.IntProperty;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
import net.minecraft.util.ItemScatterer;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@ -30,6 +32,8 @@ public abstract class TemplateBlock extends Block implements BlockEntityProvider
public TemplateBlock(Settings settings) { public TemplateBlock(Settings settings) {
super(settings); super(settings);
setDefaultState(getDefaultState().with(LIGHT, 0).with(REDSTONE, false));
} }
public static Settings configureSettings(Settings s) { public static Settings configureSettings(Settings s) {
@ -38,69 +42,75 @@ public abstract class TemplateBlock extends Block implements BlockEntityProvider
.nonOpaque(); .nonOpaque();
} }
@Override
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
super.appendProperties(builder.add(LIGHT, REDSTONE));
}
@Override @Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if(world.isClient || !(world.getBlockEntity(pos) instanceof TemplateEntity be)) return ActionResult.SUCCESS; if(!state.isOf(this) || !(world.getBlockEntity(pos) instanceof TemplateEntity be)) return ActionResult.PASS; //shouldn't happen
if(!player.canModifyBlocks() || !world.canPlayerModifyAt(player, pos)) return ActionResult.PASS;
ItemStack stack = player.getStackInHand(hand); ItemStack held = player.getStackInHand(hand);
if(stack.getItem() instanceof BlockItem) {
Block block = ((BlockItem) stack.getItem()).getBlock(); //Glowstone
if(block == Blocks.REDSTONE_TORCH) { if(held.getItem() == Items.GLOWSTONE_DUST && state.get(LIGHT) != 15 && !be.hasSpentGlowstoneDust()) {
be.setRedstone(true); world.setBlockState(pos, state.with(LIGHT, 15));
if(!player.isCreative()) stack.decrement(1); be.spentGlowstoneDust();
}
if(!player.isCreative()) held.decrement(1);
world.playSound(player, pos, SoundEvents.BLOCK_GLASS_HIT, SoundCategory.BLOCKS, 1f, 1f);
return ActionResult.SUCCESS;
}
//Redstone
if(held.getItem() == Blocks.REDSTONE_TORCH.asItem() && !state.get(REDSTONE) && !be.hasSpentRedstoneTorch()) {
world.setBlockState(pos, state.with(REDSTONE, true));
be.spentRedstoneTorch();
if(!player.isCreative()) held.decrement(1);
world.playSound(player, pos, SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.BLOCKS, 1f, 1f);
return ActionResult.SUCCESS;
}
//Changing the theme
if(held.getItem() instanceof BlockItem bi && be.getRenderedState().getBlock() == Blocks.AIR) {
Block block = bi.getBlock();
ItemPlacementContext ctx = new ItemPlacementContext(new ItemUsageContext(player, hand, hit)); ItemPlacementContext ctx = new ItemPlacementContext(new ItemUsageContext(player, hand, hit));
BlockState placementState = block.getPlacementState(ctx); BlockState placementState = block.getPlacementState(ctx);
if(placementState != null && if(placementState != null && Block.isShapeFullCube(placementState.getCollisionShape(world, pos)) && !(block instanceof BlockEntityProvider)) {
Block.isShapeFullCube(placementState.getCollisionShape(world, pos)) && if(!world.isClient) be.setRenderedState(placementState);
!(block instanceof BlockEntityProvider) &&
be.getRenderedState().getBlock() == Blocks.AIR) //Even if the block does not glow, this'll do a block update when adding a redstoney block
{ int newLuminance = be.hasSpentGlowstoneDust() ? 15 : placementState.getLuminance();
be.setRenderedState(placementState); world.setBlockState(pos, state.with(LIGHT, newLuminance));
if(!player.isCreative()) stack.decrement(1);
if(!player.isCreative()) held.decrement(1);
world.playSound(player, pos, state.getSoundGroup().getPlaceSound(), SoundCategory.BLOCKS, 1f, 1f);
return ActionResult.SUCCESS;
} }
} else if(stack.getItem() == Items.GLOWSTONE_DUST) {
be.setGlowstone(true);
if(!player.isCreative()) stack.decrement(1);
} }
return ActionResult.SUCCESS;
return ActionResult.PASS;
} }
@Override @Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
if(newState.getBlock() == Templates.SLOPE) return; if(!state.isOf(newState.getBlock()) && world.getBlockEntity(pos) instanceof TemplateEntity template) {
BlockEntity be = world.getBlockEntity(pos); DefaultedList<ItemStack> drops = DefaultedList.of();
if(be instanceof TemplateEntity) {
TemplateEntity template = (TemplateEntity) be; Block theme = template.getRenderedState().getBlock();
if(template.getRenderedState().getBlock() != Blocks.AIR) { if(theme != Blocks.AIR) drops.add(new ItemStack(theme));
ItemStack stack = new ItemStack(template.getRenderedState().getBlock()); if(template.hasSpentRedstoneTorch()) drops.add(new ItemStack(Items.REDSTONE_TORCH));
ItemEntity entity = new ItemEntity(world, pos.getX(), pos.getY(), pos.getZ(), stack); if(template.hasSpentGlowstoneDust()) drops.add(new ItemStack(Items.GLOWSTONE_DUST));
world.spawnEntity(entity);
} ItemScatterer.spawn(world, pos, drops);
if(template.hasRedstone()) {
ItemStack stack = new ItemStack(Items.REDSTONE_TORCH);
ItemEntity entity = new ItemEntity(world, pos.getX(), pos.getY(), pos.getZ(), stack);
world.spawnEntity(entity);
}
if(template.hasGlowstone()) {
ItemStack stack = new ItemStack(Items.GLOWSTONE_DUST);
ItemEntity entity = new ItemEntity(world, pos.getX(), pos.getY(), pos.getZ(), stack);
world.spawnEntity(entity);
}
} }
super.onStateReplaced(state, world, pos, newState, moved); super.onStateReplaced(state, world, pos, newState, moved);
} }
@Override
public void neighborUpdate(BlockState state, World world, BlockPos pos, Block block, BlockPos posFrom, boolean bool) {
BlockEntity be = world.getBlockEntity(pos);
if(be instanceof TemplateEntity) {
TemplateEntity template = (TemplateEntity) be;
BlockState beState = template.getRenderedState();
world.setBlockState(pos, state.with(LIGHT, template.hasGlowstone() ? 15 : beState.getLuminance()).with(REDSTONE, template.hasRedstone() || beState.emitsRedstonePower()));
}
}
@Override @Override
public boolean emitsRedstonePower(BlockState state) { public boolean emitsRedstonePower(BlockState state) {
return state.get(REDSTONE); return state.get(REDSTONE);
@ -108,30 +118,18 @@ public abstract class TemplateBlock extends Block implements BlockEntityProvider
@Override @Override
public int getWeakRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) { public int getWeakRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) {
BlockEntity be = view.getBlockEntity(pos); if(state.get(REDSTONE)) return 15;
if(be instanceof TemplateEntity) { else if(view.getBlockEntity(pos) instanceof TemplateEntity template) return template.getRenderedState().getWeakRedstonePower(view, pos, dir);
TemplateEntity template = (TemplateEntity) be; else return 0;
if(template.hasRedstone()) return 15;
BlockState beState = template.getRenderedState();
return beState.getWeakRedstonePower(view, pos, dir);
}
return 0;
} }
@Override @Override
public int getStrongRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) { public int getStrongRedstonePower(BlockState state, BlockView view, BlockPos pos, Direction dir) {
BlockEntity be = view.getBlockEntity(pos); if(state.get(REDSTONE)) return 15;
if(be instanceof TemplateEntity) { else if(view.getBlockEntity(pos) instanceof TemplateEntity template) return template.getRenderedState().getStrongRedstonePower(view, pos, dir);
TemplateEntity template = (TemplateEntity) be; else return 0;
if(template.hasRedstone()) return 15;
BlockState beState = template.getRenderedState();
return beState.getStrongRedstonePower(view, pos, dir);
}
return 0;
} }
//TODO: pass to Block.Settings
// "Cannot reference 'TemplateBlock.luminance' before supertype constructor has been called"
public int luminance(BlockState state) { public int luminance(BlockState state) {
return state.get(LIGHT); return state.get(LIGHT);
} }

View File

@ -20,8 +20,14 @@ import java.util.Objects;
public class TemplateEntity extends BlockEntity implements RenderAttachmentBlockEntity { public class TemplateEntity extends BlockEntity implements RenderAttachmentBlockEntity {
protected BlockState renderedState = Blocks.AIR.getDefaultState(); protected BlockState renderedState = Blocks.AIR.getDefaultState();
protected boolean glowstone = false;
protected boolean redstone = false; //Whether the player has manually spent a redstone/glowstone item to upgrade the template.
//It's possible to get templates that, e.g. glow, without manually spending a glowstone on them
//(put a froglight in a template!) Same for redstone activation. We need to separately store
//whether a redstone/glowstone should be refunded when the player breaks the template, and wasting a
//blockstate for it is a little silly, so, here you go.
protected boolean spentGlowstoneDust = false;
protected boolean spentRedstoneTorch = false;
public TemplateEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { public TemplateEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state); super(type, pos, state);
@ -34,10 +40,10 @@ public class TemplateEntity extends BlockEntity implements RenderAttachmentBlock
BlockState lastRenderedState = renderedState; BlockState lastRenderedState = renderedState;
renderedState = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), tag.getCompound("BlockState")); renderedState = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), tag.getCompound("BlockState"));
glowstone = tag.getBoolean("Glowstone"); spentGlowstoneDust = tag.getBoolean("Glowstone");
redstone = tag.getBoolean("Redstone"); spentRedstoneTorch = tag.getBoolean("Redstone");
//Force a chunk remesh on the client, if the displayed blockstate has changed //Force a chunk remesh on the client if the displayed blockstate has changed
if(world != null && world.isClient && !Objects.equals(lastRenderedState, renderedState)) { if(world != null && world.isClient && !Objects.equals(lastRenderedState, renderedState)) {
Templates.chunkRerenderProxy.accept(world, pos); Templates.chunkRerenderProxy.accept(world, pos);
} }
@ -47,8 +53,8 @@ public class TemplateEntity extends BlockEntity implements RenderAttachmentBlock
public void writeNbt(NbtCompound tag) { public void writeNbt(NbtCompound tag) {
super.writeNbt(tag); super.writeNbt(tag);
tag.put("BlockState", NbtHelper.fromBlockState(renderedState)); tag.put("BlockState", NbtHelper.fromBlockState(renderedState));
tag.putBoolean("Glowstone", glowstone); tag.putBoolean("Glowstone", spentGlowstoneDust);
tag.putBoolean("Redstone", redstone); tag.putBoolean("Redstone", spentRedstoneTorch);
} }
@Nullable @Nullable
@ -59,6 +65,7 @@ public class TemplateEntity extends BlockEntity implements RenderAttachmentBlock
@Override @Override
public NbtCompound toInitialChunkDataNbt() { public NbtCompound toInitialChunkDataNbt() {
//TERRIBLE yarn name, this is "getUpdateTag", it's the nbt that will be sent to clients
return createNbt(); return createNbt();
} }
@ -67,41 +74,33 @@ public class TemplateEntity extends BlockEntity implements RenderAttachmentBlock
return renderedState; return renderedState;
} }
public void change() {
markDirty();
if(world instanceof ServerWorld sworld) sworld.getChunkManager().markForUpdate(pos); //dispatch to clients
}
public BlockState getRenderedState() { public BlockState getRenderedState() {
return renderedState; return renderedState;
} }
public void setRenderedState(BlockState newState) { public void setRenderedState(BlockState newState) {
BlockState lastState = renderedState; if(!Objects.equals(renderedState, newState)) {
renderedState = newState; renderedState = newState;
if(!Objects.equals(lastState, newState)) change(); markDirty();
} if(world instanceof ServerWorld sworld) sworld.getChunkManager().markForUpdate(pos); //dispatch to clients
public boolean hasGlowstone() {
return glowstone;
}
public void setGlowstone(boolean newGlowstone) {
boolean lastGlowstone = glowstone;
glowstone = newGlowstone;
if(lastGlowstone != newGlowstone) change();
}
public boolean hasRedstone() {
return redstone;
}
public void setRedstone(boolean newRedstone) {
boolean lastRedstone = redstone;
redstone = newRedstone;
if(lastRedstone != newRedstone) {
world.updateNeighbors(pos, getCachedState().getBlock());
change();
} }
} }
public boolean hasSpentGlowstoneDust() {
return spentGlowstoneDust;
}
public void spentGlowstoneDust() {
spentGlowstoneDust = true;
markDirty();
}
public boolean hasSpentRedstoneTorch() {
return spentRedstoneTorch;
}
public void spentRedstoneTorch() {
spentRedstoneTorch = true;
markDirty();
}
} }

View File

@ -5,14 +5,10 @@ import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Objects;
public interface TemplateAppearance { public interface TemplateAppearance {
@NotNull Sprite getParticleSprite(); //TODO: plug this in @NotNull Sprite getParticleSprite(); //TODO: plug this in
@NotNull RenderMaterial getRenderMaterial(); @NotNull RenderMaterial getRenderMaterial();
@NotNull Sprite getSprite(Direction dir); @NotNull Sprite getSprite(Direction dir);
boolean hasColor(Direction dir); boolean hasColor(Direction dir);
} }