Skip to content

Commit

Permalink
Multiblocks function!!!!!
Browse files Browse the repository at this point in the history
  • Loading branch information
vertexcubed committed Sep 15, 2024
1 parent 48cf025 commit 19a1a9f
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public AdInfinitum() {
modEventBus.addListener(BlockRegistry::registerBlockItems);

StateMatcherRegistry.register(modEventBus);
MultiblockDataRegistry.register(modEventBus);
TabRegistry.register(modEventBus);
MenuRegistry.register(modEventBus);
SatelliteRegistry.register(modEventBus);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,4 @@ public HoloDoorBlock(Properties properties) {
public BlockEntityType<?> entity(BlockState state) {
return BlockRegistry.HOLO_DOOR_BLOCK_ENTITY.get();
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
package com.vertexcubed.ad_infinitum.common.block;

import com.vertexcubed.ad_infinitum.AdInfinitum;
import com.vertexcubed.ad_infinitum.common.blockentity.SatelliteLauncherBlockEntity;
import com.vertexcubed.ad_infinitum.common.registry.BlockRegistry;
import earth.terrarium.adastra.common.blocks.base.MachineBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;

public class SatelliteLauncherBlock extends MachineBlock {
public SatelliteLauncherBlock(Properties properties) {
Expand All @@ -14,4 +22,15 @@ public SatelliteLauncherBlock(Properties properties) {
public BlockEntityType<?> entity(BlockState state) {
return BlockRegistry.SATELLITE_LAUNCHER_BLOCK_ENTITY.get();
}

@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
AdInfinitum.LOGGER.info("Using!");
if(level.getBlockEntity(pos) instanceof SatelliteLauncherBlockEntity be) {
InteractionResult beResult = be.use(state,level,pos,player,hand,hit);
}


return super.use(state, level, pos, player, hand, hit);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,35 @@

import com.vertexcubed.ad_infinitum.AdInfinitum;
import com.vertexcubed.ad_infinitum.common.multiblock.Multiblock;
import com.vertexcubed.ad_infinitum.common.registry.BlockRegistry;
import com.vertexcubed.ad_infinitum.common.util.ModEnergyStorage;
import com.vertexcubed.ad_infinitum.common.multiblock.data.GenericMachineData;
import com.vertexcubed.ad_infinitum.common.util.InternalOnlyEnergyContainer;
import earth.terrarium.adastra.common.blockentities.base.EnergyContainerMachineBlockEntity;
import earth.terrarium.adastra.common.blockentities.base.sideconfig.ConfigurationEntry;
import earth.terrarium.botarium.common.energy.impl.InsertOnlyEnergyContainer;
import earth.terrarium.botarium.common.energy.impl.WrappedBlockEnergyContainer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.MenuProvider;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.event.level.BlockEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

Expand All @@ -38,11 +39,14 @@
public class SatelliteLauncherBlockEntity extends EnergyContainerMachineBlockEntity {

public static final ResourceLocation MULTIBLOCK_ID = modLoc("satellite_launcher");

public static final int MAX_TRANSFER = 20000;


private Multiblock multiblock;

private boolean isFormed = false;
private final List<BlockPos> energyInputs = new ArrayList<>();

public SatelliteLauncherBlockEntity(BlockPos pos, BlockState state) {
super(pos, state, 5);

Expand All @@ -53,12 +57,39 @@ public void firstTick(Level level, BlockPos pos, BlockState state) {
super.firstTick(level, pos, state);
Optional<Registry<Multiblock>> multiblockRegistry = level.registryAccess().registry(Multiblock.REGISTRY);
if(multiblockRegistry.isEmpty()) {
AdInfinitum.LOGGER.info("Multiblock registry is not present!");
AdInfinitum.LOGGER.error("Multiblock registry is not present!");
return;
}
multiblock = multiblockRegistry.get().get(MULTIBLOCK_ID);
MinecraftForge.EVENT_BUS.register(this);

if(isFormed) {
checkForMultiblock(level, pos);
}
}

@Override
public void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos) {
super.serverTick(level, time, state, pos);
if(!isFormed) return;
energyInputs.forEach(relativePos -> {
BlockPos energyInput = relativePos.offset(pos);
BlockEntity blockEntity = level.getBlockEntity(energyInput);
if(blockEntity != null) {
//todo: get rid of Direction.UP
blockEntity.getCapability(ForgeCapabilities.ENERGY, Direction.UP).ifPresent(energy -> {

long extracted = energy.extractEnergy(MAX_TRANSFER, true);
if(extracted == 0) return;
int inserted = (int) getEnergyStorage().internalInsert(extracted, true);
if(inserted == 0) return;
getEnergyStorage().internalInsert(energy.extractEnergy(inserted, false), false);
});
}

});


AdInfinitum.LOGGER.info(multiblock == null ? "multiblock is null!" : multiblock.toString());
}

@Override
Expand All @@ -70,7 +101,7 @@ public List<ConfigurationEntry> getDefaultConfig() {
public WrappedBlockEnergyContainer getEnergyStorage() {
if (this.energyContainer == null)
{
this.energyContainer = new WrappedBlockEnergyContainer(this, new WrappedBlockEnergyContainer(this, new InsertOnlyEnergyContainer(20000, 20000)));
this.energyContainer = new WrappedBlockEnergyContainer(this, new WrappedBlockEnergyContainer(this, new InternalOnlyEnergyContainer(200000, MAX_TRANSFER)));
}

return this.energyContainer;
Expand All @@ -85,4 +116,73 @@ public int[] getSlotsForFace(Direction pSide) {
public @Nullable AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) {
return null;
}

public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
if(multiblock == null) {
AdInfinitum.LOGGER.warn("Multiblock is null!");
return InteractionResult.FAIL;
}

if(!isFormed) {
checkForMultiblock(level, pos);
}
else {
AdInfinitum.LOGGER.info("Multiblock already formed!");
}


return InteractionResult.SUCCESS;
}

private void checkForMultiblock(Level level, BlockPos pos) {
Multiblock.TestResult result = multiblock.test(level, pos);
AdInfinitum.LOGGER.info("Multiblock found: " + result.found());

if(!result.found()) return;
isFormed = true;
setChanged();


if(multiblock.getData().isPresent() && multiblock.getData().get() instanceof GenericMachineData data) {
AdInfinitum.LOGGER.info("Data found!");
List<BlockPos> relative = data.getDataPositions(GenericMachineData.DataType.ENERGY_IN, result.rotation());
energyInputs.clear();
energyInputs.addAll(relative);
AdInfinitum.LOGGER.info("Positions: " + relative.toString());
}
}

@Override
protected void saveAdditional(@NotNull CompoundTag tag) {
super.saveAdditional(tag);
tag.putBoolean("isFormed", isFormed);
}

@Override
public void load(@NotNull CompoundTag tag) {
super.load(tag);
isFormed = tag.getBoolean("isFormed");
}

@SubscribeEvent
public void onBlockUpdate(BlockEvent.NeighborNotifyEvent event) {
if(!this.isFormed || multiblock == null) return;
BlockPos pos = event.getPos().subtract(this.worldPosition.subtract(multiblock.getCenter()));
if(multiblock.inBounds(pos)) {
Multiblock.TestResult result = multiblock.test(level, this.worldPosition);
if(!result.found()) {
BlockState oldState = event.getState();
isFormed = false;
setChanged();
Level level = ((Level) event.getLevel());
level.sendBlockUpdated(this.worldPosition, oldState, level.getBlockState(this.worldPosition), 3);
}
}
}

@Override
public void onRemoved() {
super.onRemoved();
MinecraftForge.EVENT_BUS.unregister(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import com.google.common.collect.ImmutableMap;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.vertexcubed.ad_infinitum.AdInfinitum;
Expand All @@ -10,14 +11,17 @@
import com.vertexcubed.ad_infinitum.common.multiblock.matcher.AnyMatcher;
import com.vertexcubed.ad_infinitum.common.multiblock.matcher.StateMatcher;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.core.Vec3i;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.vertexcubed.ad_infinitum.AdInfinitum.modLoc;

Expand All @@ -36,32 +40,33 @@ public class Multiblock {
public static final Codec<Multiblock> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.STRING.listOf().listOf().fieldOf("pattern").forGetter(multiblock -> multiblock._pattern),
Codec.unboundedMap(Codec.STRING, StateMatcher.CODEC).fieldOf("mappings").forGetter(multiblock -> multiblock._mappings),
MultiblockData.CODEC.fieldOf("data").forGetter(multiblock -> multiblock._data)
MultiblockData.CODEC.optionalFieldOf("data").forGetter(Multiblock::getData)
).apply(instance, Multiblock::new));


//for internal use and serialization
private final List<List<String>> _pattern;
private final Map<String, StateMatcher> _mappings;
private final MultiblockData _data;


private StateMatcher[][][] matchers;
private Vec3i center;
private final Vec3i size;
private final Optional<MultiblockData> data;


public Multiblock(List<List<String>> pattern, Map<String, StateMatcher> mappings, MultiblockData data) {
public Multiblock(List<List<String>> pattern, Map<String, StateMatcher> mappings, Optional<MultiblockData> data) {
this._pattern = pattern;
_mappings = new ImmutableMap.Builder<String, StateMatcher>()
//hardcoded keys. Can be overriden (hence buildKeepingLast instead of buildOrThrow)
.put(" ", new AirMatcher())
.put("_", new AnyMatcher())
.putAll(mappings)
.buildKeepingLast();
this._data = data;
this.data = data;
this.size = getPatternSize(pattern);
buildMultiBlock();
this.data.ifPresent(d -> d.init(this));
}

/**
Expand Down Expand Up @@ -90,10 +95,10 @@ private void buildMultiBlock() {

center = null;
matchers = new StateMatcher[size.getX()][size.getY()][size.getZ()];
for(int x = 0; x < size.getX(); x++) {
for(int y = 0; y < size.getY(); y++) {
for(int z = 0; z < size.getZ(); z++) {
String c = String.valueOf(_pattern.get(y).get(x).charAt(z));
for(int y = 0; y < size.getY(); y++) {
for(int z = 0; z < size.getZ(); z++) {
for(int x = 0; x < size.getX(); x++) {
String c = String.valueOf(_pattern.get(y).get(z).charAt(x));
if(!_mappings.containsKey(c)) {
throw new IllegalArgumentException("Key " + c + " not in mappings!");
}
Expand All @@ -103,27 +108,41 @@ private void buildMultiBlock() {
}

this.matchers[x][y][z] = _mappings.get(c);
if(this.data.isPresent()) {
this.data.get().setupData(x, y, z, c);
}
}
}
}
}

//x y z starting from 0,0,0 in multiblock space
public boolean test(Level level, BlockPos center, int x, int y, int z) {

if(x < 0 || y < 0 || z < 0 || x > size.getX() || y > size.getY() || z > size.getZ()) return false;
/**
* Returns the center in multiblock space.
*/
public Vec3i getCenter() {
return center;
}

BlockPos checkPos = center.subtract(this.center).offset(x, y, z);
BlockState blockState = level.getBlockState(checkPos);
public Optional<MultiblockData> getData() {
return data;
}

return matchers[x][y][z].getStatePredicate().test(level, checkPos, blockState);
//x y z starting from 0,0,0 in multiblock space
public TestResult test(Level level, BlockPos center) {
for(Rotation rotation : Rotation.values()) {
if(test(level, center, rotation)) return new TestResult(true, rotation);
}
return new TestResult(false, Rotation.NONE);
}

public boolean test(Level level, BlockPos center) {
for(int x = 0; x < size.getX(); x++) {
for(int y = 0; y < size.getY(); y++) {
for(int z = 0; z < size.getZ(); z++) {
if(!test(level, center, x, y, z)) {
public boolean test(Level level, BlockPos centerWorld, Rotation rotation) {
BlockPos offset = centerWorld.subtract(this.center);
for(int y = 0; y < size.getY(); y++) {
for(int z = 0; z < size.getZ(); z++) {
for(int x = 0; x < size.getX(); x++) {
BlockPos original = new BlockPos(x, y, z);
BlockPos rotated = original.subtract(this.center).rotate(rotation).offset(this.center);
if(!test(level, offset, rotated, original)) {
return false;
}
}
Expand All @@ -132,8 +151,29 @@ public boolean test(Level level, BlockPos center) {
return true;
}

public boolean test(Level level, BlockPos offset, BlockPos rotatedPos, BlockPos original) {

if(!inBounds(original)) return false;

BlockPos checkPos = rotatedPos.offset(offset);
BlockState blockState = level.getBlockState(checkPos);
return matchers[original.getX()][original.getY()][original.getZ()].getStatePredicate().test(level, checkPos, blockState);
}

public boolean inBounds(BlockPos pos) {
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
return !(x < 0 || y < 0 || z < 0 || x > size.getX() || y > size.getY() || z > size.getZ());
}


@Override
public String toString() {
return "Multiblock { Pattern: " + _pattern +", Mappings: " + _mappings + " }";
}



public record TestResult(Boolean found, Rotation rotation) {}
}
Loading

0 comments on commit 19a1a9f

Please sign in to comment.