Working in part placement
This commit is contained in:
@@ -30,6 +30,7 @@ import alexiil.mc.lib.attributes.AttributeProvider;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockEntityProvider;
|
||||
import net.minecraft.block.BlockState;
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.block.networking;
|
||||
|
||||
import appeng.api.parts.IFacadeContainer;
|
||||
import appeng.api.parts.IFacadePart;
|
||||
import appeng.api.parts.PartItemStack;
|
||||
import appeng.api.parts.SelectedPart;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.block.AEBaseTileBlock;
|
||||
import appeng.client.render.cablebus.CableBusBakedModel;
|
||||
import appeng.client.render.cablebus.CableBusBreakingParticle;
|
||||
import appeng.client.render.cablebus.CableBusRenderState;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.helpers.AEGlassMaterial;
|
||||
import appeng.integration.abstraction.IAEFacade;
|
||||
import appeng.parts.ICableBusContainer;
|
||||
import appeng.parts.NullCableBusContainer;
|
||||
import appeng.tile.networking.CableBusBlockEntity;
|
||||
import appeng.util.Platform;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.event.client.player.ClientPickBlockGatherCallback;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ShapeContext;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.DyeColor;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.hit.HitResult.Type;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.util.shape.VoxelShapes;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implements IAEFacade {
|
||||
|
||||
private static final ICableBusContainer NULL_CABLE_BUS = new NullCableBusContainer();
|
||||
|
||||
public CableBusBlock() {
|
||||
super(defaultProps(AEGlassMaterial.INSTANCE)
|
||||
.nonOpaque()
|
||||
.dropsNothing()
|
||||
.dynamicBounds());
|
||||
}
|
||||
|
||||
static {
|
||||
ClientPickBlockGatherCallback.EVENT.register((player, result) -> {
|
||||
if (result instanceof BlockHitResult) {
|
||||
BlockHitResult blockResult = (BlockHitResult) result;
|
||||
BlockState blockState = player.world.getBlockState(((BlockHitResult) result).getBlockPos());
|
||||
if (blockState.getBlock() instanceof CableBusBlock) {
|
||||
CableBusBlock cableBus = (CableBusBlock) blockState.getBlock();
|
||||
return cableBus.getPickBlock(blockState,
|
||||
result, player.world, blockResult.getBlockPos(), player);
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent(BlockState state, BlockView reader, BlockPos pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void randomDisplayTick(final BlockState state, final World worldIn, final BlockPos pos, final Random rand) {
|
||||
this.cb(worldIn, pos).randomDisplayTick(worldIn, pos, rand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeakRedstonePower(final BlockState state, final BlockView w, final BlockPos pos, final Direction side) {
|
||||
return this.cb(w, pos).isProvidingWeakPower(side.getOpposite()); // TODO:
|
||||
// IS
|
||||
// OPPOSITE!?
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean emitsRedstonePower(final BlockState state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollision(BlockState state, World w, BlockPos pos, Entity entityIn) {
|
||||
this.cb(w, pos).onEntityCollision(entityIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStrongRedstonePower(BlockState state, BlockView world, BlockPos pos, Direction direction) {
|
||||
return this.cb(world, pos).isProvidingStrongPower(direction.getOpposite()); // TODO:
|
||||
// IS
|
||||
// OPPOSITE!?
|
||||
}
|
||||
|
||||
// FIXME Dynamic light seems unsupported (?) Must maybe use blockstates... :|
|
||||
// FIXME FABRIC @Override
|
||||
// FIXME FABRIC public int getLightValue(final BlockState state, final BlockView world, final BlockPos pos) {
|
||||
// FIXME FABRIC if (state.getBlock() != this) {
|
||||
// FIXME FABRIC return state.getLuminance();
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC return this.cb(world, pos).getLightValue();
|
||||
// FIXME FABRIC }
|
||||
|
||||
|
||||
// FIXME: Must hook isClimbing ourselves
|
||||
// FIXME FABRIC @Override
|
||||
// FIXME FABRIC public boolean isLadder(BlockState state, WorldView world, BlockPos pos, LivingEntity entity) {
|
||||
// FIXME FABRIC return this.cb(world, pos).isLadder(entity);
|
||||
// FIXME FABRIC }
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canReplace(BlockState state, ItemPlacementContext context) {
|
||||
// FIXME: Potentially check the fluid one too
|
||||
return super.canReplace(state, context) && this.cb(context.getWorld(), context.getBlockPos()).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
// FIXME FABRIC Hook does not exist
|
||||
// FIXME FABRIC @Override
|
||||
// FIXME FABRIC public boolean removedByPlayer(BlockState state, World world, BlockPos pos, PlayerEntity player,
|
||||
// FIXME FABRIC boolean willHarvest, IFluidState fluid) {
|
||||
// FIXME FABRIC if (player.abilities.isCreativeMode) {
|
||||
// FIXME FABRIC final AEBaseBlockEntity tile = this.getBlockEntity(world, pos);
|
||||
// FIXME FABRIC if (tile != null) {
|
||||
// FIXME FABRIC tile.disableDrops();
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC // maybe ray trace?
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC return super.removedByPlayer(state, world, pos, player, willHarvest, fluid);
|
||||
// FIXME FABRIC }
|
||||
|
||||
// FIXME FABRIC @Override
|
||||
// FIXME FABRIC public boolean canConnectRedstone(final BlockState state, final BlockView w, final BlockPos pos,
|
||||
// FIXME FABRIC Direction side) {
|
||||
// FIXME FABRIC if (side == null) {
|
||||
// FIXME FABRIC side = Direction.UP;
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC return this.cb(w, pos).canConnectRedstone(EnumSet.of(side));
|
||||
// FIXME FABRIC }
|
||||
|
||||
public ItemStack getPickBlock(BlockState state, HitResult target, BlockView world, BlockPos pos,
|
||||
PlayerEntity player) {
|
||||
final Vec3d v3 = target.getPos().subtract(pos.getX(), pos.getY(), pos.getZ());
|
||||
final SelectedPart sp = this.cb(world, pos).selectPart(v3);
|
||||
|
||||
if (sp.part != null) {
|
||||
return sp.part.getItemStack(PartItemStack.PICK);
|
||||
} else if (sp.facade != null) {
|
||||
return sp.facade.getItemStack();
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
|
||||
// FIXME FABRIC MIXIN net.minecraft.client.particle.ParticleManager.addBlockBreakingParticles
|
||||
@Environment(EnvType.CLIENT)
|
||||
public boolean addHitEffects(final BlockState state, final World world, final HitResult target,
|
||||
final ParticleManager effectRenderer) {
|
||||
|
||||
// Half the particle rate. Since we're spawning concentrated on a specific spot,
|
||||
// our particle effect otherwise looks too strong
|
||||
if (Platform.getRandom().nextBoolean()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target.getType() != Type.BLOCK) {
|
||||
return false;
|
||||
}
|
||||
BlockPos blockPos = new BlockPos(target.getPos().x, target.getPos().y, target.getPos().z);
|
||||
|
||||
ICableBusContainer cb = this.cb(world, blockPos);
|
||||
|
||||
// Our built-in model has the actual baked sprites we need
|
||||
BakedModel model = MinecraftClient.getInstance().getBlockRenderManager()
|
||||
.getModel(this.getDefaultState());
|
||||
|
||||
// We cannot add the effect if we don't have the model
|
||||
if (!(model instanceof CableBusBakedModel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CableBusBakedModel cableBusModel = (CableBusBakedModel) model;
|
||||
|
||||
CableBusRenderState renderState = cb.getRenderState();
|
||||
|
||||
// Spawn a particle for one of the particle textures
|
||||
Sprite texture = Platform.pickRandom(cableBusModel.getParticleTextures(renderState));
|
||||
if (texture != null) {
|
||||
double x = target.getPos().x;
|
||||
double y = target.getPos().y;
|
||||
double z = target.getPos().z;
|
||||
// FIXME: Check how this looks, probably like shit, maybe provide parts the
|
||||
// ability to supply particle textures???
|
||||
effectRenderer
|
||||
.addParticle(new CableBusBreakingParticle((ClientWorld) world, x, y, z, texture).scale(0.8F));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME FABRIC: Mixin to net.minecraft.client.particle.ParticleManager.addBlockBreakParticles
|
||||
@Environment(EnvType.CLIENT)
|
||||
public boolean addDestroyEffects(BlockState state, World world, BlockPos pos, ParticleManager effectRenderer) {
|
||||
ICableBusContainer cb = this.cb(world, pos);
|
||||
|
||||
// Our built-in model has the actual baked sprites we need
|
||||
BakedModel model = MinecraftClient.getInstance().getBlockRenderManager()
|
||||
.getModel(this.getDefaultState());
|
||||
|
||||
// We cannot add the effect if we dont have the model
|
||||
if (!(model instanceof CableBusBakedModel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CableBusBakedModel cableBusModel = (CableBusBakedModel) model;
|
||||
|
||||
CableBusRenderState renderState = cb.getRenderState();
|
||||
|
||||
List<Sprite> textures = cableBusModel.getParticleTextures(renderState);
|
||||
|
||||
if (!textures.isEmpty()) {
|
||||
// Shamelessly inspired by ParticleManager.addBlockDestroyEffects
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
for (int l = 0; l < 4; ++l) {
|
||||
// Randomly select one of the textures if the cable bus has more than just one
|
||||
// possibility here
|
||||
final Sprite texture = Platform.pickRandom(textures);
|
||||
|
||||
final double x = pos.getX() + (j + 0.5D) / 4.0D;
|
||||
final double y = pos.getY() + (k + 0.5D) / 4.0D;
|
||||
final double z = pos.getZ() + (l + 0.5D) / 4.0D;
|
||||
|
||||
// FIXME: Check how this looks, probably like shit, maybe provide parts the
|
||||
// ability to supply particle textures???
|
||||
Particle effect = new CableBusBreakingParticle((ClientWorld) world, x, y, z, x - pos.getX() - 0.5D,
|
||||
y - pos.getY() - 0.5D, z - pos.getZ() - 0.5D, texture);
|
||||
effectRenderer.addParticle(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborUpdate(BlockState state, World world, BlockPos pos, Block blockIn, BlockPos fromPos,
|
||||
boolean isMoving) {
|
||||
if (Platform.isServer()) {
|
||||
this.cb(world, pos).onneighborUpdate(world, pos, fromPos);
|
||||
}
|
||||
}
|
||||
|
||||
private ICableBusContainer cb(final BlockView w, final BlockPos pos) {
|
||||
final BlockEntity te = w.getBlockEntity(pos);
|
||||
ICableBusContainer out = null;
|
||||
|
||||
if (te instanceof CableBusBlockEntity) {
|
||||
out = ((CableBusBlockEntity) te).getCableBus();
|
||||
}
|
||||
|
||||
return out == null ? NULL_CABLE_BUS : out;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private IFacadeContainer fc(final BlockView w, final BlockPos pos) {
|
||||
final BlockEntity te = w.getBlockEntity(pos);
|
||||
IFacadeContainer out = null;
|
||||
|
||||
if (te instanceof CableBusBlockEntity) {
|
||||
out = ((CableBusBlockEntity) te).getCableBus().getFacadeContainer();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Override
|
||||
public void onBlockBreakStart(BlockState state, World worldIn, BlockPos pos, PlayerEntity player) {
|
||||
if (worldIn.isClient()) {
|
||||
final HitResult rtr = AppEng.instance().getRTR();
|
||||
if (rtr instanceof BlockHitResult) {
|
||||
BlockHitResult brtr = (BlockHitResult) rtr;
|
||||
if (brtr.getBlockPos().equals(pos)) {
|
||||
final Vec3d hitVec = rtr.getPos().subtract(new Vec3d(pos.getX(), pos.getY(), pos.getZ()));
|
||||
|
||||
if (this.cb(worldIn, pos).clicked(player, Hand.MAIN_HAND, hitVec)) {
|
||||
throw new IllegalStateException();
|
||||
// FIXME FABRIC NetworkHandler.instance().sendToServer(new ClickPacket(pos, brtr.getSide(), (float) hitVec.x,
|
||||
// FIXME FABRIC (float) hitVec.y, (float) hitVec.z, Hand.MAIN_HAND, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onBlockClickPacket(World worldIn, BlockPos pos, PlayerEntity playerIn, Hand hand, Vec3d hitVec) {
|
||||
this.cb(worldIn, pos).clicked(playerIn, hand, hitVec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult onActivated(final World w, final BlockPos pos, final PlayerEntity player, final Hand hand,
|
||||
final @Nullable ItemStack heldItem, final BlockHitResult hit) {
|
||||
// Transform from world into block space
|
||||
Vec3d hitVec = hit.getPos();
|
||||
Vec3d hitInBlock = new Vec3d(hitVec.x - pos.getX(), hitVec.y - pos.getY(), hitVec.z - pos.getZ());
|
||||
return this.cb(w, pos).activate(player, hand, hitInBlock) ? ActionResult.SUCCESS : ActionResult.PASS;
|
||||
}
|
||||
|
||||
public boolean recolorBlock(final BlockView world, final BlockPos pos, final Direction side,
|
||||
final DyeColor color, final PlayerEntity who) {
|
||||
try {
|
||||
return this.cb(world, pos).recolourBlock(side, AEColor.values()[color.ordinal()], who);
|
||||
} catch (final Throwable ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getFacadeState(BlockView world, BlockPos pos, Direction side) {
|
||||
if (side != null) {
|
||||
IFacadeContainer container = this.fc(world, pos);
|
||||
if (container != null) {
|
||||
IFacadePart facade = container.getFacade(AEPartLocation.fromFacing(side));
|
||||
if (facade != null) {
|
||||
return facade.getBlockState();
|
||||
}
|
||||
}
|
||||
}
|
||||
return world.getBlockState(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getOutlineShape(BlockState state, BlockView w, BlockPos pos, ShapeContext context) {
|
||||
CableBusBlockEntity te = getBlockEntity(w, pos);
|
||||
if (te == null) {
|
||||
return VoxelShapes.empty();
|
||||
} else {
|
||||
return te.getCableBus().getOutlineShape();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getCollisionShape(BlockState state, BlockView w, BlockPos pos, ShapeContext context) {
|
||||
CableBusBlockEntity te = getBlockEntity(w, pos);
|
||||
if (te == null) {
|
||||
return VoxelShapes.empty();
|
||||
} else {
|
||||
Entity entity = null;
|
||||
// FIXME FABRIC: even EntityShapeContext doesn't give us the actual entity we're colliding with :|
|
||||
return te.getCableBus().getCollisionShape(entity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.block.networking;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.color.block.BlockColorProvider;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.parts.CableBusContainer;
|
||||
import appeng.tile.networking.CableBusBlockEntity;
|
||||
|
||||
/**
|
||||
* Exposes the cable bus color as tint indices 0 (dark variant), 1 (medium
|
||||
* variant) and 2 (bright variant).
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class CableBusColor implements BlockColorProvider {
|
||||
|
||||
@Override
|
||||
public int getColor(BlockState state, @Nullable BlockRenderView worldIn, @Nullable BlockPos pos, int color) {
|
||||
|
||||
AEColor busColor = AEColor.TRANSPARENT;
|
||||
|
||||
if (worldIn != null && pos != null) {
|
||||
BlockEntity tileEntity = worldIn.getBlockEntity(pos);
|
||||
if (tileEntity instanceof CableBusBlockEntity) {
|
||||
CableBusContainer container = ((CableBusBlockEntity) tileEntity).getCableBus();
|
||||
busColor = container.getColor();
|
||||
}
|
||||
}
|
||||
|
||||
return busColor.getVariantByTintIndex(color);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.block.networking;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import appeng.bootstrap.BlockRenderingCustomizer;
|
||||
import appeng.bootstrap.IBlockRendering;
|
||||
import appeng.bootstrap.IItemRendering;
|
||||
|
||||
/**
|
||||
* Customizes the rendering behavior for cable busses, which are the biggest
|
||||
* multipart of AE2.
|
||||
*/
|
||||
public class CableBusRendering extends BlockRenderingCustomizer {
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
// FIXME This is straight up impossible in Vanilla, and questionable if it's actually needed.
|
||||
// FIXME rendering.renderType(rt -> true);
|
||||
|
||||
rendering.blockColor(new CableBusColor());
|
||||
rendering.modelCustomizer((loc, model) -> model);
|
||||
}
|
||||
}
|
||||
@@ -4,17 +4,21 @@ import appeng.api.parts.CableRenderMode;
|
||||
import appeng.bootstrap.ModelsReloadCallback;
|
||||
import appeng.bootstrap.components.IItemColorRegistrationComponent;
|
||||
import appeng.bootstrap.components.IModelBakeComponent;
|
||||
import appeng.client.render.cablebus.CableBusModelLoader;
|
||||
import appeng.client.render.effects.*;
|
||||
import appeng.client.render.tesr.SkyChestTESR;
|
||||
import appeng.core.Api;
|
||||
import appeng.core.ApiDefinitions;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.AppEngBase;
|
||||
import appeng.core.features.registries.PartModels;
|
||||
import appeng.core.sync.network.ClientNetworkHandler;
|
||||
import appeng.entity.*;
|
||||
import appeng.hooks.ClientTickHandler;
|
||||
import appeng.util.Platform;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
|
||||
import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendereregistry.v1.EntityRendererRegistry;
|
||||
import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback;
|
||||
@@ -60,6 +64,7 @@ public final class AppEngClient extends AppEngBase {
|
||||
|
||||
ModelsReloadCallback.EVENT.register(this::onModelsReloaded);
|
||||
|
||||
registerModelProviders();
|
||||
registerParticleRenderers();
|
||||
registerEntityRenderers();
|
||||
registerItemColors();
|
||||
@@ -93,7 +98,7 @@ public final class AppEngClient extends AppEngBase {
|
||||
|
||||
@Override
|
||||
public HitResult getRTR() {
|
||||
return null;
|
||||
return client.crosshairTarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,7 +108,14 @@ public final class AppEngClient extends AppEngBase {
|
||||
|
||||
@Override
|
||||
public CableRenderMode getRenderMode() {
|
||||
return null;
|
||||
if (Platform.isServer()) {
|
||||
return super.getRenderMode();
|
||||
}
|
||||
|
||||
final MinecraftClient mc = MinecraftClient.getInstance();
|
||||
final PlayerEntity player = mc.player;
|
||||
|
||||
return this.renderModeForPlayer(player);
|
||||
}
|
||||
|
||||
public void triggerUpdates() {
|
||||
@@ -190,4 +202,31 @@ public final class AppEngClient extends AppEngBase {
|
||||
}
|
||||
}
|
||||
|
||||
private void registerModelProviders() {
|
||||
|
||||
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
|
||||
|
||||
// FIXME FABRIC addBuiltInModel("glass", GlassModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("sky_compass", SkyCompassModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("dummy_fluid_item", DummyFluidItemModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("memory_card", MemoryCardModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("biometric_card", BiometricCardModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("drive", DriveModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("color_applicator", ColorApplicatorModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("spatial_pylon", SpatialPylonModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
|
||||
// FIXME FABRIC addBuiltInModel("facade", FacadeItemModel::new);
|
||||
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "encoded_pattern"),
|
||||
// FIXME FABRIC EncodedPatternModelLoader.INSTANCE);
|
||||
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "part_plane"),
|
||||
// FIXME FABRIC PlaneModelLoader.INSTANCE);
|
||||
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "crafting_cube"),
|
||||
// FIXME FABRIC CraftingCubeModelLoader.INSTANCE);
|
||||
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE);
|
||||
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "cable_bus"),
|
||||
// FIXME FABRIC new CableBusModelLoader());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render;
|
||||
|
||||
import net.minecraft.client.color.item.ItemColorProvider;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.util.AEColor;
|
||||
|
||||
/**
|
||||
* Returns the shades of a single AE color for tint indices 0, 1, and 2.
|
||||
*/
|
||||
public class StaticItemColor implements ItemColorProvider {
|
||||
|
||||
private final AEColor color;
|
||||
|
||||
public StaticItemColor(AEColor color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColor(ItemStack stack, int tintIndex) {
|
||||
return this.color.getVariantByTintIndex(tintIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,727 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.core.AppEng;
|
||||
|
||||
/**
|
||||
* A helper class that builds quads for cable connections.
|
||||
*/
|
||||
class CableBuilder {
|
||||
|
||||
// Textures for the cable core types, one per type/color pair
|
||||
private final EnumMap<CableCoreType, EnumMap<AEColor, Sprite>> coreTextures;
|
||||
|
||||
// Textures for rendering the actual connection cubes, one per type/color pair
|
||||
private final EnumMap<AECableType, EnumMap<AEColor, Sprite>> connectionTextures;
|
||||
|
||||
private final SmartCableTextures smartCableTextures;
|
||||
|
||||
CableBuilder(Function<SpriteIdentifier, Sprite> bakedTextureGetter) {
|
||||
this.coreTextures = new EnumMap<>(CableCoreType.class);
|
||||
|
||||
for (CableCoreType type : CableCoreType.values()) {
|
||||
EnumMap<AEColor, Sprite> colorTextures = new EnumMap<>(AEColor.class);
|
||||
|
||||
for (AEColor color : AEColor.values()) {
|
||||
colorTextures.put(color, bakedTextureGetter.apply(type.getTexture(color)));
|
||||
}
|
||||
|
||||
this.coreTextures.put(type, colorTextures);
|
||||
}
|
||||
|
||||
this.connectionTextures = new EnumMap<>(AECableType.class);
|
||||
|
||||
for (AECableType type : AECableType.VALIDCABLES) {
|
||||
EnumMap<AEColor, Sprite> colorTextures = new EnumMap<>(AEColor.class);
|
||||
|
||||
for (AEColor color : AEColor.values()) {
|
||||
colorTextures.put(color, bakedTextureGetter.apply(getConnectionTexture(type, color)));
|
||||
}
|
||||
|
||||
this.connectionTextures.put(type, colorTextures);
|
||||
}
|
||||
|
||||
this.smartCableTextures = new SmartCableTextures(bakedTextureGetter);
|
||||
}
|
||||
|
||||
static SpriteIdentifier getConnectionTexture(AECableType cableType, AEColor color) {
|
||||
String textureFolder;
|
||||
switch (cableType) {
|
||||
case GLASS:
|
||||
textureFolder = "parts/cable/glass/";
|
||||
break;
|
||||
case COVERED:
|
||||
textureFolder = "parts/cable/covered/";
|
||||
break;
|
||||
case SMART:
|
||||
textureFolder = "parts/cable/smart/";
|
||||
break;
|
||||
case DENSE_COVERED:
|
||||
textureFolder = "parts/cable/dense_covered/";
|
||||
break;
|
||||
case DENSE_SMART:
|
||||
textureFolder = "parts/cable/dense_smart/";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Cable type " + cableType + " does not support connections.");
|
||||
}
|
||||
|
||||
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
|
||||
new Identifier(AppEng.MOD_ID, textureFolder + color.name().toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the core of a cable to the given list of quads.
|
||||
*
|
||||
* The type of cable core is automatically deduced from the given cable type.
|
||||
*/
|
||||
public void addCableCore(AECableType cableType, AEColor color, List<BakedQuad> quadsOut) {
|
||||
switch (cableType) {
|
||||
case GLASS:
|
||||
this.addCableCore(CableCoreType.GLASS, color, quadsOut);
|
||||
break;
|
||||
case COVERED:
|
||||
case SMART:
|
||||
this.addCableCore(CableCoreType.COVERED, color, quadsOut);
|
||||
break;
|
||||
case DENSE_COVERED:
|
||||
case DENSE_SMART:
|
||||
this.addCableCore(CableCoreType.DENSE, color, quadsOut);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
public void addCableCore(CableCoreType coreType, AEColor color, List<BakedQuad> quadsOut) {
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.coreTextures.get(coreType).get(color);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
switch (coreType) {
|
||||
case GLASS:
|
||||
cubeBuilder.addCube(6, 6, 6, 10, 10, 10);
|
||||
break;
|
||||
case COVERED:
|
||||
cubeBuilder.addCube(5, 5, 5, 11, 11, 11);
|
||||
break;
|
||||
case DENSE:
|
||||
cubeBuilder.addCube(3, 3, 3, 13, 13, 13);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void addGlassConnection(Direction facing, AEColor cableColor, AECableType connectionType,
|
||||
boolean cableBusAdjacent, List<BakedQuad> quadsOut) {
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
// We render all faces except the one on the connection side
|
||||
cubeBuilder.setDrawFaces(EnumSet.complementOf(EnumSet.of(facing)));
|
||||
|
||||
// For to-machine connections, use a thicker end-cap for the connection
|
||||
if (connectionType != AECableType.GLASS && !cableBusAdjacent) {
|
||||
Sprite texture = this.connectionTextures.get(AECableType.COVERED).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
this.addBigCoveredCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.GLASS).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
cubeBuilder.addCube(6, 0, 6, 10, 6, 10);
|
||||
break;
|
||||
case EAST:
|
||||
cubeBuilder.addCube(10, 6, 6, 16, 10, 10);
|
||||
break;
|
||||
case NORTH:
|
||||
cubeBuilder.addCube(6, 6, 0, 10, 10, 6);
|
||||
break;
|
||||
case SOUTH:
|
||||
cubeBuilder.addCube(6, 6, 10, 10, 10, 16);
|
||||
break;
|
||||
case UP:
|
||||
cubeBuilder.addCube(6, 10, 6, 10, 16, 10);
|
||||
break;
|
||||
case WEST:
|
||||
cubeBuilder.addCube(0, 6, 6, 6, 10, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void addStraightGlassConnection(Direction facing, AEColor cableColor, List<BakedQuad> quadsOut) {
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
// We render all faces except the connection caps. We can do this because the
|
||||
// glass cable is the smallest one
|
||||
// and its ends will always be covered by something
|
||||
cubeBuilder.setDrawFaces(EnumSet.complementOf(EnumSet.of(facing, facing.getOpposite())));
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.GLASS).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
case UP:
|
||||
cubeBuilder.addCube(6, 0, 6, 10, 16, 10);
|
||||
break;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
cubeBuilder.addCube(6, 6, 0, 10, 10, 16);
|
||||
break;
|
||||
case EAST:
|
||||
case WEST:
|
||||
cubeBuilder.addCube(0, 6, 6, 16, 10, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void addConstrainedGlassConnection(Direction facing, AEColor cableColor, int distanceFromEdge,
|
||||
List<BakedQuad> quadsOut) {
|
||||
|
||||
// Glass connections reach only 6 voxels from the edge
|
||||
if (distanceFromEdge >= 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.GLASS).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
cubeBuilder.addCube(6, distanceFromEdge, 6, 10, 6, 10);
|
||||
break;
|
||||
case EAST:
|
||||
cubeBuilder.addCube(10, 6, 6, 16 - distanceFromEdge, 10, 10);
|
||||
break;
|
||||
case NORTH:
|
||||
cubeBuilder.addCube(6, 6, distanceFromEdge, 10, 10, 6);
|
||||
break;
|
||||
case SOUTH:
|
||||
cubeBuilder.addCube(6, 6, 10, 10, 10, 16 - distanceFromEdge);
|
||||
break;
|
||||
case UP:
|
||||
cubeBuilder.addCube(6, 10, 6, 10, 16 - distanceFromEdge, 10);
|
||||
break;
|
||||
case WEST:
|
||||
cubeBuilder.addCube(distanceFromEdge, 6, 6, 6, 10, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void addCoveredConnection(Direction facing, AEColor cableColor, AECableType connectionType,
|
||||
boolean cableBusAdjacent, List<BakedQuad> quadsOut) {
|
||||
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
// We render all faces except the one on the connection side
|
||||
cubeBuilder.setDrawFaces(EnumSet.complementOf(EnumSet.of(facing)));
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.COVERED).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
// Draw a covered connection, if anything but glass is requested
|
||||
if (connectionType != AECableType.GLASS && !cableBusAdjacent) {
|
||||
this.addBigCoveredCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
addCoveredCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
public void addStraightCoveredConnection(Direction facing, AEColor cableColor, List<BakedQuad> quadsOut) {
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.COVERED).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
setStraightCableUVs(cubeBuilder, facing, 5, 11);
|
||||
|
||||
addStraightCoveredCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
private static void setStraightCableUVs(CubeBuilder cubeBuilder, Direction facing, int x, int y) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
case UP:
|
||||
cubeBuilder.setCustomUv(Direction.NORTH, x, 0, y, x);
|
||||
cubeBuilder.setCustomUv(Direction.EAST, x, 0, y, x);
|
||||
cubeBuilder.setCustomUv(Direction.SOUTH, x, 0, y, x);
|
||||
cubeBuilder.setCustomUv(Direction.WEST, x, 0, y, x);
|
||||
break;
|
||||
case EAST:
|
||||
case WEST:
|
||||
cubeBuilder.setCustomUv(Direction.UP, 0, x, x, y);
|
||||
cubeBuilder.setCustomUv(Direction.DOWN, 0, x, x, y);
|
||||
cubeBuilder.setCustomUv(Direction.NORTH, 0, x, x, y);
|
||||
cubeBuilder.setCustomUv(Direction.SOUTH, 0, x, x, y);
|
||||
break;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
cubeBuilder.setCustomUv(Direction.UP, x, 0, y, x);
|
||||
cubeBuilder.setCustomUv(Direction.DOWN, x, 0, y, x);
|
||||
cubeBuilder.setCustomUv(Direction.EAST, 0, x, x, y);
|
||||
cubeBuilder.setCustomUv(Direction.WEST, 0, x, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void addConstrainedCoveredConnection(Direction facing, AEColor cableColor, int distanceFromEdge,
|
||||
List<BakedQuad> quadsOut) {
|
||||
// The core of a covered cable reaches up to 5 voxels from the block edge, so
|
||||
// drawing a connection can only occur from there onwards
|
||||
if (distanceFromEdge >= 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.COVERED).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
addCoveredCableSizedCube(facing, distanceFromEdge, cubeBuilder);
|
||||
}
|
||||
|
||||
public void addSmartConnection(Direction facing, AEColor cableColor, AECableType connectionType,
|
||||
boolean cableBusAdjacent, int channels, List<BakedQuad> quadsOut) {
|
||||
if (connectionType == AECableType.COVERED || connectionType == AECableType.GLASS) {
|
||||
this.addCoveredConnection(facing, cableColor, connectionType, cableBusAdjacent, quadsOut);
|
||||
return;
|
||||
}
|
||||
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
// We render all faces except the one on the connection side
|
||||
cubeBuilder.setDrawFaces(EnumSet.complementOf(EnumSet.of(facing)));
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.SMART).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
Sprite oddChannel = this.smartCableTextures.getOddTextureForChannels(channels);
|
||||
Sprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// For to-machine connections, use a thicker end-cap for the connection
|
||||
if (connectionType != AECableType.GLASS && !cableBusAdjacent) {
|
||||
this.addBigCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
this.addBigCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
this.addBigCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to normal rendering for the rest
|
||||
cubeBuilder.setRenderFullBright(false);
|
||||
cubeBuilder.setTexture(texture);
|
||||
}
|
||||
|
||||
addCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
addCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addCoveredCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
public void addStraightSmartConnection(Direction facing, AEColor cableColor, int channels,
|
||||
List<BakedQuad> quadsOut) {
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.SMART).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
setStraightCableUVs(cubeBuilder, facing, 5, 11);
|
||||
|
||||
addStraightCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
Sprite oddChannel = this.smartCableTextures.getOddTextureForChannels(channels);
|
||||
Sprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
addStraightCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addStraightCoveredCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
public void addConstrainedSmartConnection(Direction facing, AEColor cableColor, int distanceFromEdge, int channels,
|
||||
List<BakedQuad> quadsOut) {
|
||||
// Same as with covered cables, the smart cable's core extends up to 5 voxels
|
||||
// away from the edge.
|
||||
// Drawing a connection to any point before that point is fruitless
|
||||
if (distanceFromEdge >= 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.SMART).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
addCoveredCableSizedCube(facing, distanceFromEdge, cubeBuilder);
|
||||
|
||||
Sprite oddChannel = this.smartCableTextures.getOddTextureForChannels(channels);
|
||||
Sprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
addCoveredCableSizedCube(facing, distanceFromEdge, cubeBuilder);
|
||||
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addCoveredCableSizedCube(facing, distanceFromEdge, cubeBuilder);
|
||||
}
|
||||
|
||||
public void addDenseCoveredConnection(Direction facing, AEColor cableColor, AECableType connectionType,
|
||||
boolean cableBusAdjacent, List<BakedQuad> quadsOut) {
|
||||
// Dense cables only render their connections as dense if the adjacent blocks
|
||||
// actually wants that
|
||||
if (connectionType == AECableType.COVERED || connectionType == AECableType.SMART
|
||||
|| connectionType == AECableType.GLASS) {
|
||||
this.addCoveredConnection(facing, cableColor, connectionType, cableBusAdjacent, quadsOut);
|
||||
return;
|
||||
}
|
||||
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
// We render all faces except the one on the connection side
|
||||
cubeBuilder.setDrawFaces(EnumSet.complementOf(EnumSet.of(facing)));
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.DENSE_COVERED).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
addDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to normal rendering for the rest
|
||||
cubeBuilder.setRenderFullBright(false);
|
||||
cubeBuilder.setTexture(texture);
|
||||
}
|
||||
|
||||
public void addDenseSmartConnection(Direction facing, AEColor cableColor, AECableType connectionType,
|
||||
boolean cableBusAdjacent, int channels, List<BakedQuad> quadsOut) {
|
||||
// Dense cables only render their connections as dense if the adjacent blocks
|
||||
// actually wants that
|
||||
if (connectionType == AECableType.SMART) {
|
||||
this.addSmartConnection(facing, cableColor, connectionType, cableBusAdjacent, channels, quadsOut);
|
||||
return;
|
||||
} else if (connectionType == AECableType.COVERED || connectionType == AECableType.GLASS) {
|
||||
this.addCoveredConnection(facing, cableColor, connectionType, cableBusAdjacent, quadsOut);
|
||||
return;
|
||||
} else if (connectionType == AECableType.DENSE_COVERED) {
|
||||
this.addDenseCoveredConnection(facing, cableColor, connectionType, cableBusAdjacent, quadsOut);
|
||||
return;
|
||||
}
|
||||
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
// We render all faces except the one on the connection side
|
||||
cubeBuilder.setDrawFaces(EnumSet.complementOf(EnumSet.of(facing)));
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.DENSE_SMART).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
addDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Dense cables show used channels in groups of 4, rounded up
|
||||
channels = (channels + 3) / 4;
|
||||
|
||||
Sprite oddChannel = this.smartCableTextures.getOddTextureForChannels(channels);
|
||||
Sprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
addDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to normal rendering for the rest
|
||||
cubeBuilder.setRenderFullBright(false);
|
||||
cubeBuilder.setTexture(texture);
|
||||
}
|
||||
|
||||
public void addStraightDenseCoveredConnection(Direction facing, AEColor cableColor, List<BakedQuad> quadsOut) {
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.DENSE_COVERED).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
setStraightCableUVs(cubeBuilder, facing, 5, 11);
|
||||
|
||||
addStraightDenseCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
public void addStraightDenseSmartConnection(Direction facing, AEColor cableColor, int channels,
|
||||
List<BakedQuad> quadsOut) {
|
||||
CubeBuilder cubeBuilder = new CubeBuilder(quadsOut);
|
||||
|
||||
Sprite texture = this.connectionTextures.get(AECableType.DENSE_SMART).get(cableColor);
|
||||
cubeBuilder.setTexture(texture);
|
||||
|
||||
setStraightCableUVs(cubeBuilder, facing, 5, 11);
|
||||
|
||||
addStraightDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Dense cables show used channels in groups of 4, rounded up
|
||||
channels = (channels + 3) / 4;
|
||||
|
||||
Sprite oddChannel = this.smartCableTextures.getOddTextureForChannels(channels);
|
||||
Sprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
addStraightDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addStraightDenseCableSizedCube(facing, cubeBuilder);
|
||||
}
|
||||
|
||||
private static void addDenseCableSizedCube(Direction facing, CubeBuilder cubeBuilder) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
cubeBuilder.addCube(4, 0, 4, 12, 5, 12);
|
||||
break;
|
||||
case EAST:
|
||||
cubeBuilder.addCube(11, 4, 4, 16, 12, 12);
|
||||
break;
|
||||
case NORTH:
|
||||
cubeBuilder.addCube(4, 4, 0, 12, 12, 5);
|
||||
break;
|
||||
case SOUTH:
|
||||
cubeBuilder.addCube(4, 4, 11, 12, 12, 16);
|
||||
break;
|
||||
case UP:
|
||||
cubeBuilder.addCube(4, 11, 4, 12, 16, 12);
|
||||
break;
|
||||
case WEST:
|
||||
cubeBuilder.addCube(0, 4, 4, 5, 12, 12);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a cube to the given cube builder that has the size of a dense cable
|
||||
// connection and spans the entire block
|
||||
// for the given direction
|
||||
private static void addStraightDenseCableSizedCube(Direction facing, CubeBuilder cubeBuilder) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
case UP:
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 3);
|
||||
cubeBuilder.addCube(3, 0, 3, 13, 16, 13);
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 0);
|
||||
break;
|
||||
case EAST:
|
||||
case WEST:
|
||||
cubeBuilder.setUvRotation(Direction.SOUTH, 3);
|
||||
cubeBuilder.setUvRotation(Direction.NORTH, 3);
|
||||
cubeBuilder.addCube(0, 3, 3, 16, 13, 13);
|
||||
cubeBuilder.setUvRotation(Direction.SOUTH, 0);
|
||||
cubeBuilder.setUvRotation(Direction.NORTH, 0);
|
||||
break;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 3);
|
||||
cubeBuilder.setUvRotation(Direction.WEST, 3);
|
||||
cubeBuilder.addCube(3, 3, 0, 13, 13, 16);
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 0);
|
||||
cubeBuilder.setUvRotation(Direction.WEST, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a cube to the given cube builder that has the size of a covered cable
|
||||
// connection from the core of the cable
|
||||
// to the given face
|
||||
private static void addCoveredCableSizedCube(Direction facing, CubeBuilder cubeBuilder) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
cubeBuilder.addCube(6, 0, 6, 10, 5, 10);
|
||||
break;
|
||||
case EAST:
|
||||
cubeBuilder.addCube(11, 6, 6, 16, 10, 10);
|
||||
break;
|
||||
case NORTH:
|
||||
cubeBuilder.addCube(6, 6, 0, 10, 10, 5);
|
||||
break;
|
||||
case SOUTH:
|
||||
cubeBuilder.addCube(6, 6, 11, 10, 10, 16);
|
||||
break;
|
||||
case UP:
|
||||
cubeBuilder.addCube(6, 11, 6, 10, 16, 10);
|
||||
break;
|
||||
case WEST:
|
||||
cubeBuilder.addCube(0, 6, 6, 5, 10, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a cube to the given cube builder that has the size of a covered cable
|
||||
// connection and spans the entire block
|
||||
// for the given direction
|
||||
private static void addStraightCoveredCableSizedCube(Direction facing, CubeBuilder cubeBuilder) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
case UP:
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 3);
|
||||
cubeBuilder.addCube(5, 0, 5, 11, 16, 11);
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 0);
|
||||
break;
|
||||
case EAST:
|
||||
case WEST:
|
||||
cubeBuilder.setUvRotation(Direction.SOUTH, 3);
|
||||
cubeBuilder.setUvRotation(Direction.NORTH, 3);
|
||||
cubeBuilder.addCube(0, 5, 5, 16, 11, 11);
|
||||
cubeBuilder.setUvRotation(Direction.SOUTH, 0);
|
||||
cubeBuilder.setUvRotation(Direction.NORTH, 0);
|
||||
break;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 3);
|
||||
cubeBuilder.setUvRotation(Direction.WEST, 3);
|
||||
cubeBuilder.addCube(5, 5, 0, 11, 11, 16);
|
||||
cubeBuilder.setUvRotation(Direction.EAST, 0);
|
||||
cubeBuilder.setUvRotation(Direction.WEST, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void addCoveredCableSizedCube(Direction facing, int distanceFromEdge, CubeBuilder cubeBuilder) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
cubeBuilder.addCube(6, distanceFromEdge, 6, 10, 5, 10);
|
||||
break;
|
||||
case EAST:
|
||||
cubeBuilder.addCube(11, 6, 6, 16 - distanceFromEdge, 10, 10);
|
||||
break;
|
||||
case NORTH:
|
||||
cubeBuilder.addCube(6, 6, distanceFromEdge, 10, 10, 5);
|
||||
break;
|
||||
case SOUTH:
|
||||
cubeBuilder.addCube(6, 6, 11, 10, 10, 16 - distanceFromEdge);
|
||||
break;
|
||||
case UP:
|
||||
cubeBuilder.addCube(6, 11, 6, 10, 16 - distanceFromEdge, 10);
|
||||
break;
|
||||
case WEST:
|
||||
cubeBuilder.addCube(distanceFromEdge, 6, 6, 5, 10, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This renders a slightly bigger covered cable connection to the specified
|
||||
* side. This is used to connect cable cores with adjacent machines that do not
|
||||
* want to be connected to using a glass cable connection. This applies to most
|
||||
* machines (interfaces, etc.)
|
||||
*/
|
||||
private void addBigCoveredCableSizedCube(Direction facing, CubeBuilder cubeBuilder) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
cubeBuilder.addCube(5, 0, 5, 11, 4, 11);
|
||||
break;
|
||||
case EAST:
|
||||
cubeBuilder.addCube(12, 5, 5, 16, 11, 11);
|
||||
break;
|
||||
case NORTH:
|
||||
cubeBuilder.addCube(5, 5, 0, 11, 11, 4);
|
||||
break;
|
||||
case SOUTH:
|
||||
cubeBuilder.addCube(5, 5, 12, 11, 11, 16);
|
||||
break;
|
||||
case UP:
|
||||
cubeBuilder.addCube(5, 12, 5, 11, 16, 11);
|
||||
break;
|
||||
case WEST:
|
||||
cubeBuilder.addCube(0, 5, 5, 4, 11, 11);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get all textures needed for building the actual cable quads
|
||||
public static List<SpriteIdentifier> getTextures() {
|
||||
List<SpriteIdentifier> locations = new ArrayList<>();
|
||||
|
||||
for (CableCoreType coreType : CableCoreType.values()) {
|
||||
for (AEColor color : AEColor.values()) {
|
||||
locations.add(coreType.getTexture(color));
|
||||
}
|
||||
}
|
||||
|
||||
for (AECableType cableType : AECableType.VALIDCABLES) {
|
||||
for (AEColor color : AEColor.values()) {
|
||||
locations.add(getConnectionTexture(cableType, color));
|
||||
}
|
||||
}
|
||||
|
||||
Collections.addAll(locations, SmartCableTextures.SMART_CHANNELS_TEXTURES);
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
public Sprite getCoreTexture(CableCoreType coreType, AEColor color) {
|
||||
return this.coreTextures.get(coreType).get(color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.MissingSprite;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CableBusBakedModel implements BakedModel, FabricBakedModel {
|
||||
|
||||
// FIXME: This entire cache seems dumb as shit
|
||||
private static final Map<CableBusRenderState, Mesh> CABLE_MODEL_CACHE = new HashMap<>();
|
||||
|
||||
private final CableBuilder cableBuilder;
|
||||
|
||||
private final FacadeBuilder facadeBuilder;
|
||||
|
||||
private final Map<Identifier, BakedModel> partModels;
|
||||
|
||||
private final Sprite particleTexture;
|
||||
|
||||
CableBusBakedModel(CableBuilder cableBuilder, FacadeBuilder facadeBuilder,
|
||||
Map<Identifier, BakedModel> partModels, Sprite particleTexture) {
|
||||
this.cableBuilder = cableBuilder;
|
||||
this.facadeBuilder = facadeBuilder;
|
||||
this.partModels = partModels;
|
||||
this.particleTexture = particleTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
// This model will only ever be used for blocks
|
||||
}
|
||||
|
||||
private CableBusRenderState getRenderState(BlockRenderView blockView, BlockPos pos) {
|
||||
|
||||
RenderAttachedBlockView renderAttachedBlockView = (RenderAttachedBlockView) blockView;
|
||||
Object renderAttachment = renderAttachedBlockView.getBlockEntityRenderAttachment(pos);
|
||||
if (renderAttachment instanceof CableBusRenderState) {
|
||||
return (CableBusRenderState) renderAttachment;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
|
||||
CableBusRenderState renderState = getRenderState(blockView, pos);
|
||||
|
||||
if (renderState == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderLayer layer = RenderLayer.getCutout(); // FIXME: Fabric can only render within one layer (?)
|
||||
|
||||
// The core parts of the cable will only be rendered in the CUTOUT layer.
|
||||
// Facades will add them selves to what ever the block would be rendered with,
|
||||
// except when transparent facades are enabled, they are forced to TRANSPARENT.
|
||||
if (layer == RenderLayer.getCutout()) {
|
||||
// First, handle the cable at the center of the cable bus
|
||||
final Mesh cableModel = CABLE_MODEL_CACHE.computeIfAbsent(renderState, this::buildCableModel);
|
||||
if (cableModel != null) {
|
||||
context.meshConsumer().accept(cableModel);
|
||||
}
|
||||
|
||||
// Then handle attachments
|
||||
for (Direction facing : Direction.values()) {
|
||||
final IPartModel partModel = renderState.getAttachments().get(facing);
|
||||
if (partModel == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object partModelData = renderState.getPartModelData().get(facing);
|
||||
|
||||
for (Identifier model : partModel.getModels()) {
|
||||
BakedModel bakedModel = this.partModels.get(model);
|
||||
|
||||
if (bakedModel == null) {
|
||||
throw new IllegalStateException("Trying to use an unregistered part model: " + model);
|
||||
}
|
||||
|
||||
context.pushTransform(QuadRotator.get(facing, Direction.UP));
|
||||
if (bakedModel instanceof FabricBakedModel) {
|
||||
((FabricBakedModel) bakedModel).emitBlockQuads(blockView, state, pos, randomSupplier, context);
|
||||
} else {
|
||||
context.fallbackConsumer().accept(bakedModel);
|
||||
}
|
||||
context.popTransform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.facadeBuilder.buildFacadeQuads(layer, renderState, randomSupplier, context, this.partModels::get);
|
||||
}
|
||||
|
||||
// Determines whether a cable is connected to exactly two sides that are
|
||||
// opposite each other
|
||||
private static boolean isStraightLine(AECableType cableType, EnumMap<Direction, AECableType> sides) {
|
||||
final Iterator<Entry<Direction, AECableType>> it = sides.entrySet().iterator();
|
||||
if (!it.hasNext()) {
|
||||
return false; // No connections
|
||||
}
|
||||
|
||||
final Entry<Direction, AECableType> nextConnection = it.next();
|
||||
final Direction firstSide = nextConnection.getKey();
|
||||
final AECableType firstType = nextConnection.getValue();
|
||||
|
||||
if (!it.hasNext()) {
|
||||
return false; // Only a single connection
|
||||
}
|
||||
if (firstSide.getOpposite() != it.next().getKey()) {
|
||||
return false; // Connected to two sides that are not opposite each other
|
||||
}
|
||||
if (it.hasNext()) {
|
||||
return false; // Must not have any other connection points
|
||||
}
|
||||
|
||||
final AECableType secondType = sides.get(firstSide.getOpposite());
|
||||
|
||||
return firstType == secondType && cableType == firstType && cableType == secondType;
|
||||
}
|
||||
|
||||
private Mesh buildCableModel(CableBusRenderState renderState) {
|
||||
AECableType cableType = renderState.getCableType();
|
||||
if (cableType == AECableType.NONE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AEColor cableColor = renderState.getCableColor();
|
||||
EnumMap<Direction, AECableType> connectionTypes = renderState.getConnectionTypes();
|
||||
|
||||
MeshBuilder builder = IndigoRenderer.INSTANCE.meshBuilder();
|
||||
QuadEmitter emitter = builder.getEmitter();
|
||||
// FIXME
|
||||
// FIXME // If the connection is straight, no busses are attached, and no covered core
|
||||
// FIXME // has been forced (in case of glass
|
||||
// FIXME // cables), then render the cable as a simplified straight line.
|
||||
// FIXME boolean noAttachments = !renderState.getAttachments().values().stream()
|
||||
// FIXME .anyMatch(IPartModel::requireCableConnection);
|
||||
// FIXME if (noAttachments && isStraightLine(cableType, connectionTypes)) {
|
||||
// FIXME Direction facing = connectionTypes.keySet().iterator().next();
|
||||
// FIXME
|
||||
// FIXME switch (cableType) {
|
||||
// FIXME case GLASS:
|
||||
// FIXME this.cableBuilder.addStraightGlassConnection(facing, cableColor, emitter);
|
||||
// FIXME break;
|
||||
// FIXME case COVERED:
|
||||
// FIXME this.cableBuilder.addStraightCoveredConnection(facing, cableColor, emitter);
|
||||
// FIXME break;
|
||||
// FIXME case SMART:
|
||||
// FIXME this.cableBuilder.addStraightSmartConnection(facing, cableColor,
|
||||
// FIXME renderState.getChannelsOnSide().get(facing), emitter);
|
||||
// FIXME break;
|
||||
// FIXME case DENSE_COVERED:
|
||||
// FIXME this.cableBuilder.addStraightDenseCoveredConnection(facing, cableColor, emitter);
|
||||
// FIXME break;
|
||||
// FIXME case DENSE_SMART:
|
||||
// FIXME this.cableBuilder.addStraightDenseSmartConnection(facing, cableColor,
|
||||
// FIXME renderState.getChannelsOnSide().get(facing), emitter);
|
||||
// FIXME break;
|
||||
// FIXME default:
|
||||
// FIXME break;
|
||||
// FIXME }
|
||||
// FIXME
|
||||
// FIXME return null; // Don't render the other form of connection
|
||||
// FIXME }
|
||||
// FIXME
|
||||
// FIXME this.cableBuilder.addCableCore(renderState.getCoreType(), cableColor, emitter);
|
||||
// FIXME
|
||||
// FIXME // Render all internal connections to attachments
|
||||
// FIXME EnumMap<Direction, Integer> attachmentConnections = renderState.getAttachmentConnections();
|
||||
// FIXME for (Direction facing : attachmentConnections.keySet()) {
|
||||
// FIXME int distance = attachmentConnections.get(facing);
|
||||
// FIXME int channels = renderState.getChannelsOnSide().get(facing);
|
||||
// FIXME
|
||||
// FIXME switch (cableType) {
|
||||
// FIXME case GLASS:
|
||||
// FIXME this.cableBuilder.addConstrainedGlassConnection(facing, cableColor, distance, emitter);
|
||||
// FIXME break;
|
||||
// FIXME case COVERED:
|
||||
// FIXME this.cableBuilder.addConstrainedCoveredConnection(facing, cableColor, distance, emitter);
|
||||
// FIXME break;
|
||||
// FIXME case SMART:
|
||||
// FIXME this.cableBuilder.addConstrainedSmartConnection(facing, cableColor, distance, channels, emitter);
|
||||
// FIXME break;
|
||||
// FIXME case DENSE_COVERED:
|
||||
// FIXME case DENSE_SMART:
|
||||
// FIXME // Dense cables do not render connections to parts since none can be attached
|
||||
// FIXME break;
|
||||
// FIXME default:
|
||||
// FIXME break;
|
||||
// FIXME }
|
||||
// FIXME }
|
||||
// FIXME
|
||||
// FIXME // Render all outgoing connections using the appropriate type
|
||||
// FIXME for (final Entry<Direction, AECableType> connection : connectionTypes.entrySet()) {
|
||||
// FIXME final Direction facing = connection.getKey();
|
||||
// FIXME final AECableType connectionType = connection.getValue();
|
||||
// FIXME final boolean cableBusAdjacent = renderState.getCableBusAdjacent().contains(facing);
|
||||
// FIXME final int channels = renderState.getChannelsOnSide().get(facing);
|
||||
// FIXME
|
||||
// FIXME switch (cableType) {
|
||||
// FIXME case GLASS:
|
||||
// FIXME this.cableBuilder.addGlassConnection(facing, cableColor, connectionType, cableBusAdjacent,
|
||||
// FIXME emitter);
|
||||
// FIXME break;
|
||||
// FIXME case COVERED:
|
||||
// FIXME this.cableBuilder.addCoveredConnection(facing, cableColor, connectionType, cableBusAdjacent,
|
||||
// FIXME emitter);
|
||||
// FIXME break;
|
||||
// FIXME case SMART:
|
||||
// FIXME this.cableBuilder.addSmartConnection(facing, cableColor, connectionType, cableBusAdjacent, channels,
|
||||
// FIXME emitter);
|
||||
// FIXME break;
|
||||
// FIXME case DENSE_COVERED:
|
||||
// FIXME this.cableBuilder.addDenseCoveredConnection(facing, cableColor, connectionType, cableBusAdjacent,
|
||||
// FIXME emitter);
|
||||
// FIXME break;
|
||||
// FIXME case DENSE_SMART:
|
||||
// FIXME this.cableBuilder.addDenseSmartConnection(facing, cableColor, connectionType, cableBusAdjacent,
|
||||
// FIXME channels, emitter);
|
||||
// FIXME break;
|
||||
// FIXME default:
|
||||
// FIXME break;
|
||||
// FIXME }
|
||||
// FIXME }
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of texture sprites appropriate for particles (digging, etc.)
|
||||
* given the render state for a cable bus.
|
||||
*/
|
||||
public List<Sprite> getParticleTextures(CableBusRenderState renderState) {
|
||||
CableCoreType coreType = CableCoreType.fromCableType(renderState.getCableType());
|
||||
AEColor cableColor = renderState.getCableColor();
|
||||
|
||||
List<Sprite> result = new ArrayList<>();
|
||||
|
||||
if (coreType != null) {
|
||||
result.add(this.cableBuilder.getCoreTexture(coreType, cableColor));
|
||||
}
|
||||
|
||||
// If no core is present, just use the first part that comes into play
|
||||
for (Direction side : renderState.getAttachments().keySet()) {
|
||||
IPartModel partModel = renderState.getAttachments().get(side);
|
||||
|
||||
for (Identifier model : partModel.getModels()) {
|
||||
BakedModel bakedModel = this.partModels.get(model);
|
||||
|
||||
if (bakedModel == null) {
|
||||
throw new IllegalStateException("Trying to use an unregistered part model: " + model);
|
||||
}
|
||||
|
||||
Sprite particleTexture = bakedModel.getSprite();
|
||||
|
||||
// If a part sub-model has no particle texture (indicated by it being the
|
||||
// missing texture),
|
||||
// don't add it, so we don't get ugly missing texture break particles.
|
||||
if (!isMissingTexture(particleTexture)) {
|
||||
result.add(particleTexture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isMissingTexture(Sprite particleTexture) {
|
||||
return particleTexture instanceof MissingSprite;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return false;// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getSprite() {
|
||||
return this.particleTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return ModelTransformation.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
CABLE_MODEL_CACHE.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanillaAdapter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import net.minecraft.client.particle.ParticleTextureSheet;
|
||||
import net.minecraft.client.particle.SpriteBillboardParticle;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
// Derived from Vanilla's BreakingParticle, but allows
|
||||
// a texture to be specified directly rather than via an itemstack
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class CableBusBreakingParticle extends SpriteBillboardParticle {
|
||||
|
||||
private final float field_217571_C;
|
||||
private final float field_217572_F;
|
||||
|
||||
public CableBusBreakingParticle(ClientWorld world, double x, double y, double z, double speedX, double speedY,
|
||||
double speedZ, Sprite sprite) {
|
||||
super(world, x, y, z, speedX, speedY, speedZ);
|
||||
this.setSprite(sprite);
|
||||
this.gravityStrength = 1.0F;
|
||||
this.scale /= 2.0F;
|
||||
this.field_217571_C = this.random.nextFloat() * 3.0F;
|
||||
this.field_217572_F = this.random.nextFloat() * 3.0F;
|
||||
}
|
||||
|
||||
public CableBusBreakingParticle(ClientWorld world, double x, double y, double z, Sprite sprite) {
|
||||
this(world, x, y, z, 0, 0, 0, sprite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParticleTextureSheet getType() {
|
||||
return ParticleTextureSheet.TERRAIN_SHEET;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getMinU() {
|
||||
return this.sprite.getFrameU((this.field_217571_C + 1.0F) / 4.0F * 16.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getMaxU() {
|
||||
return this.sprite.getFrameU(this.field_217571_C / 4.0F * 16.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getMinV() {
|
||||
return this.sprite.getFrameV(this.field_217572_F / 4.0F * 16.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getMaxV() {
|
||||
return this.sprite.getFrameV((this.field_217572_F + 1.0F) / 4.0F * 16.0F);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.client.render.model.ModelLoader;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.features.registries.PartModels;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The built-in model for the cable bus block.
|
||||
*/
|
||||
public class CableBusModel implements UnbakedModel {
|
||||
|
||||
private final PartModels partModels;
|
||||
|
||||
public CableBusModel(PartModels partModels) {
|
||||
this.partModels = partModels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
|
||||
Map<Identifier, BakedModel> partModels = this.loadPartModels(loader, rotationContainer);
|
||||
|
||||
CableBuilder cableBuilder = new CableBuilder(textureGetter);
|
||||
FacadeBuilder facadeBuilder = new FacadeBuilder();
|
||||
|
||||
// This should normally not be used, but we *have* to provide a particle texture
|
||||
// or otherwise damage models will
|
||||
// crash
|
||||
Sprite particleTexture = cableBuilder.getCoreTexture(CableCoreType.GLASS, AEColor.TRANSPARENT);
|
||||
|
||||
return new CableBusBakedModel(cableBuilder, facadeBuilder, partModels, particleTexture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SpriteIdentifier> getTextureDependencies(Function<Identifier, UnbakedModel> unbakedModelGetter, Set<Pair<String, String>> unresolvedTextureReferences) {
|
||||
return Collections.unmodifiableList(CableBuilder.getTextures());
|
||||
}
|
||||
|
||||
private Map<Identifier, BakedModel> loadPartModels(ModelLoader loader,
|
||||
ModelBakeSettings rotationContainer) {
|
||||
ImmutableMap.Builder<Identifier, BakedModel> result = ImmutableMap.builder();
|
||||
|
||||
for (Identifier location : this.partModels.getModels()) {
|
||||
BakedModel bakedModel = loader.bake(location, rotationContainer);
|
||||
if (bakedModel == null) {
|
||||
AELog.warn("Failed to bake part model {}", location);
|
||||
} else {
|
||||
result.put(location, bakedModel);
|
||||
}
|
||||
}
|
||||
|
||||
return result.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.features.registries.PartModels;
|
||||
import net.fabricmc.fabric.api.client.model.ModelProviderContext;
|
||||
import net.fabricmc.fabric.api.client.model.ModelProviderException;
|
||||
import net.fabricmc.fabric.api.client.model.ModelResourceProvider;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class CableBusModelLoader implements ModelResourceProvider {
|
||||
|
||||
private static final Identifier CABLE_BUS_MODEL = AppEng.makeId("block/cable_bus");
|
||||
|
||||
private final PartModels partModels;
|
||||
|
||||
public CableBusModelLoader(PartModels partModels) {
|
||||
this.partModels = partModels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context) throws ModelProviderException {
|
||||
if (CABLE_BUS_MODEL.equals(resourceId)) {
|
||||
CableBusBakedModel.clearCache();
|
||||
return new CableBusModel(partModels);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
|
||||
/**
|
||||
* This class captures the entire rendering state needed for a cable bus and
|
||||
* transports it to the rendering thread for processing.
|
||||
*/
|
||||
public class CableBusRenderState {
|
||||
|
||||
// The cable type used for rendering the outgoing connections to other blocks
|
||||
// and attached parts
|
||||
private AECableType cableType = AECableType.NONE;
|
||||
|
||||
// The type to use for rendering the core of the cable.
|
||||
private CableCoreType coreType;
|
||||
|
||||
private AEColor cableColor = AEColor.TRANSPARENT;
|
||||
|
||||
// Describes the outgoing connections of this cable bus to other blocks, and how
|
||||
// they should be rendered
|
||||
private EnumMap<Direction, AECableType> connectionTypes = new EnumMap<>(Direction.class);
|
||||
|
||||
// Indicate on which sides signified by connectionTypes above, there is another
|
||||
// cable bus. If a side is connected,
|
||||
// but it is absent from this
|
||||
// set, then it means that there is a Grid host, but not a cable bus on that
|
||||
// side (i.e. an interface, a controller,
|
||||
// etc.)
|
||||
private EnumSet<Direction> cableBusAdjacent = EnumSet.noneOf(Direction.class);
|
||||
|
||||
// Specifies the number of channels used for the connection to a given side.
|
||||
// Only contains entries if
|
||||
// connections contains a corresponding entry.
|
||||
private EnumMap<Direction, Integer> channelsOnSide = new EnumMap<>(Direction.class);
|
||||
|
||||
private EnumMap<Direction, IPartModel> attachments = new EnumMap<>(Direction.class);
|
||||
|
||||
// For each attachment, this contains the distance from the edge until which a
|
||||
// cable connection should be drawn
|
||||
private EnumMap<Direction, Integer> attachmentConnections = new EnumMap<>(Direction.class);
|
||||
|
||||
// Contains the facade to use for each side that has a facade attached
|
||||
private EnumMap<Direction, FacadeRenderState> facades = new EnumMap<>(Direction.class);
|
||||
|
||||
// Used for Facades.
|
||||
private WeakReference<BlockRenderView> world;
|
||||
private BlockPos pos;
|
||||
|
||||
// Contains the bounding boxes of all parts on the cable bus to allow facades to
|
||||
// cut out holes for the parts. This
|
||||
// list is only populated if there are
|
||||
// facades on this cable bus
|
||||
private List<Box> boundingBoxes = new ArrayList<>();
|
||||
|
||||
// Additional model data passed to the part models
|
||||
private EnumMap<Direction, Object> partModelData = new EnumMap<>(Direction.class);
|
||||
|
||||
public CableCoreType getCoreType() {
|
||||
return this.coreType;
|
||||
}
|
||||
|
||||
public void setCoreType(CableCoreType coreType) {
|
||||
this.coreType = coreType;
|
||||
}
|
||||
|
||||
public AECableType getCableType() {
|
||||
return this.cableType;
|
||||
}
|
||||
|
||||
public void setCableType(AECableType cableType) {
|
||||
this.cableType = cableType;
|
||||
}
|
||||
|
||||
public AEColor getCableColor() {
|
||||
return this.cableColor;
|
||||
}
|
||||
|
||||
public void setCableColor(AEColor cableColor) {
|
||||
this.cableColor = cableColor;
|
||||
}
|
||||
|
||||
public EnumMap<Direction, Integer> getChannelsOnSide() {
|
||||
return this.channelsOnSide;
|
||||
}
|
||||
|
||||
public EnumMap<Direction, AECableType> getConnectionTypes() {
|
||||
return this.connectionTypes;
|
||||
}
|
||||
|
||||
public void setConnectionTypes(EnumMap<Direction, AECableType> connectionTypes) {
|
||||
this.connectionTypes = connectionTypes;
|
||||
}
|
||||
|
||||
public void setChannelsOnSide(EnumMap<Direction, Integer> channelsOnSide) {
|
||||
this.channelsOnSide = channelsOnSide;
|
||||
}
|
||||
|
||||
public EnumSet<Direction> getCableBusAdjacent() {
|
||||
return this.cableBusAdjacent;
|
||||
}
|
||||
|
||||
public void setCableBusAdjacent(EnumSet<Direction> cableBusAdjacent) {
|
||||
this.cableBusAdjacent = cableBusAdjacent;
|
||||
}
|
||||
|
||||
public EnumMap<Direction, IPartModel> getAttachments() {
|
||||
return this.attachments;
|
||||
}
|
||||
|
||||
public EnumMap<Direction, Integer> getAttachmentConnections() {
|
||||
return this.attachmentConnections;
|
||||
}
|
||||
|
||||
public EnumMap<Direction, FacadeRenderState> getFacades() {
|
||||
return this.facades;
|
||||
}
|
||||
|
||||
public BlockRenderView getWorld() {
|
||||
return this.world.get();
|
||||
}
|
||||
|
||||
public void setWorld(BlockRenderView world) {
|
||||
this.world = new WeakReference<>(world);
|
||||
}
|
||||
|
||||
public BlockPos getPos() {
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
public void setPos(BlockPos pos) {
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
public List<Box> getBoundingBoxes() {
|
||||
return this.boundingBoxes;
|
||||
}
|
||||
|
||||
public EnumMap<Direction, Object> getPartModelData() {
|
||||
return this.partModelData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.attachmentConnections == null) ? 0 : this.attachmentConnections.hashCode());
|
||||
result = prime * result + ((this.cableBusAdjacent == null) ? 0 : this.cableBusAdjacent.hashCode());
|
||||
result = prime * result + ((this.cableColor == null) ? 0 : this.cableColor.hashCode());
|
||||
result = prime * result + ((this.cableType == null) ? 0 : this.cableType.hashCode());
|
||||
result = prime * result + ((this.channelsOnSide == null) ? 0 : this.channelsOnSide.hashCode());
|
||||
result = prime * result + ((this.connectionTypes == null) ? 0 : this.connectionTypes.hashCode());
|
||||
result = prime * result + ((this.coreType == null) ? 0 : this.coreType.hashCode());
|
||||
result = prime * result + ((this.partModelData == null) ? 0 : this.partModelData.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this.getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final CableBusRenderState other = (CableBusRenderState) obj;
|
||||
|
||||
return this.cableColor == other.cableColor && this.cableType == other.cableType
|
||||
&& this.coreType == other.coreType
|
||||
&& Objects.equals(this.attachmentConnections, other.attachmentConnections)
|
||||
&& Objects.equals(this.cableBusAdjacent, other.cableBusAdjacent)
|
||||
&& Objects.equals(this.channelsOnSide, other.channelsOnSide)
|
||||
&& Objects.equals(this.connectionTypes, other.connectionTypes)
|
||||
&& Objects.equals(this.partModelData, other.partModelData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.core.AppEng;
|
||||
|
||||
/**
|
||||
* AE can render the core of a cable (the core that connections are made to, in
|
||||
* case the cable is not a straight line) in three different ways: - Glass -
|
||||
* Covered (also used by the Smart Cable) - Dense
|
||||
*/
|
||||
public enum CableCoreType {
|
||||
GLASS("parts/cable/core/glass"), COVERED("parts/cable/core/covered"), DENSE("parts/cable/core/dense_smart");
|
||||
|
||||
private static final Map<AECableType, CableCoreType> cableMapping = generateCableMapping();
|
||||
|
||||
/**
|
||||
* Creates the mapping that assigns a cable core type to an AE cable type.
|
||||
*/
|
||||
private static Map<AECableType, CableCoreType> generateCableMapping() {
|
||||
|
||||
Map<AECableType, CableCoreType> result = new EnumMap<>(AECableType.class);
|
||||
|
||||
result.put(AECableType.GLASS, CableCoreType.GLASS);
|
||||
result.put(AECableType.COVERED, CableCoreType.COVERED);
|
||||
result.put(AECableType.SMART, CableCoreType.COVERED);
|
||||
result.put(AECableType.DENSE_COVERED, CableCoreType.DENSE);
|
||||
result.put(AECableType.DENSE_SMART, CableCoreType.DENSE);
|
||||
|
||||
return ImmutableMap.copyOf(result);
|
||||
}
|
||||
|
||||
private final String textureFolder;
|
||||
|
||||
CableCoreType(String textureFolder) {
|
||||
this.textureFolder = textureFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of core that should be rendered when the given cable isn't
|
||||
* straight and needs to have a core to attach connections to. Is null
|
||||
* for the NULL cable.
|
||||
*/
|
||||
public static CableCoreType fromCableType(AECableType cableType) {
|
||||
return cableMapping.get(cableType);
|
||||
}
|
||||
|
||||
public SpriteIdentifier getTexture(AEColor color) {
|
||||
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
|
||||
new Identifier(AppEng.MOD_ID, this.textureFolder + "/" + color.name().toLowerCase()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer;
|
||||
import net.minecraft.client.render.*;
|
||||
import net.minecraft.client.util.math.Vector4f;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
/**
|
||||
* Builds the quads for a cube.
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class CubeBuilder {
|
||||
|
||||
private final List<BakedQuad> output;
|
||||
|
||||
private final EnumMap<Direction, Sprite> textures = new EnumMap<>(Direction.class);
|
||||
|
||||
private EnumSet<Direction> drawFaces = EnumSet.allOf(Direction.class);
|
||||
|
||||
private final EnumMap<Direction, Vector4f> customUv = new EnumMap<>(Direction.class);
|
||||
|
||||
private final byte[] uvRotations = new byte[Direction.values().length];
|
||||
|
||||
private int color = 0xFFFFFFFF;
|
||||
|
||||
private boolean useStandardUV = false;
|
||||
|
||||
private boolean renderFullBright;
|
||||
|
||||
private final MeshBuilder meshBuilder;
|
||||
|
||||
private final QuadEmitter emitter;
|
||||
|
||||
private int vertexIndex = 0;
|
||||
|
||||
public CubeBuilder(List<BakedQuad> output) {
|
||||
this.output = output;
|
||||
|
||||
meshBuilder = IndigoRenderer.INSTANCE.meshBuilder();
|
||||
emitter = meshBuilder.getEmitter();
|
||||
|
||||
emitter.emit();
|
||||
meshBuilder.build();
|
||||
ModelHelper.toQuadLists(meshBuilder.build());
|
||||
}
|
||||
|
||||
public CubeBuilder() {
|
||||
this(new ArrayList<>(6));
|
||||
}
|
||||
|
||||
public void addCube(float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||
x1 /= 16.0f;
|
||||
y1 /= 16.0f;
|
||||
z1 /= 16.0f;
|
||||
x2 /= 16.0f;
|
||||
y2 /= 16.0f;
|
||||
z2 /= 16.0f;
|
||||
|
||||
for (Direction face : this.drawFaces) {
|
||||
this.putFace(face, x1, y1, z1, x2, y2, z2);
|
||||
}
|
||||
}
|
||||
|
||||
public void addQuad(Direction face, float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||
this.putFace(face, x1, y1, z1, x2, y2, z2);
|
||||
}
|
||||
|
||||
private static final class UvVector {
|
||||
float u1;
|
||||
float u2;
|
||||
float v1;
|
||||
float v2;
|
||||
}
|
||||
|
||||
private void putFace(Direction face, float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||
|
||||
Sprite texture = this.textures.get(face);
|
||||
|
||||
QuadEmitter emitter = this.emitter;
|
||||
emitter.colorIndex(-1)
|
||||
.nominalFace(face);
|
||||
|
||||
UvVector uv = new UvVector();
|
||||
|
||||
// The user might have set specific UV coordinates for this face
|
||||
Vector4f customUv = this.customUv.get(face);
|
||||
if (customUv != null) {
|
||||
uv.u1 = texture.getFrameU(customUv.getX());
|
||||
uv.v1 = texture.getFrameV(customUv.getY());
|
||||
uv.u2 = texture.getFrameU(customUv.getZ());
|
||||
uv.v2 = texture.getFrameV(customUv.getW());
|
||||
} else if (this.useStandardUV) {
|
||||
uv = this.getStandardUv(face, texture, x1, y1, z1, x2, y2, z2);
|
||||
} else {
|
||||
uv = this.getDefaultUv(face, texture, x1, y1, z1, x2, y2, z2);
|
||||
}
|
||||
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
this.putVertexTR(face, x2, y1, z1, uv);
|
||||
this.putVertexBR(face, x2, y1, z2, uv);
|
||||
this.putVertexBL(face, x1, y1, z2, uv);
|
||||
this.putVertexTL(face, x1, y1, z1, uv);
|
||||
break;
|
||||
case UP:
|
||||
this.putVertexTL(face, x1, y2, z1, uv);
|
||||
this.putVertexBL(face, x1, y2, z2, uv);
|
||||
this.putVertexBR(face, x2, y2, z2, uv);
|
||||
this.putVertexTR(face, x2, y2, z1, uv);
|
||||
break;
|
||||
case NORTH:
|
||||
this.putVertexBR(face, x2, y2, z1, uv);
|
||||
this.putVertexTR(face, x2, y1, z1, uv);
|
||||
this.putVertexTL(face, x1, y1, z1, uv);
|
||||
this.putVertexBL(face, x1, y2, z1, uv);
|
||||
break;
|
||||
case SOUTH:
|
||||
this.putVertexBL(face, x1, y2, z2, uv);
|
||||
this.putVertexTL(face, x1, y1, z2, uv);
|
||||
this.putVertexTR(face, x2, y1, z2, uv);
|
||||
this.putVertexBR(face, x2, y2, z2, uv);
|
||||
break;
|
||||
case WEST:
|
||||
this.putVertexTL(face, x1, y1, z1, uv);
|
||||
this.putVertexTR(face, x1, y1, z2, uv);
|
||||
this.putVertexBR(face, x1, y2, z2, uv);
|
||||
this.putVertexBL(face, x1, y2, z1, uv);
|
||||
break;
|
||||
case EAST:
|
||||
this.putVertexBR(face, x2, y2, z1, uv);
|
||||
this.putVertexBL(face, x2, y2, z2, uv);
|
||||
this.putVertexTL(face, x2, y1, z2, uv);
|
||||
this.putVertexTR(face, x2, y1, z1, uv);
|
||||
break;
|
||||
}
|
||||
|
||||
if (renderFullBright) {
|
||||
// Force Brightness to 15, this is for full bright mode
|
||||
// this vertex element will only be present in that case
|
||||
int lightmap = LightmapTextureManager.pack(15, 15);
|
||||
emitter.lightmap(lightmap, lightmap, lightmap, lightmap);
|
||||
}
|
||||
|
||||
// FIXME: this is unnecessarily inefficient
|
||||
emitter.emit();
|
||||
List<BakedQuad>[] quads = ModelHelper.toQuadLists(meshBuilder.build());
|
||||
this.output.addAll(Arrays.stream(quads).flatMap(Collection::stream).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private UvVector getDefaultUv(Direction face, Sprite texture, float x1, float y1, float z1, float x2,
|
||||
float y2, float z2) {
|
||||
|
||||
UvVector uv = new UvVector();
|
||||
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
uv.u1 = texture.getFrameU(x1 * 16);
|
||||
uv.v1 = texture.getFrameV(z1 * 16);
|
||||
uv.u2 = texture.getFrameU(x2 * 16);
|
||||
uv.v2 = texture.getFrameV(z2 * 16);
|
||||
break;
|
||||
case UP:
|
||||
uv.u1 = texture.getFrameU(x1 * 16);
|
||||
uv.v1 = texture.getFrameV(z1 * 16);
|
||||
uv.u2 = texture.getFrameU(x2 * 16);
|
||||
uv.v2 = texture.getFrameV(z2 * 16);
|
||||
break;
|
||||
case NORTH:
|
||||
uv.u1 = texture.getFrameU(x1 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(x2 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
case SOUTH:
|
||||
uv.u1 = texture.getFrameU(x1 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(x2 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
case WEST:
|
||||
uv.u1 = texture.getFrameU(z1 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(z2 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
case EAST:
|
||||
uv.u1 = texture.getFrameU(z2 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(z1 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
}
|
||||
|
||||
return uv;
|
||||
}
|
||||
|
||||
private UvVector getStandardUv(Direction face, Sprite texture, float x1, float y1, float z1, float x2,
|
||||
float y2, float z2) {
|
||||
UvVector uv = new UvVector();
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
uv.u1 = texture.getFrameU(x1 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - z1 * 16);
|
||||
uv.u2 = texture.getFrameU(x2 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - z2 * 16);
|
||||
break;
|
||||
case UP:
|
||||
uv.u1 = texture.getFrameU(x1 * 16);
|
||||
uv.v1 = texture.getFrameV(z1 * 16);
|
||||
uv.u2 = texture.getFrameU(x2 * 16);
|
||||
uv.v2 = texture.getFrameV(z2 * 16);
|
||||
break;
|
||||
case NORTH:
|
||||
uv.u1 = texture.getFrameU(16 - x1 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(16 - x2 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
case SOUTH:
|
||||
uv.u1 = texture.getFrameU(x1 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(x2 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
case WEST:
|
||||
uv.u1 = texture.getFrameU(z1 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(z2 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
case EAST:
|
||||
uv.u1 = texture.getFrameU(16 - z2 * 16);
|
||||
uv.v1 = texture.getFrameV(16 - y1 * 16);
|
||||
uv.u2 = texture.getFrameU(16 - z1 * 16);
|
||||
uv.v2 = texture.getFrameV(16 - y2 * 16);
|
||||
break;
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
|
||||
// uv.u1, uv.v1
|
||||
private void putVertexTL(Direction face, float x, float y, float z, UvVector uv) {
|
||||
float u, v;
|
||||
|
||||
switch (this.uvRotations[face.ordinal()]) {
|
||||
default:
|
||||
case 0:
|
||||
u = uv.u1;
|
||||
v = uv.v1;
|
||||
break;
|
||||
case 1: // 90° clockwise
|
||||
u = uv.u1;
|
||||
v = uv.v2;
|
||||
break;
|
||||
case 2: // 180° clockwise
|
||||
u = uv.u2;
|
||||
v = uv.v2;
|
||||
break;
|
||||
case 3: // 270° clockwise
|
||||
u = uv.u2;
|
||||
v = uv.v1;
|
||||
break;
|
||||
}
|
||||
|
||||
this.putVertex(face, x, y, z, u, v);
|
||||
}
|
||||
|
||||
// uv.u2, uv.v1
|
||||
private void putVertexTR(Direction face, float x, float y, float z, UvVector uv) {
|
||||
float u, v;
|
||||
|
||||
switch (this.uvRotations[face.ordinal()]) {
|
||||
default:
|
||||
case 0:
|
||||
u = uv.u2;
|
||||
v = uv.v1;
|
||||
break;
|
||||
case 1: // 90° clockwise
|
||||
u = uv.u1;
|
||||
v = uv.v1;
|
||||
break;
|
||||
case 2: // 180° clockwise
|
||||
u = uv.u1;
|
||||
v = uv.v2;
|
||||
break;
|
||||
case 3: // 270° clockwise
|
||||
u = uv.u2;
|
||||
v = uv.v2;
|
||||
break;
|
||||
}
|
||||
this.putVertex(face, x, y, z, u, v);
|
||||
}
|
||||
|
||||
// uv.u2, uv.v2
|
||||
private void putVertexBR(Direction face, float x, float y, float z, UvVector uv) {
|
||||
|
||||
float u;
|
||||
float v;
|
||||
|
||||
switch (this.uvRotations[face.ordinal()]) {
|
||||
default:
|
||||
case 0:
|
||||
u = uv.u2;
|
||||
v = uv.v2;
|
||||
break;
|
||||
case 1: // 90° clockwise
|
||||
u = uv.u2;
|
||||
v = uv.v1;
|
||||
break;
|
||||
case 2: // 180° clockwise
|
||||
u = uv.u1;
|
||||
v = uv.v1;
|
||||
break;
|
||||
case 3: // 270° clockwise
|
||||
u = uv.u1;
|
||||
v = uv.v2;
|
||||
break;
|
||||
}
|
||||
|
||||
this.putVertex(face, x, y, z, u, v);
|
||||
}
|
||||
|
||||
// uv.u1, uv.v2
|
||||
private void putVertexBL(Direction face, float x, float y, float z, UvVector uv) {
|
||||
|
||||
float u;
|
||||
float v;
|
||||
|
||||
switch (this.uvRotations[face.ordinal()]) {
|
||||
default:
|
||||
case 0:
|
||||
u = uv.u1;
|
||||
v = uv.v2;
|
||||
break;
|
||||
case 1: // 90° clockwise
|
||||
u = uv.u2;
|
||||
v = uv.v2;
|
||||
break;
|
||||
case 2: // 180° clockwise
|
||||
u = uv.u2;
|
||||
v = uv.v1;
|
||||
break;
|
||||
case 3: // 270° clockwise
|
||||
u = uv.u1;
|
||||
v = uv.v1;
|
||||
break;
|
||||
}
|
||||
|
||||
this.putVertex(face, x, y, z, u, v);
|
||||
}
|
||||
|
||||
private void putVertex(Direction face, float x, float y, float z, float u, float v) {
|
||||
|
||||
emitter.pos(vertexIndex, x, y, z);
|
||||
emitter.pos(vertexIndex, face.getOffsetX(), face.getOffsetY(), face.getOffsetZ());
|
||||
|
||||
// Color format is RGBA
|
||||
emitter.spriteColor(vertexIndex, this.color);
|
||||
|
||||
emitter.sprite(vertexIndex, 0, u, v);
|
||||
|
||||
vertexIndex++;
|
||||
}
|
||||
|
||||
public void setTexture(Sprite texture) {
|
||||
for (Direction face : Direction.values()) {
|
||||
this.textures.put(face, texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTextures(Sprite up, Sprite down, Sprite north,
|
||||
Sprite south, Sprite east, Sprite west) {
|
||||
this.textures.put(Direction.UP, up);
|
||||
this.textures.put(Direction.DOWN, down);
|
||||
this.textures.put(Direction.NORTH, north);
|
||||
this.textures.put(Direction.SOUTH, south);
|
||||
this.textures.put(Direction.EAST, east);
|
||||
this.textures.put(Direction.WEST, west);
|
||||
}
|
||||
|
||||
public void setTexture(Direction facing, Sprite sprite) {
|
||||
this.textures.put(facing, sprite);
|
||||
}
|
||||
|
||||
public void setDrawFaces(EnumSet<Direction> drawFaces) {
|
||||
this.drawFaces = drawFaces;
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vertex color for future vertices to the given RGB value, and forces
|
||||
* the alpha component to 255.
|
||||
*/
|
||||
public void setColorRGB(int color) {
|
||||
this.setColor(color | 0xFF000000);
|
||||
}
|
||||
|
||||
public void setColorRGB(float r, float g, float b) {
|
||||
this.setColorRGB((int) (r * 255) << 16 | (int) (g * 255) << 8 | (int) (b * 255));
|
||||
}
|
||||
|
||||
public void setRenderFullBright(boolean renderFullBright) {
|
||||
this.renderFullBright = renderFullBright;
|
||||
}
|
||||
|
||||
public void setCustomUv(Direction facing, float u1, float v1, float u2, float v2) {
|
||||
this.customUv.put(facing, new Vector4f(u1, v1, u2, v2));
|
||||
}
|
||||
|
||||
public void setUvRotation(Direction facing, int rotation) {
|
||||
if (rotation == 2) {
|
||||
rotation = 3;
|
||||
} else if (rotation == 3) {
|
||||
rotation = 2;
|
||||
}
|
||||
Preconditions.checkArgument(rotation >= 0 && rotation <= 3, "rotation");
|
||||
this.uvRotations[facing.ordinal()] = (byte) rotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* CubeBuilder uses UV optimized for cables by default. This switches to
|
||||
* standard UV coordinates.
|
||||
*/
|
||||
public void useStandardUV() {
|
||||
this.useStandardUV = true;
|
||||
}
|
||||
|
||||
public List<BakedQuad> getOutput() {
|
||||
return this.output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.RenderLayers;
|
||||
import net.minecraft.client.render.VertexFormats;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.block.BlockRenderManager;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.util.AEAxisAlignedBB;
|
||||
import appeng.parts.misc.CableAnchorPart;
|
||||
/**
|
||||
* The FacadeBuilder builds for facades..
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public class FacadeBuilder {
|
||||
|
||||
public static final double THICK_THICKNESS = 2D / 16D;
|
||||
public static final double THIN_THICKNESS = 1D / 16D;
|
||||
|
||||
public static final Box[] THICK_FACADE_BOXES = new Box[] {
|
||||
new Box(0.0, 0.0, 0.0, 1.0, THICK_THICKNESS, 1.0),
|
||||
new Box(0.0, 1.0 - THICK_THICKNESS, 0.0, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, 1.0, 1.0, THICK_THICKNESS),
|
||||
new Box(0.0, 0.0, 1.0 - THICK_THICKNESS, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, THICK_THICKNESS, 1.0, 1.0),
|
||||
new Box(1.0 - THICK_THICKNESS, 0.0, 0.0, 1.0, 1.0, 1.0) };
|
||||
|
||||
public static final Box[] THIN_FACADE_BOXES = new Box[] {
|
||||
new Box(0.0, 0.0, 0.0, 1.0, THIN_THICKNESS, 1.0),
|
||||
new Box(0.0, 1.0 - THIN_THICKNESS, 0.0, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, 1.0, 1.0, THIN_THICKNESS),
|
||||
new Box(0.0, 0.0, 1.0 - THIN_THICKNESS, 1.0, 1.0, 1.0),
|
||||
new Box(0.0, 0.0, 0.0, THIN_THICKNESS, 1.0, 1.0),
|
||||
new Box(1.0 - THIN_THICKNESS, 0.0, 0.0, 1.0, 1.0, 1.0) };
|
||||
|
||||
//FIXME private final ThreadLocal<BakedPipeline> pipelines = ThreadLocal.withInitial(() -> BakedPipeline.builder()
|
||||
//FIXME // Clamper is responsible for clamping the vertex to the bounds specified.
|
||||
//FIXME .addElement("clamper", QuadClamper.FACTORY)
|
||||
//FIXME // Strips faces if they match a mask.
|
||||
//FIXME .addElement("face_stripper", QuadFaceStripper.FACTORY)
|
||||
//FIXME // Kicks the edge inner corners in, solves Z fighting
|
||||
//FIXME .addElement("corner_kicker", QuadCornerKicker.FACTORY)
|
||||
//FIXME // Re-Interpolates the UV's for the quad.
|
||||
//FIXME .addElement("interp", QuadReInterpolator.FACTORY)
|
||||
//FIXME // Tints the quad if we need it to. Disabled by default.
|
||||
//FIXME .addElement("tinter", QuadTinter.FACTORY, false)
|
||||
//FIXME // Overrides the quad's alpha if we are forcing transparent facades.
|
||||
//FIXME .addElement("transparent", QuadAlphaOverride.FACTORY, false, e -> e.setAlphaOverride(0x4C / 255F)).build()//
|
||||
//FIXME );
|
||||
//FIXME private final ThreadLocal<Quad> collectors = ThreadLocal.withInitial(Quad::new);
|
||||
|
||||
public void buildFacadeQuads(RenderLayer layer, CableBusRenderState renderState, Supplier<Random> rand,
|
||||
RenderContext context, Function<Identifier, BakedModel> modelLookup) {
|
||||
//FIXME BakedPipeline pipeline = this.pipelines.get();
|
||||
//FIXME Quad collectorQuad = this.collectors.get();
|
||||
boolean transparent = AEApi.instance().partHelper().getCableRenderMode().transparentFacades;
|
||||
Map<Direction, FacadeRenderState> facadeStates = renderState.getFacades();
|
||||
List<Box> partBoxes = renderState.getBoundingBoxes();
|
||||
Set<Direction> sidesWithParts = renderState.getAttachments().keySet();
|
||||
BlockRenderView parentWorld = renderState.getWorld();
|
||||
BlockPos pos = renderState.getPos();
|
||||
BlockColors blockColors = MinecraftClient.getInstance().getBlockColors();
|
||||
boolean thinFacades = isUseThinFacades(partBoxes);
|
||||
|
||||
for (Entry<Direction, FacadeRenderState> entry : facadeStates.entrySet()) {
|
||||
Direction side = entry.getKey();
|
||||
int sideIndex = side.ordinal();
|
||||
FacadeRenderState facadeRenderState = entry.getValue();
|
||||
boolean renderStilt = !sidesWithParts.contains(side);
|
||||
if (layer == RenderLayer.getCutout() && renderStilt) {
|
||||
context.pushTransform(QuadRotator.get(side, Direction.UP));
|
||||
for (Identifier part : CableAnchorPart.FACADE_MODELS.getModels()) {
|
||||
BakedModel partModel = modelLookup.apply(part);
|
||||
context.fallbackConsumer().accept(partModel);
|
||||
}
|
||||
context.popTransform();
|
||||
}
|
||||
// If we are forcing transparency and this isn't the Translucent layer.
|
||||
if (transparent && layer != RenderLayer.getTranslucent()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockState blockState = facadeRenderState.getSourceBlock();
|
||||
// If we aren't forcing transparency let the block decide if it should render.
|
||||
if (!transparent && layer != null) {
|
||||
// FIXME FABRIC only one layer per block
|
||||
// FIXME FABRIC if (!RenderLayers.canRenderInLayer(blockState, layer)) {
|
||||
// FIXME FABRIC continue;
|
||||
// FIXME FABRIC }
|
||||
}
|
||||
|
||||
Box fullBounds = thinFacades ? THIN_FACADE_BOXES[sideIndex] : THICK_FACADE_BOXES[sideIndex];
|
||||
Box facadeBox = fullBounds;
|
||||
// If we are a transparent facade, we need to modify out BB.
|
||||
if (facadeRenderState.isTransparent()) {
|
||||
double offset = thinFacades ? THIN_THICKNESS : THICK_THICKNESS;
|
||||
AEAxisAlignedBB tmpBB = null;
|
||||
for (Direction face : Direction.values()) {
|
||||
// Only faces that aren't on our axis
|
||||
if (face.getAxis() != side.getAxis()) {
|
||||
FacadeRenderState otherState = facadeStates.get(face);
|
||||
if (otherState != null && !otherState.isTransparent()) {
|
||||
if (tmpBB == null) {
|
||||
tmpBB = AEAxisAlignedBB.fromBounds(facadeBox);
|
||||
}
|
||||
switch (face) {
|
||||
case DOWN:
|
||||
tmpBB.minY += offset;
|
||||
break;
|
||||
case UP:
|
||||
tmpBB.maxY -= offset;
|
||||
break;
|
||||
case NORTH:
|
||||
tmpBB.minZ += offset;
|
||||
break;
|
||||
case SOUTH:
|
||||
tmpBB.maxZ -= offset;
|
||||
break;
|
||||
case WEST:
|
||||
tmpBB.minX += offset;
|
||||
break;
|
||||
case EAST:
|
||||
tmpBB.maxX -= offset;
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Switch falloff. " + String.valueOf(face));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tmpBB != null) {
|
||||
facadeBox = tmpBB.getBoundingBox();
|
||||
}
|
||||
}
|
||||
|
||||
AEAxisAlignedBB cutOutBox = getCutOutBox(facadeBox, partBoxes);
|
||||
List<Box> holeStrips = getBoxes(facadeBox, cutOutBox, side.getAxis());
|
||||
// FIXME BlockRenderView facadeAccess = new FacadeBlockAccess(parentWorld, pos, side, blockState);
|
||||
|
||||
// FIXME FABRIC BlockRenderManager dispatcher = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
// FIXME FABRIC BakedModel model = dispatcher.getModel(blockState);
|
||||
// FIXME FABRIC IModelData modelData = model.getModelData(facadeAccess, pos, blockState, EmptyModelData.INSTANCE);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC List<BakedQuad> modelQuads = new ArrayList<>();
|
||||
// FIXME FABRIC // If we are forcing transparent facades, fake the render layer, and grab all
|
||||
// FIXME FABRIC // quads.
|
||||
// FIXME FABRIC if (transparent || layer == null) {
|
||||
// FIXME FABRIC for (RenderLayer forcedLayer : RenderLayer.getBlockRenderTypes()) {
|
||||
// FIXME FABRIC // Check if the block renders on the layer we want to force.
|
||||
// FIXME FABRIC if (RenderLayers.canRenderInLayer(blockState, forcedLayer)) {
|
||||
// FIXME FABRIC // Force the layer and gather quads.
|
||||
// FIXME FABRIC ForgeHooksClient.setRenderLayer(forcedLayer);
|
||||
// FIXME FABRIC modelQuads.addAll(gatherQuads(model, blockState, rand, modelData));
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Reset.
|
||||
// FIXME FABRIC ForgeHooksClient.setRenderLayer(layer);
|
||||
// FIXME FABRIC } else {
|
||||
// FIXME FABRIC modelQuads.addAll(gatherQuads(model, blockState, rand, modelData));
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // No quads.. Cool, next!
|
||||
// FIXME FABRIC if (modelQuads.isEmpty()) {
|
||||
// FIXME FABRIC continue;
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Grab out pipeline elements.
|
||||
// FIXME FABRIC QuadClamper clamper = pipeline.getElement("clamper", QuadClamper.class);
|
||||
// FIXME FABRIC QuadFaceStripper edgeStripper = pipeline.getElement("face_stripper", QuadFaceStripper.class);
|
||||
// FIXME FABRIC QuadTinter tinter = pipeline.getElement("tinter", QuadTinter.class);
|
||||
// FIXME FABRIC QuadCornerKicker kicker = pipeline.getElement("corner_kicker", QuadCornerKicker.class);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Set global element states.
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // calculate the side mask.
|
||||
// FIXME FABRIC int facadeMask = 0;
|
||||
// FIXME FABRIC for (Entry<Direction, FacadeRenderState> ent : facadeStates.entrySet()) {
|
||||
// FIXME FABRIC Direction s = ent.getKey();
|
||||
// FIXME FABRIC if (s.getAxis() != side.getAxis()) {
|
||||
// FIXME FABRIC FacadeRenderState otherState = ent.getValue();
|
||||
// FIXME FABRIC if (!otherState.isTransparent()) {
|
||||
// FIXME FABRIC facadeMask |= 1 << s.ordinal();
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC // Setup the edge stripper.
|
||||
// FIXME FABRIC edgeStripper.setBounds(fullBounds);
|
||||
// FIXME FABRIC edgeStripper.setMask(facadeMask);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Setup the kicker.
|
||||
// FIXME FABRIC kicker.setSide(sideIndex);
|
||||
// FIXME FABRIC kicker.setFacadeMask(facadeMask);
|
||||
// FIXME FABRIC kicker.setBox(fullBounds);
|
||||
// FIXME FABRIC kicker.setThickness(thinFacades ? THIN_THICKNESS : THICK_THICKNESS);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC for (BakedQuad quad : modelQuads) {
|
||||
// FIXME FABRIC // lookup the format in CachedFormat.
|
||||
// FIXME FABRIC CachedFormat format = CachedFormat.lookup(VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL);
|
||||
// FIXME FABRIC // If this quad has a tint index, setup the tinter.
|
||||
// FIXME FABRIC if (quad.hasTintIndex()) {
|
||||
// FIXME FABRIC tinter.setTint(blockColors.getColor(blockState, facadeAccess, pos, quad.getColorIndex()));
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC for (Box box : holeStrips) {
|
||||
// FIXME FABRIC // setup the clamper for this box
|
||||
// FIXME FABRIC clamper.setClampBounds(box);
|
||||
// FIXME FABRIC // Reset the pipeline, clears all enabled/disabled states.
|
||||
// FIXME FABRIC pipeline.reset(format);
|
||||
// FIXME FABRIC // Reset out collector.
|
||||
// FIXME FABRIC collectorQuad.reset(format);
|
||||
// FIXME FABRIC // Enable / disable the optional elements
|
||||
// FIXME FABRIC pipeline.setElementState("tinter", quad.hasTintIndex());
|
||||
// FIXME FABRIC pipeline.setElementState("transparent", transparent);
|
||||
// FIXME FABRIC // Prepare the pipeline for a quad.
|
||||
// FIXME FABRIC pipeline.prepare(collectorQuad);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC // Pipe our quad into the pipeline.
|
||||
// FIXME FABRIC quad.pipe(pipeline);
|
||||
// FIXME FABRIC // Check if the collector got any data.
|
||||
// FIXME FABRIC if (collectorQuad.full) {
|
||||
// FIXME FABRIC // Add the result.
|
||||
// FIXME FABRIC quads.add(collectorQuad.bake());
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is slow, so should be cached.
|
||||
*
|
||||
* @return The model.
|
||||
*/
|
||||
public List<BakedQuad> buildFacadeItemQuads(ItemStack textureItem, Direction side) {
|
||||
List<BakedQuad> facadeQuads = new ArrayList<>();
|
||||
|
||||
BakedModel model = MinecraftClient.getInstance().getItemRenderer().getHeldItemModel(textureItem, null,
|
||||
null);
|
||||
List<BakedQuad> modelQuads = gatherQuads(model, null, new Random());
|
||||
|
||||
//FIXME BakedPipeline pipeline = this.pipelines.get();
|
||||
//FIXME Quad collectorQuad = this.collectors.get();
|
||||
|
||||
// Grab pipeline elements.
|
||||
// FIXME QuadClamper clamper = pipeline.getElement("clamper", QuadClamper.class);
|
||||
// FIXME QuadTinter tinter = pipeline.getElement("tinter", QuadTinter.class);
|
||||
|
||||
for (BakedQuad quad : modelQuads) {
|
||||
// Lookup the CachedFormat for this quads format.
|
||||
// FIXME CachedFormat format = CachedFormat.lookup(VertexFormats.POSITION_COLOR_TEXTURE_LIGHT_NORMAL);
|
||||
// Reset the pipeline.
|
||||
// FIXME pipeline.reset(format);
|
||||
// Reset the collector.
|
||||
//FIXME collectorQuad.reset(format);
|
||||
// If we have a tint index, setup the tinter and enable it.
|
||||
// FIXME if (quad.hasTintIndex()) {
|
||||
// FIXME tinter.setTint(MinecraftClient.getInstance().getItemColors().getColor(textureItem, quad.getColorIndex()));
|
||||
// FIXME pipeline.enableElement("tinter");
|
||||
// FIXME }
|
||||
// Disable elements we don't need for items.
|
||||
// FIXME pipeline.disableElement("face_stripper");
|
||||
// FIXME pipeline.disableElement("corner_kicker");
|
||||
// FIXME // Setup the clamper
|
||||
// FIXME clamper.setClampBounds(THICK_FACADE_BOXES[side.ordinal()]);
|
||||
// FIXME // Prepare the pipeline.
|
||||
// FIXME pipeline.prepare(collectorQuad);
|
||||
// FIXME // Pipe our quad into the pipeline.
|
||||
// FIXME quad.pipe(pipeline);
|
||||
// FIXME // Check the collector for data and add the quad if there was.
|
||||
// FIXME if (collectorQuad.full) {
|
||||
// FIXME facadeQuads.add(collectorQuad.bake());
|
||||
// FIXME }
|
||||
}
|
||||
return facadeQuads;
|
||||
}
|
||||
|
||||
// Helper to gather all quads from a model into a list.
|
||||
private static List<BakedQuad> gatherQuads(BakedModel model, BlockState state, Random rand) {
|
||||
List<BakedQuad> modelQuads = new ArrayList<>();
|
||||
for (Direction face : Direction.values()) {
|
||||
modelQuads.addAll(model.getQuads(state, face, rand));
|
||||
}
|
||||
modelQuads.addAll(model.getQuads(state, null, rand));
|
||||
return modelQuads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the actual facade bounding box, and the bounding boxes of all parts,
|
||||
* determine the biggest union of AABB that intersect with the facade's bounding
|
||||
* box. This AABB will need to be "cut out" when the facade is rendered.
|
||||
*/
|
||||
@Nullable
|
||||
private static AEAxisAlignedBB getCutOutBox(Box facadeBox, List<Box> partBoxes) {
|
||||
AEAxisAlignedBB b = null;
|
||||
for (Box bb : partBoxes) {
|
||||
if (bb.intersects(facadeBox)) {
|
||||
if (b == null) {
|
||||
b = AEAxisAlignedBB.fromBounds(bb);
|
||||
} else {
|
||||
b.maxX = Math.max(b.maxX, bb.maxX);
|
||||
b.maxY = Math.max(b.maxY, bb.maxY);
|
||||
b.maxZ = Math.max(b.maxZ, bb.maxZ);
|
||||
b.minX = Math.min(b.minX, bb.minX);
|
||||
b.minY = Math.min(b.minY, bb.minY);
|
||||
b.minZ = Math.min(b.minZ, bb.minZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the box segments around the specified hole. If the specified hole
|
||||
* is null, a Singleton of the Facade box is returned.
|
||||
*
|
||||
* @param fb The Facade's box.
|
||||
* @param hole The hole to 'cut'.
|
||||
* @param axis The axis the facade is on.
|
||||
*
|
||||
* @return The box segments.
|
||||
*/
|
||||
private static List<Box> getBoxes(Box fb, AEAxisAlignedBB hole, Axis axis) {
|
||||
if (hole == null) {
|
||||
return Collections.singletonList(fb);
|
||||
}
|
||||
List<Box> boxes = new ArrayList<>();
|
||||
switch (axis) {
|
||||
case Y:
|
||||
boxes.add(new Box(fb.minX, fb.minY, fb.minZ, hole.minX, fb.maxY, fb.maxZ));
|
||||
boxes.add(new Box(hole.maxX, fb.minY, fb.minZ, fb.maxX, fb.maxY, fb.maxZ));
|
||||
|
||||
boxes.add(new Box(hole.minX, fb.minY, fb.minZ, hole.maxX, fb.maxY, hole.minZ));
|
||||
boxes.add(new Box(hole.minX, fb.minY, hole.maxZ, hole.maxX, fb.maxY, fb.maxZ));
|
||||
|
||||
break;
|
||||
case Z:
|
||||
boxes.add(new Box(fb.minX, fb.minY, fb.minZ, fb.maxX, hole.minY, fb.maxZ));
|
||||
boxes.add(new Box(fb.minX, hole.maxY, fb.minZ, fb.maxX, fb.maxY, fb.maxZ));
|
||||
|
||||
boxes.add(new Box(fb.minX, hole.minY, fb.minZ, hole.minX, hole.maxY, fb.maxZ));
|
||||
boxes.add(new Box(hole.maxX, hole.minY, fb.minZ, fb.maxX, hole.maxY, fb.maxZ));
|
||||
|
||||
break;
|
||||
case X:
|
||||
boxes.add(new Box(fb.minX, fb.minY, fb.minZ, fb.maxX, hole.minY, fb.maxZ));
|
||||
boxes.add(new Box(fb.minX, hole.maxY, fb.minZ, fb.maxX, fb.maxY, fb.maxZ));
|
||||
|
||||
boxes.add(new Box(fb.minX, hole.minY, fb.minZ, fb.maxX, hole.maxY, hole.minZ));
|
||||
boxes.add(new Box(fb.minX, hole.minY, hole.maxZ, fb.maxX, hole.maxY, fb.maxZ));
|
||||
break;
|
||||
default:
|
||||
// should never happen.
|
||||
throw new RuntimeException("switch falloff. " + String.valueOf(axis));
|
||||
}
|
||||
|
||||
return boxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if any of the part's bounding boxes intersects with the outside 2
|
||||
* voxel wide layer. If so, we should use thinner facades (1 voxel deep).
|
||||
*/
|
||||
private static boolean isUseThinFacades(List<Box> partBoxes) {
|
||||
final double min = 2.0 / 16.0;
|
||||
final double max = 14.0 / 16.0;
|
||||
|
||||
for (Box bb : partBoxes) {
|
||||
int o = 0;
|
||||
o += bb.maxX > max ? 1 : 0;
|
||||
o += bb.maxY > max ? 1 : 0;
|
||||
o += bb.maxZ > max ? 1 : 0;
|
||||
o += bb.minX < min ? 1 : 0;
|
||||
o += bb.minY < min ? 1 : 0;
|
||||
o += bb.minZ < min ? 1 : 0;
|
||||
|
||||
if (o >= 2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
|
||||
/**
|
||||
* Captures the state required to render a facade properly.
|
||||
*/
|
||||
public class FacadeRenderState {
|
||||
|
||||
// The block state to use for rendering this facade
|
||||
private final BlockState sourceBlock;
|
||||
|
||||
private final boolean transparent;
|
||||
|
||||
public FacadeRenderState(BlockState sourceBlock, boolean transparent) {
|
||||
this.sourceBlock = sourceBlock;
|
||||
this.transparent = transparent;
|
||||
}
|
||||
|
||||
public BlockState getSourceBlock() {
|
||||
return this.sourceBlock;
|
||||
}
|
||||
|
||||
public boolean isTransparent() {
|
||||
return this.transparent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import appeng.client.render.FacingToRotation;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.minecraft.client.util.math.Vector3f;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Matrix4f;
|
||||
|
||||
/**
|
||||
* Assuming a default-orientation of forward=NORTH and up=UP, this class rotates
|
||||
* a given list of quads to the desired facing
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class QuadRotator implements RenderContext.QuadTransform {
|
||||
// FIXME private static final ThreadLocal<BakedPipeline> pipelines = ThreadLocal.withInitial(() -> //
|
||||
// FIXME BakedPipeline.builder()//
|
||||
// FIXME .addElement("transformer", QuadMatrixTransformer.FACTORY)//
|
||||
// FIXME .build());
|
||||
// FIXME private static final ThreadLocal<Quad> collectors = ThreadLocal.withInitial(Quad::new);
|
||||
|
||||
private static final RenderContext.QuadTransform NULL_TRANSFORM = quad -> true;
|
||||
|
||||
private final FacingToRotation rotation;
|
||||
|
||||
public QuadRotator(FacingToRotation rotation) {
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public static RenderContext.QuadTransform get(Direction newForward, Direction newUp) {
|
||||
if (newForward == Direction.NORTH && newUp == Direction.UP) {
|
||||
return NULL_TRANSFORM; // This is the default orientation
|
||||
}
|
||||
FacingToRotation rotation = getRotation(newForward, newUp);
|
||||
if (rotation.isRedundant()) {
|
||||
return NULL_TRANSFORM;
|
||||
}
|
||||
return new QuadRotator(rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transform(MutableQuadView quad) {
|
||||
|
||||
// FIXME: Temporary rotation fix
|
||||
Matrix4f mat = new Matrix4f();
|
||||
mat.addToLastColumn(new Vector3f(-0.5f, -0.5f, -0.5f));
|
||||
mat.multiply(rotation.getMat());
|
||||
mat.addToLastColumn(new Vector3f(0.5f, 0.5f, 0.5f));
|
||||
|
||||
// FIXME ROTATION pipeline.reset(format);
|
||||
// FIXME ROTATION collector.reset(format);
|
||||
// FIXME ROTATION
|
||||
// FIXME ROTATION transformer.setMatrix(mat);
|
||||
// FIXME ROTATION pipeline.prepare(collector);
|
||||
// FIXME ROTATION quad.pipe(pipeline);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static FacingToRotation getRotation(Direction forward, Direction up) {
|
||||
// Sanitize forward/up
|
||||
if (forward.getAxis() == up.getAxis()) {
|
||||
if (up.getAxis() == Direction.Axis.Y) {
|
||||
up = Direction.NORTH;
|
||||
} else {
|
||||
up = Direction.UP;
|
||||
}
|
||||
}
|
||||
|
||||
return FacingToRotation.get(forward, up);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
|
||||
/**
|
||||
* Manages the channel textures for smart cables.
|
||||
*/
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class SmartCableTextures {
|
||||
|
||||
public static final SpriteIdentifier[] SMART_CHANNELS_TEXTURES = Arrays
|
||||
.stream(new Identifier[] { new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_00"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_01"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_02"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_03"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_04"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_10"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_11"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_12"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_13"), //
|
||||
new Identifier(AppEng.MOD_ID, "parts/cable/smart/channels_14")//
|
||||
}).map(e -> new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, e)).toArray(SpriteIdentifier[]::new);
|
||||
|
||||
// Textures used to display channels on smart cables. There's two sets of 5
|
||||
// textures each, and
|
||||
// one of each set are composed together to get even/odd colored channels
|
||||
private final Sprite[] textures;
|
||||
|
||||
public SmartCableTextures(Function<SpriteIdentifier, Sprite> bakedTextureGetter) {
|
||||
this.textures = Arrays.stream(SMART_CHANNELS_TEXTURES)//
|
||||
.map(bakedTextureGetter)//
|
||||
.toArray(Sprite[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* The odd variant is used for displaying channels 1-4 as in use.
|
||||
*/
|
||||
public Sprite getOddTextureForChannels(int channels) {
|
||||
if (channels < 0) {
|
||||
return this.textures[0];
|
||||
} else if (channels <= 4) {
|
||||
return this.textures[channels];
|
||||
} else {
|
||||
return this.textures[4];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The odd variant is used for displaying channels 5-8 as in use.
|
||||
*/
|
||||
public Sprite getEvenTextureForChannels(int channels) {
|
||||
if (channels < 5) {
|
||||
return this.textures[5];
|
||||
} else if (channels <= 8) {
|
||||
return this.textures[1 + channels];
|
||||
} else {
|
||||
return this.textures[9];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,27 +145,6 @@ public interface AppEng {
|
||||
// definitions.getRegistry().getBootstrapComponents(IClientSetupComponent.class)
|
||||
// .forEachRemaining(IClientSetupComponent::setup);
|
||||
//
|
||||
// addBuiltInModel("glass", GlassModel::new);
|
||||
// addBuiltInModel("sky_compass", SkyCompassModel::new);
|
||||
// addBuiltInModel("dummy_fluid_item", DummyFluidItemModel::new);
|
||||
// addBuiltInModel("memory_card", MemoryCardModel::new);
|
||||
// addBuiltInModel("biometric_card", BiometricCardModel::new);
|
||||
// addBuiltInModel("drive", DriveModel::new);
|
||||
// addBuiltInModel("color_applicator", ColorApplicatorModel::new);
|
||||
// addBuiltInModel("spatial_pylon", SpatialPylonModel::new);
|
||||
// addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
|
||||
// addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
|
||||
// addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
|
||||
// addBuiltInModel("facade", FacadeItemModel::new);
|
||||
// ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "encoded_pattern"),
|
||||
// EncodedPatternModelLoader.INSTANCE);
|
||||
// ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "part_plane"),
|
||||
// PlaneModelLoader.INSTANCE);
|
||||
// ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "crafting_cube"),
|
||||
// CraftingCubeModelLoader.INSTANCE);
|
||||
// ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE);
|
||||
// ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "cable_bus"),
|
||||
// new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
|
||||
//
|
||||
// }
|
||||
//
|
||||
@@ -214,7 +193,7 @@ public interface AppEng {
|
||||
////
|
||||
//// if( Platform.isClient() )
|
||||
//// {
|
||||
//// AppEng.proxy.preinit();
|
||||
//// AppEng.instance().preinit();
|
||||
//// }
|
||||
////
|
||||
//// IntegrationRegistry.INSTANCE.preInit();
|
||||
@@ -243,7 +222,7 @@ public interface AppEng {
|
||||
// // FIXME CrashReportExtender.registerCrashCallable( new
|
||||
// // IntegrationCrashEnhancement() );
|
||||
//
|
||||
// AppEng.proxy.postInit();
|
||||
// AppEng.instance().postInit();
|
||||
// AEConfig.instance().save();
|
||||
//
|
||||
// NetworkHandler.init(new Identifier(MOD_ID, "main"));
|
||||
|
||||
@@ -2,6 +2,12 @@ package appeng.core;
|
||||
|
||||
import appeng.api.features.IRegistryContainer;
|
||||
import appeng.api.networking.IGridCacheRegistry;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.networking.ticking.ITickManager;
|
||||
import appeng.api.parts.CableRenderMode;
|
||||
import appeng.bootstrap.components.ITileEntityRegistrationComponent;
|
||||
import appeng.client.render.effects.ParticleTypes;
|
||||
import appeng.core.features.registries.cell.BasicCellHandler;
|
||||
@@ -14,10 +20,14 @@ import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.network.TargetPoint;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.hooks.ToolItemHook;
|
||||
import appeng.me.cache.*;
|
||||
import appeng.mixins.CriteriaRegisterMixin;
|
||||
import appeng.recipes.handlers.*;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
import net.minecraft.recipe.RecipeType;
|
||||
import net.minecraft.util.Identifier;
|
||||
@@ -28,6 +38,9 @@ public abstract class AppEngBase implements AppEng {
|
||||
|
||||
protected AdvancementTriggers advancementTriggers;
|
||||
|
||||
// WTF is this doing? Should this be a ThreadLocal???
|
||||
private PlayerEntity renderModeBased;
|
||||
|
||||
public AppEngBase() {
|
||||
if (AppEng.instance() != null) {
|
||||
throw new IllegalStateException();
|
||||
@@ -60,13 +73,13 @@ public abstract class AppEngBase implements AppEng {
|
||||
final IRegistryContainer registries = api.registries();
|
||||
|
||||
final IGridCacheRegistry gcr = registries.gridCache();
|
||||
// FIXME FABRIC gcr.registerGridCache(ITickManager.class, TickManagerCache.class);
|
||||
// FIXME FABRIC gcr.registerGridCache(IEnergyGrid.class, EnergyGridCache.class);
|
||||
// FIXME FABRIC gcr.registerGridCache(IPathingGrid.class, PathGridCache.class);
|
||||
// FIXME FABRIC gcr.registerGridCache(IStorageGrid.class, GridStorageCache.class);
|
||||
gcr.registerGridCache(ITickManager.class, TickManagerCache::new);
|
||||
gcr.registerGridCache(IEnergyGrid.class, EnergyGridCache::new);
|
||||
gcr.registerGridCache(IPathingGrid.class, PathGridCache::new);
|
||||
gcr.registerGridCache(IStorageGrid.class, GridStorageCache::new);
|
||||
// FIXME FABRIC gcr.registerGridCache(P2PCache.class, P2PCache.class);
|
||||
// FIXME FABRIC gcr.registerGridCache(ISpatialCache.class, SpatialPylonCache.class);
|
||||
// FIXME FABRIC gcr.registerGridCache(ISecurityGrid.class, SecurityCache.class);
|
||||
gcr.registerGridCache(ISecurityGrid.class, SecurityCache::new);
|
||||
// FIXME FABRIC gcr.registerGridCache(ICraftingGrid.class, CraftingGridCache.class);
|
||||
|
||||
registries.cell().addCellHandler(new BasicCellHandler());
|
||||
@@ -130,4 +143,36 @@ public abstract class AppEngBase implements AppEng {
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CableRenderMode getRenderMode() {
|
||||
if (this.renderModeBased == null) {
|
||||
return CableRenderMode.STANDARD;
|
||||
}
|
||||
|
||||
return this.renderModeForPlayer(this.renderModeBased);
|
||||
}
|
||||
|
||||
// FIXME this is some hot shit _FOR WHAT_?
|
||||
@Override
|
||||
public void updateRenderMode(final PlayerEntity player) {
|
||||
this.renderModeBased = player;
|
||||
}
|
||||
|
||||
protected CableRenderMode renderModeForPlayer(final PlayerEntity player) {
|
||||
if (player != null) {
|
||||
for (int x = 0; x < PlayerInventory.getHotbarSize(); x++) {
|
||||
final ItemStack is = player.inventory.getStack(x);
|
||||
|
||||
// FIXME FABRIC if (!is.isEmpty() && is.getItem() instanceof NetworkToolItem) {
|
||||
// FIXME FABRIC final CompoundTag c = is.getTag();
|
||||
// FIXME FABRIC if (c != null && c.getBoolean("hideFacades")) {
|
||||
// FIXME FABRIC return CableRenderMode.CABLE_VIEW;
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
}
|
||||
}
|
||||
|
||||
return CableRenderMode.STANDARD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
package appeng.core.api;
|
||||
|
||||
import appeng.parts.PartPlacement;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
@@ -35,8 +36,7 @@ public class ApiPart implements IPartHelper {
|
||||
@Override
|
||||
public ActionResult placeBus(final ItemStack is, final BlockPos pos, final Direction side,
|
||||
final PlayerEntity player, final Hand hand, final World w) {
|
||||
// FIXME return PartPlacement.place(is, pos, side, player, hand, w, PartPlacement.PlaceType.PLACE_ITEM, 0);
|
||||
throw new IllegalStateException();
|
||||
return PartPlacement.place(is, pos, side, player, hand, w, PartPlacement.PlaceType.PLACE_ITEM, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,8 @@ import appeng.api.definitions.IBlocks;
|
||||
import appeng.api.definitions.ITileDefinition;
|
||||
import appeng.api.features.AEFeature;
|
||||
import appeng.block.misc.*;
|
||||
import appeng.block.networking.CableBusBlock;
|
||||
import appeng.block.networking.CableBusRendering;
|
||||
import appeng.block.storage.SkyChestBlock;
|
||||
import appeng.bootstrap.*;
|
||||
import appeng.bootstrap.components.IInitComponent;
|
||||
@@ -35,6 +37,8 @@ import appeng.entity.TinyTNTPrimedEntity;
|
||||
import appeng.hooks.TinyTNTDispenseItemBehavior;
|
||||
import appeng.tile.misc.LightDetectorBlockEntity;
|
||||
import appeng.tile.misc.SkyCompassBlockEntity;
|
||||
import appeng.tile.networking.CableBusBlockEntity;
|
||||
import appeng.tile.networking.CableBusTESR;
|
||||
import appeng.tile.storage.SkyChestBlockEntity;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
@@ -516,16 +520,16 @@ public final class ApiBlocks implements IBlocks {
|
||||
() -> new AEStairsBlock(this.quartzPillar().block().getDefaultState(), QUARTZ_PROPERTIES))
|
||||
.addFeatures(AEFeature.CERTUS).build();
|
||||
|
||||
// FIXME this.multiPart = registry.block("cable_bus", CableBusBlock::new).rendering(new CableBusRendering())
|
||||
// FIXME .tileEntity(registry.tileEntity("cable_bus", CableBusBlockEntity.class, CableBusBlockEntity::new)
|
||||
// FIXME .rendering(new TileEntityRenderingCustomizer<CableBusBlockEntity>() {
|
||||
// FIXME @Override
|
||||
// FIXME @Environment(EnvType.CLIENT)
|
||||
// FIXME public void customize(TileEntityRendering<CableBusBlockEntity> rendering) {
|
||||
// FIXME rendering.tileEntityRenderer(CableBusTESR::new);
|
||||
// FIXME }
|
||||
// FIXME }).build())
|
||||
// FIXME .build();
|
||||
this.multiPart = registry.block("cable_bus", CableBusBlock::new).rendering(new CableBusRendering())
|
||||
.tileEntity(registry.tileEntity("cable_bus", CableBusBlockEntity.class, CableBusBlockEntity::new)
|
||||
.rendering(new TileEntityRenderingCustomizer<CableBusBlockEntity>() {
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void customize(TileEntityRendering<CableBusBlockEntity> rendering) {
|
||||
rendering.tileEntityRenderer(CableBusTESR::new);
|
||||
}
|
||||
}).build())
|
||||
.build();
|
||||
|
||||
this.skyStoneSlab = deco.block("sky_stone_slab", () -> new SlabBlock(SKYSTONE_PROPERTIES))
|
||||
.addFeatures(AEFeature.SKY_STONE).build();
|
||||
|
||||
@@ -20,9 +20,25 @@ package appeng.core.api.definitions;
|
||||
|
||||
import appeng.api.definitions.IItemDefinition;
|
||||
import appeng.api.definitions.IParts;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.AEColoredItemDefinition;
|
||||
import appeng.bootstrap.FeatureFactory;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.CreativeTab;
|
||||
import appeng.core.features.ActivityState;
|
||||
import appeng.core.features.ColoredItemDefinition;
|
||||
import appeng.core.features.ItemStackSrc;
|
||||
import appeng.core.features.registries.PartModels;
|
||||
import appeng.items.parts.ColoredPartItem;
|
||||
import appeng.items.parts.PartItem;
|
||||
import appeng.items.parts.PartItemRendering;
|
||||
import appeng.parts.misc.CableAnchorPart;
|
||||
import appeng.parts.networking.*;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Internal implementation for the API parts
|
||||
@@ -73,110 +89,108 @@ public final class ApiParts implements IParts {
|
||||
public ApiParts(FeatureFactory registry, PartModels partModels) {
|
||||
registerPartModels(partModels);
|
||||
|
||||
// FIXME this.cableSmart = constructColoredDefinition(registry, "smart_cable", PartType.CABLE_SMART,
|
||||
// FIXME SmartCablePart::new);
|
||||
// FIXME this.cableCovered = constructColoredDefinition(registry, "covered_cable", PartType.CABLE_COVERED,
|
||||
// FIXME CoveredCablePart::new);
|
||||
// FIXME this.cableGlass = constructColoredDefinition(registry, "glass_cable", PartType.CABLE_GLASS,
|
||||
// FIXME GlassCablePart::new);
|
||||
// FIXME this.cableDenseCovered = constructColoredDefinition(registry, "covered_dense_cable",
|
||||
// FIXME PartType.CABLE_DENSE_COVERED, CoveredDenseCablePart::new);
|
||||
// FIXME this.cableDenseSmart = constructColoredDefinition(registry, "smart_dense_cable", PartType.CABLE_DENSE_SMART,
|
||||
// FIXME SmartDenseCablePart::new);
|
||||
// FIXME this.quartzFiber = createPart(registry, "quartz_fiber", PartType.QUARTZ_FIBER, QuartzFiberPart::new);
|
||||
// FIXME this.toggleBus = createPart(registry, "toggle_bus", PartType.TOGGLE_BUS, ToggleBusPart::new);
|
||||
// FIXME this.invertedToggleBus = createPart(registry, "inverted_toggle_bus", PartType.INVERTED_TOGGLE_BUS,
|
||||
this.cableSmart = constructColoredDefinition(registry, "smart_cable", SmartCablePart::new);
|
||||
this.cableCovered = constructColoredDefinition(registry, "covered_cable", CoveredCablePart::new);
|
||||
this.cableGlass = constructColoredDefinition(registry, "glass_cable",
|
||||
GlassCablePart::new);
|
||||
this.cableDenseCovered = constructColoredDefinition(registry, "covered_dense_cable",
|
||||
CoveredDenseCablePart::new);
|
||||
this.cableDenseSmart = constructColoredDefinition(registry, "smart_dense_cable",
|
||||
SmartDenseCablePart::new);
|
||||
this.quartzFiber = createPart(registry, "quartz_fiber", QuartzFiberPart::new);
|
||||
// FIXME this.toggleBus = createPart(registry, "toggle_bus", ToggleBusPart::new);
|
||||
// FIXME this.invertedToggleBus = createPart(registry, "inverted_toggle_bus",
|
||||
// FIXME InvertedToggleBusPart::new);
|
||||
// FIXME this.cableAnchor = createPart(registry, "cable_anchor", PartType.CABLE_ANCHOR, CableAnchorPart::new);
|
||||
// FIXME this.monitor = createPart(registry, "monitor", PartType.MONITOR, PanelPart::new);
|
||||
// FIXME this.semiDarkMonitor = createPart(registry, "semi_dark_monitor", PartType.SEMI_DARK_MONITOR,
|
||||
this.cableAnchor = createPart(registry, "cable_anchor", CableAnchorPart::new);
|
||||
// FIXME this.monitor = createPart(registry, "monitor", PanelPart::new);
|
||||
// FIXME this.semiDarkMonitor = createPart(registry, "semi_dark_monitor",
|
||||
// FIXME SemiDarkPanelPart::new);
|
||||
// FIXME this.darkMonitor = createPart(registry, "dark_monitor", PartType.DARK_MONITOR, DarkPanelPart::new);
|
||||
// FIXME this.storageBus = createPart(registry, "storage_bus", PartType.STORAGE_BUS, StorageBusPart::new);
|
||||
// FIXME this.fluidStorageBus = createPart(registry, "fluid_storage_bus", PartType.FLUID_STORAGE_BUS,
|
||||
// FIXME this.darkMonitor = createPart(registry, "dark_monitor", DarkPanelPart::new);
|
||||
// FIXME this.storageBus = createPart(registry, "storage_bus", StorageBusPart::new);
|
||||
// FIXME this.fluidStorageBus = createPart(registry, "fluid_storage_bus",
|
||||
// FIXME FluidStorageBusPart::new);
|
||||
// FIXME this.importBus = createPart(registry, "import_bus", PartType.IMPORT_BUS, ImportBusPart::new);
|
||||
// FIXME this.fluidImportBus = createPart(registry, "fluid_import_bus", PartType.FLUID_IMPORT_BUS,
|
||||
// FIXME this.importBus = createPart(registry, "import_bus", ImportBusPart::new);
|
||||
// FIXME this.fluidImportBus = createPart(registry, "fluid_import_bus",
|
||||
// FIXME FluidImportBusPart::new);
|
||||
// FIXME this.exportBus = createPart(registry, "export_bus", PartType.EXPORT_BUS, ExportBusPart::new);
|
||||
// FIXME this.fluidExportBus = createPart(registry, "fluid_export_bus", PartType.FLUID_EXPORT_BUS,
|
||||
// FIXME this.exportBus = createPart(registry, "export_bus", ExportBusPart::new);
|
||||
// FIXME this.fluidExportBus = createPart(registry, "fluid_export_bus",
|
||||
// FIXME FluidExportBusPart::new);
|
||||
// FIXME this.levelEmitter = createPart(registry, "level_emitter", PartType.LEVEL_EMITTER, LevelEmitterPart::new);
|
||||
// FIXME this.fluidLevelEmitter = createPart(registry, "fluid_level_emitter", PartType.FLUID_LEVEL_EMITTER,
|
||||
// FIXME this.levelEmitter = createPart(registry, "level_emitter", LevelEmitterPart::new);
|
||||
// FIXME this.fluidLevelEmitter = createPart(registry, "fluid_level_emitter",
|
||||
// FIXME FluidLevelEmitterPart::new);
|
||||
// FIXME this.annihilationPlane = createPart(registry, "annihilation_plane", PartType.ANNIHILATION_PLANE,
|
||||
// FIXME this.annihilationPlane = createPart(registry, "annihilation_plane",
|
||||
// FIXME AnnihilationPlanePart::new);
|
||||
// FIXME this.identityAnnihilationPlane = createPart(registry, "identity_annihilation_plane",
|
||||
// FIXME PartType.IDENTITY_ANNIHILATION_PLANE, IdentityAnnihilationPlanePart::new);
|
||||
// FIXME IdentityAnnihilationPlanePart::new);
|
||||
// FIXME this.fluidAnnihilationPlane = createPart(registry, "fluid_annihilation_plane",
|
||||
// FIXME PartType.FLUID_ANNIHILATION_PLANE, FluidAnnihilationPlanePart::new);
|
||||
// FIXME this.formationPlane = createPart(registry, "formation_plane", PartType.FORMATION_PLANE,
|
||||
// FIXME FluidAnnihilationPlanePart::new);
|
||||
// FIXME this.formationPlane = createPart(registry, "formation_plane",
|
||||
// FIXME FormationPlanePart::new);
|
||||
// FIXME this.fluidFormationPlane = createPart(registry, "fluid_formation_plane", PartType.FLUID_FORMATION_PLANE,
|
||||
// FIXME this.fluidFormationPlane = createPart(registry, "fluid_formation_plane",
|
||||
// FIXME FluidFormationPlanePart::new);
|
||||
// FIXME this.patternTerminal = createPart(registry, "pattern_terminal", PartType.PATTERN_TERMINAL,
|
||||
// FIXME this.patternTerminal = createPart(registry, "pattern_terminal",
|
||||
// FIXME PatternTerminalPart::new);
|
||||
// FIXME this.craftingTerminal = createPart(registry, "crafting_terminal", PartType.CRAFTING_TERMINAL,
|
||||
// FIXME this.craftingTerminal = createPart(registry, "crafting_terminal",
|
||||
// FIXME CraftingTerminalPart::new);
|
||||
// FIXME this.terminal = createPart(registry, "terminal", PartType.TERMINAL, TerminalPart::new);
|
||||
// FIXME this.storageMonitor = createPart(registry, "storage_monitor", PartType.STORAGE_MONITOR,
|
||||
// FIXME this.terminal = createPart(registry, "terminal", TerminalPart::new);
|
||||
// FIXME this.storageMonitor = createPart(registry, "storage_monitor",
|
||||
// FIXME StorageMonitorPart::new);
|
||||
// FIXME this.conversionMonitor = createPart(registry, "conversion_monitor", PartType.CONVERSION_MONITOR,
|
||||
// FIXME this.conversionMonitor = createPart(registry, "conversion_monitor",
|
||||
// FIXME ConversionMonitorPart::new);
|
||||
// FIXME this.iface = createPart(registry, "cable_interface", PartType.INTERFACE, InterfacePart::new);
|
||||
// FIXME this.fluidIface = createPart(registry, "cable_fluid_interface", PartType.FLUID_INTERFACE,
|
||||
// FIXME this.iface = createPart(registry, "cable_interface", InterfacePart::new);
|
||||
// FIXME this.fluidIface = createPart(registry, "cable_fluid_interface",
|
||||
// FIXME FluidInterfacePart::new);
|
||||
// FIXME this.p2PTunnelME = createPart(registry, "me_p2p_tunnel", PartType.P2P_TUNNEL_ME, MEP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelRedstone = createPart(registry, "redstone_p2p_tunnel", PartType.P2P_TUNNEL_REDSTONE,
|
||||
// FIXME this.p2PTunnelME = createPart(registry, "me_p2p_tunnel", MEP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelRedstone = createPart(registry, "redstone_p2p_tunnel",
|
||||
// FIXME RedstoneP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelItems = createPart(registry, "item_p2p_tunnel", PartType.P2P_TUNNEL_ITEM, ItemP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelFluids = createPart(registry, "fluid_p2p_tunnel", PartType.P2P_TUNNEL_FLUID,
|
||||
// FIXME this.p2PTunnelItems = createPart(registry, "item_p2p_tunnel", ItemP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelFluids = createPart(registry, "fluid_p2p_tunnel",
|
||||
// FIXME FluidP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelEU = null; // FIXME createPart( "ic2_p2p_tunnel", PartType.P2P_TUNNEL_IC2,
|
||||
// FIXME this.p2PTunnelEU = null; // FIXME createPart( "ic2_p2p_tunnel",
|
||||
// FIXME // PartP2PIC2Power::new);
|
||||
// FIXME this.p2PTunnelFE = createPart(registry, "fe_p2p_tunnel", PartType.P2P_TUNNEL_FE, FEP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelLight = createPart(registry, "light_p2p_tunnel", PartType.P2P_TUNNEL_LIGHT,
|
||||
// FIXME this.p2PTunnelFE = createPart(registry, "fe_p2p_tunnel", FEP2PTunnelPart::new);
|
||||
// FIXME this.p2PTunnelLight = createPart(registry, "light_p2p_tunnel",
|
||||
// FIXME LightP2PTunnelPart::new);
|
||||
// FIXME this.interfaceTerminal = createPart(registry, "interface_terminal", PartType.INTERFACE_TERMINAL,
|
||||
// FIXME this.interfaceTerminal = createPart(registry, "interface_terminal",
|
||||
// FIXME InterfaceTerminalPart::new);
|
||||
// FIXME this.fluidTerminal = createPart(registry, "fluid_terminal", PartType.FLUID_TERMINAL, FluidTerminalPart::new);
|
||||
// FIXME this.fluidTerminal = createPart(registry, "fluid_terminal", FluidTerminalPart::new);
|
||||
}
|
||||
|
||||
private void registerPartModels(PartModels partModels) {
|
||||
|
||||
// FIXME // Register the built-in models for annihilation planes
|
||||
// FIXME Identifier fluidFormationPlaneTexture = new Identifier(AppEng.MOD_ID,
|
||||
// FIXME "item/part/fluid_formation_plane");
|
||||
// FIXME Identifier fluidFormationPlaneOnTexture = new Identifier(AppEng.MOD_ID,
|
||||
// FIXME "parts/fluid_formation_plane_on");
|
||||
// FIXME
|
||||
// FIXME // Register all part models
|
||||
// FIXME for (PartType partType : PartType.values()) {
|
||||
// FIXME partModels.registerModels(partType.getModels());
|
||||
// FIXME }
|
||||
// Register the built-in models for annihilation planes
|
||||
Identifier fluidFormationPlaneTexture = new Identifier(AppEng.MOD_ID,
|
||||
"item/part/fluid_formation_plane");
|
||||
Identifier fluidFormationPlaneOnTexture = new Identifier(AppEng.MOD_ID,
|
||||
"parts/fluid_formation_plane_on");
|
||||
|
||||
// Register all part models
|
||||
// FIXME FABRIC for (PartType partType : PartType.values()) {
|
||||
// FIXME FABRIC partModels.registerModels(partType.getModels());
|
||||
// FIXME FABRIC }
|
||||
}
|
||||
|
||||
// FIXME private <T extends IPart> IItemDefinition createPart(FeatureFactory registry, String id, PartType type,
|
||||
// FIXME Function<ItemStack, T> factory) {
|
||||
// FIXME return registry.item(id, props -> new PartItem<>(props, type, factory)).itemGroup(CreativeTab.INSTANCE)
|
||||
// FIXME .rendering(new PartItemRendering()).build();
|
||||
// FIXME }
|
||||
// FIXME
|
||||
// FIXME private <T extends IPart> AEColoredItemDefinition constructColoredDefinition(FeatureFactory registry,
|
||||
// FIXME String idSuffix, PartType type, Function<ItemStack, T> factory) {
|
||||
// FIXME final ColoredItemDefinition definition = new ColoredItemDefinition();
|
||||
// FIXME
|
||||
// FIXME for (final AEColor color : AEColor.values()) {
|
||||
// FIXME String id = color.registryPrefix + '_' + idSuffix;
|
||||
// FIXME
|
||||
// FIXME IItemDefinition itemDef = registry.item(id, props -> new ColoredPartItem<>(props, type, factory, color))
|
||||
// FIXME .itemGroup(CreativeTab.INSTANCE).rendering(new PartItemRendering(color)).build();
|
||||
// FIXME
|
||||
// FIXME definition.add(color, new ItemStackSrc(itemDef.item(), ActivityState.Enabled));
|
||||
// FIXME }
|
||||
// FIXME
|
||||
// FIXME return definition;
|
||||
// FIXME }
|
||||
private <T extends IPart> IItemDefinition createPart(FeatureFactory registry, String id,
|
||||
Function<ItemStack, T> factory) {
|
||||
return registry.item(id, props -> new PartItem<>(props, factory)).itemGroup(CreativeTab.INSTANCE)
|
||||
.rendering(new PartItemRendering()).build();
|
||||
}
|
||||
|
||||
private <T extends IPart> AEColoredItemDefinition constructColoredDefinition(FeatureFactory registry,
|
||||
String idSuffix, Function<ItemStack, T> factory) {
|
||||
final ColoredItemDefinition definition = new ColoredItemDefinition();
|
||||
|
||||
for (final AEColor color : AEColor.values()) {
|
||||
String id = color.registryPrefix + '_' + idSuffix;
|
||||
|
||||
IItemDefinition itemDef = registry.item(id, props -> new ColoredPartItem<>(props, factory, color))
|
||||
.itemGroup(CreativeTab.INSTANCE).rendering(new PartItemRendering(color)).build();
|
||||
|
||||
definition.add(color, new ItemStackSrc(itemDef.item(), ActivityState.Enabled));
|
||||
}
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEColoredItemDefinition cableSmart() {
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import appeng.core.sync.packets.PartPlacementPacket;
|
||||
import appeng.core.sync.packets.SpawnEntityPacket;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
@@ -40,15 +41,13 @@ public class BasePacketHandler {
|
||||
// PACKET_ME_FLUID_INVENTORY_UPDATE(MEFluidInventoryUpdatePacket.class, MEFluidInventoryUpdatePacket::new),
|
||||
//
|
||||
// PACKET_CONFIG_BUTTON(ConfigButtonPacket.class, ConfigButtonPacket::new),
|
||||
//
|
||||
// PACKET_PART_PLACEMENT(PartPlacementPacket.class, PartPlacementPacket::new),
|
||||
//
|
||||
|
||||
PACKET_PART_PLACEMENT(PartPlacementPacket.class, PartPlacementPacket::new),
|
||||
|
||||
// PACKET_LIGHTNING(LightningPacket.class, LightningPacket::new),
|
||||
//
|
||||
// PACKET_MATTER_CANNON(MatterCannonPacket.class, MatterCannonPacket::new),
|
||||
//
|
||||
// PACKET_MOCK_EXPLOSION(MockExplosionPacket.class, MockExplosionPacket::new),
|
||||
//
|
||||
// PACKET_VALUE_CONFIG(ConfigValuePacket.class, ConfigValuePacket::new),
|
||||
//
|
||||
// PACKET_ITEM_TRANSITION_EFFECT(ItemTransitionEffectPacket.class, ItemTransitionEffectPacket::new),
|
||||
|
||||
@@ -21,6 +21,7 @@ public class ServerNetworkHandler implements NetworkHandler {
|
||||
private final ServerSidePacketRegistry registry = ServerSidePacketRegistry.INSTANCE;
|
||||
|
||||
public ServerNetworkHandler() {
|
||||
NetworkHandlerHolder.INSTANCE = this;
|
||||
registry.register(BasePacket.CHANNEL, this::handlePacketFromClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.particle.ParticleTypes;
|
||||
import net.fabricmc.api.EnvType;
|
||||
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
|
||||
public class MockExplosionPacket extends BasePacket {
|
||||
|
||||
private final double x;
|
||||
private final double y;
|
||||
private final double z;
|
||||
|
||||
public MockExplosionPacket(final PacketByteBuf stream) {
|
||||
this.x = stream.readDouble();
|
||||
this.y = stream.readDouble();
|
||||
this.z = stream.readDouble();
|
||||
}
|
||||
|
||||
// api
|
||||
public MockExplosionPacket(final double x, final double y, final double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
|
||||
final PacketByteBuf data = new PacketByteBuf(Unpooled.buffer());
|
||||
|
||||
data.writeInt(this.getPacketID());
|
||||
data.writeDouble(x);
|
||||
data.writeDouble(y);
|
||||
data.writeDouble(z);
|
||||
|
||||
this.configureWrite(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void clientPacketData(final INetworkInfo network, final PlayerEntity player) {
|
||||
player.world.addParticle(ParticleTypes.EXPLOSION, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
import appeng.parts.PartPlacement;
|
||||
|
||||
public class PartPlacementPacket extends BasePacket {
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
private int z;
|
||||
private int face;
|
||||
private float eyeHeight;
|
||||
private Hand hand;
|
||||
|
||||
public PartPlacementPacket(final PacketByteBuf stream) {
|
||||
this.x = stream.readInt();
|
||||
this.y = stream.readInt();
|
||||
this.z = stream.readInt();
|
||||
this.face = stream.readByte();
|
||||
this.eyeHeight = stream.readFloat();
|
||||
this.hand = Hand.values()[stream.readByte()];
|
||||
}
|
||||
|
||||
// api
|
||||
public PartPlacementPacket(final BlockPos pos, final Direction face, final float eyeHeight, final Hand hand) {
|
||||
final PacketByteBuf data = new PacketByteBuf(Unpooled.buffer());
|
||||
|
||||
data.writeInt(this.getPacketID());
|
||||
data.writeInt(pos.getX());
|
||||
data.writeInt(pos.getY());
|
||||
data.writeInt(pos.getZ());
|
||||
data.writeByte(face.ordinal());
|
||||
data.writeFloat(eyeHeight);
|
||||
data.writeByte(hand.ordinal());
|
||||
|
||||
this.configureWrite(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverPacketData(final INetworkInfo manager, final PlayerEntity player) {
|
||||
final ServerPlayerEntity sender = (ServerPlayerEntity) player;
|
||||
AppEng.instance().updateRenderMode(sender);
|
||||
PartPlacement.setEyeHeight(this.eyeHeight);
|
||||
PartPlacement.place(sender.getStackInHand(this.hand), new BlockPos(this.x, this.y, this.z),
|
||||
Direction.values()[this.face], sender, this.hand, sender.world,
|
||||
PartPlacement.PlaceType.INTERACT_FIRST_PASS, 0);
|
||||
AppEng.instance().updateRenderMode(null);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ public final class GrowingCrystalEntity extends AEBaseItemEntity {
|
||||
|
||||
if (this.progress_1000 >= len) {
|
||||
this.progress_1000 = 0;
|
||||
// FIXME FABRIC AppEng.proxy.spawnEffect(EffectType.Vibrant, this.world, this.getX(), this.getY() + 0.2,
|
||||
// FIXME FABRIC AppEng.instance().spawnEffect(EffectType.Vibrant, this.world, this.getX(), this.getY() + 0.2,
|
||||
// FIXME FABRIC this.getZ(), null);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.facade;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.parts.IFacadeContainer;
|
||||
import appeng.api.parts.IFacadePart;
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.items.parts.FacadeItem;
|
||||
import appeng.parts.CableBusStorage;
|
||||
|
||||
public class FacadeContainer implements IFacadeContainer {
|
||||
|
||||
private final int facades = 6;
|
||||
private final CableBusStorage storage;
|
||||
|
||||
public FacadeContainer(final CableBusStorage cbs) {
|
||||
this.storage = cbs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addFacade(final IFacadePart a) {
|
||||
if (this.getFacade(a.getSide()) == null) {
|
||||
this.storage.setFacade(a.getSide().ordinal(), a);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFacade(final IPartHost host, final AEPartLocation side) {
|
||||
if (side != null && side != AEPartLocation.INTERNAL) {
|
||||
if (this.storage.getFacade(side.ordinal()) != null) {
|
||||
this.storage.setFacade(side.ordinal(), null);
|
||||
if (host != null) {
|
||||
host.markForUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFacadePart getFacade(final AEPartLocation s) {
|
||||
return this.storage.getFacade(s.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rotateLeft() {
|
||||
final IFacadePart[] newFacades = new FacadePart[6];
|
||||
|
||||
newFacades[AEPartLocation.UP.ordinal()] = this.storage.getFacade(AEPartLocation.UP.ordinal());
|
||||
newFacades[AEPartLocation.DOWN.ordinal()] = this.storage.getFacade(AEPartLocation.DOWN.ordinal());
|
||||
|
||||
newFacades[AEPartLocation.EAST.ordinal()] = this.storage.getFacade(AEPartLocation.NORTH.ordinal());
|
||||
newFacades[AEPartLocation.SOUTH.ordinal()] = this.storage.getFacade(AEPartLocation.EAST.ordinal());
|
||||
|
||||
newFacades[AEPartLocation.WEST.ordinal()] = this.storage.getFacade(AEPartLocation.SOUTH.ordinal());
|
||||
newFacades[AEPartLocation.NORTH.ordinal()] = this.storage.getFacade(AEPartLocation.WEST.ordinal());
|
||||
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
this.storage.setFacade(x, newFacades[x]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag c) {
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
if (this.storage.getFacade(x) != null) {
|
||||
final CompoundTag data = new CompoundTag();
|
||||
this.storage.getFacade(x).getItemStack().toTag(data);
|
||||
c.put("facade:" + x, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readFromStream(final PacketByteBuf out) throws IOException {
|
||||
final int facadeSides = out.readByte();
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
final AEPartLocation side = AEPartLocation.fromOrdinal(x);
|
||||
final int ix = (1 << x);
|
||||
if ((facadeSides & ix) == ix) {
|
||||
final int id = Math.abs(out.readInt());
|
||||
|
||||
Optional<net.minecraft.item.Item> maybeFacadeItem = AEApi.instance().definitions().items().facade()
|
||||
.maybeItem();
|
||||
if (maybeFacadeItem.isPresent()) {
|
||||
final FacadeItem ifa = (FacadeItem) maybeFacadeItem.get();
|
||||
final ItemStack facade = ifa.createFromID(id);
|
||||
if (facade != null) {
|
||||
changed = changed || this.storage.getFacade(x) == null;
|
||||
this.storage.setFacade(x, ifa.createPartFromItemStack(facade, side));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
changed = changed || this.storage.getFacade(x) != null;
|
||||
this.storage.setFacade(x, null);
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag c) {
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
this.storage.setFacade(x, null);
|
||||
|
||||
final CompoundTag t = c.getCompound("facade:" + x);
|
||||
if (t != null) {
|
||||
final ItemStack is = ItemStack.fromTag(t);
|
||||
if (!is.isEmpty()) {
|
||||
final net.minecraft.item.Item i = is.getItem();
|
||||
if (i instanceof IFacadeItem) {
|
||||
this.storage.setFacade(x,
|
||||
((IFacadeItem) i).createPartFromItemStack(is, AEPartLocation.fromOrdinal(x)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToStream(final PacketByteBuf out) throws IOException {
|
||||
int facadeSides = 0;
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
if (this.getFacade(AEPartLocation.fromOrdinal(x)) != null) {
|
||||
facadeSides |= (1 << x);
|
||||
}
|
||||
}
|
||||
out.writeByte((byte) facadeSides);
|
||||
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
final IFacadePart part = this.getFacade(AEPartLocation.fromOrdinal(x));
|
||||
if (part != null) {
|
||||
final int itemID = Item.getRawId(part.getItem());
|
||||
out.writeInt(itemID * (part.notAEFacade() ? -1 : 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
if (this.storage.getFacade(x) != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.facade;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
|
||||
import appeng.api.parts.IFacadePart;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
|
||||
public class FacadePart implements IFacadePart {
|
||||
|
||||
private final ItemStack facade;
|
||||
private final AEPartLocation side;
|
||||
|
||||
public FacadePart(final ItemStack facade, final AEPartLocation side) {
|
||||
if (facade == null) {
|
||||
throw new IllegalArgumentException("Facade Part constructed on null item.");
|
||||
}
|
||||
this.facade = facade.copy();
|
||||
this.facade.setCount(1);
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack() {
|
||||
return this.facade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper ch, boolean livingEntity) {
|
||||
if (livingEntity) {
|
||||
// prevent weird snag behavior
|
||||
ch.addBox(0.0, 0.0, 14, 16.0, 16.0, 16.0);
|
||||
} else {
|
||||
// the box is 15.9 for transition planes to pick up collision events.
|
||||
ch.addBox(0.0, 0.0, 14, 16.0, 16.0, 15.9);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEPartLocation getSide() {
|
||||
return this.side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getItem() {
|
||||
final ItemStack is = this.getTextureItem();
|
||||
if (is.isEmpty()) {
|
||||
return Items.AIR;
|
||||
}
|
||||
return is.getItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notAEFacade() {
|
||||
return !(this.facade.getItem() instanceof IFacadeItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getTextureItem() {
|
||||
final Item maybeFacade = this.facade.getItem();
|
||||
|
||||
// AE Facade
|
||||
if (maybeFacade instanceof IFacadeItem) {
|
||||
final IFacadeItem facade = (IFacadeItem) maybeFacade;
|
||||
|
||||
return facade.getTextureItem(this.facade);
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState() {
|
||||
final Item maybeFacade = this.facade.getItem();
|
||||
|
||||
// AE Facade
|
||||
if (maybeFacade instanceof IFacadeItem) {
|
||||
final IFacadeItem facade = (IFacadeItem) maybeFacade;
|
||||
|
||||
return facade.getTextureBlockState(this.facade);
|
||||
}
|
||||
|
||||
return Blocks.GLASS.getDefaultState();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.facade;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.util.AEPartLocation;
|
||||
|
||||
public interface IFacadeItem {
|
||||
|
||||
FacadePart createPartFromItemStack(ItemStack is, AEPartLocation side);
|
||||
|
||||
ItemStack getTextureItem(ItemStack is);
|
||||
|
||||
BlockState getTextureBlockState(ItemStack is);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.helpers;
|
||||
|
||||
import appeng.api.implementations.tiles.IColorableTile;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.parts.IPartHost;
|
||||
|
||||
public interface AEMultiTile extends IGridHost, IPartHost, IColorableTile {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2018, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.integration.abstraction;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockView;
|
||||
|
||||
import team.chisel.ctm.api.IFacade;
|
||||
|
||||
/**
|
||||
* Neat abstraction class for All the IFacade interfaces.
|
||||
*
|
||||
* @author covers1624
|
||||
*/
|
||||
public interface IAEFacade extends IFacade {
|
||||
|
||||
BlockState getFacadeState(BlockView world, BlockPos pos, @Nullable Direction side);
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
default BlockState getFacade(@Nonnull BlockView world, @Nonnull BlockPos pos, @Nullable Direction side) {
|
||||
return getFacadeState(world, pos, side);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
default BlockState getFacade(@Nonnull BlockView world, @Nonnull BlockPos pos, @Nullable Direction side,
|
||||
@Nonnull BlockPos connection) {
|
||||
return getFacadeState(world, pos, side);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package appeng.items.parts;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.util.AEColor;
|
||||
|
||||
public class ColoredPartItem<T extends IPart> extends PartItem<T> {
|
||||
|
||||
private final AEColor color;
|
||||
|
||||
public ColoredPartItem(Settings properties, Function<ItemStack, T> factory, AEColor color) {
|
||||
super(properties, factory);
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public AEColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.items.parts;
|
||||
|
||||
import appeng.hooks.AEToolItem;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.api.EnvironmentInterface;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.RenderLayers;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tag.BlockTags;
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.world.EmptyBlockView;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.exceptions.MissingDefinitionException;
|
||||
import appeng.api.features.AEFeature;
|
||||
import appeng.api.parts.IAlphaPassItem;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.facade.FacadePart;
|
||||
import appeng.facade.IFacadeItem;
|
||||
import appeng.items.AEBaseItem;
|
||||
|
||||
@EnvironmentInterface(value = EnvType.CLIENT, itf=IAlphaPassItem.class)
|
||||
public class FacadeItem extends AEBaseItem implements IFacadeItem, IAlphaPassItem, AEToolItem {
|
||||
|
||||
/**
|
||||
* Block tag used to explicitly whitelist blocks for use in facades.
|
||||
*/
|
||||
private static final Identifier TAG_WHITELISTED = new Identifier(AppEng.MOD_ID, "whitelisted/facades");
|
||||
|
||||
private static final String NBT_ITEM_ID = "item";
|
||||
|
||||
public FacadeItem(Settings properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult onItemUseFirst(ItemStack stack, ItemUsageContext context) {
|
||||
return AEApi.instance().partHelper().placeBus(stack, context.getBlockPos(), context.getSide(), context.getPlayer(),
|
||||
context.getHand(), context.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getName(ItemStack is) {
|
||||
try {
|
||||
final ItemStack in = this.getTextureItem(is);
|
||||
if (!in.isEmpty()) {
|
||||
return super.getName(is).copy().append(" - ").append(in.getName());
|
||||
}
|
||||
} catch (final Throwable ignored) {
|
||||
|
||||
}
|
||||
|
||||
return super.getName(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendStacks(ItemGroup group, DefaultedList<ItemStack> items) {
|
||||
}
|
||||
|
||||
public ItemStack createFacadeForItem(final ItemStack itemStack, final boolean returnItem) {
|
||||
if (itemStack.isEmpty() || itemStack.hasTag() || !(itemStack.getItem() instanceof BlockItem)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
BlockItem blockItem = (BlockItem) itemStack.getItem();
|
||||
Block block = blockItem.getBlock();
|
||||
if (block == Blocks.AIR) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
// We only support the default state for facades. Sorry.
|
||||
BlockState blockState = block.getDefaultState();
|
||||
|
||||
final boolean areTileEntitiesEnabled = AEConfig.instance().isFeatureEnabled(AEFeature.TILE_ENTITY_FACADES);
|
||||
Tag<Block> whitelistTag = BlockTags.getContainer().getOrCreate(TAG_WHITELISTED);
|
||||
final boolean isWhiteListed = block.isIn(whitelistTag);
|
||||
final boolean isModel = blockState.getRenderType() == BlockRenderType.MODEL;
|
||||
|
||||
final BlockState defaultState = block.getDefaultState();
|
||||
final boolean isTileEntity = block.hasBlockEntity();
|
||||
final boolean isFullCube = defaultState.isOpaqueFullCube(EmptyBlockView.INSTANCE, BlockPos.ORIGIN);
|
||||
|
||||
final boolean isTileEntityAllowed = !isTileEntity || (areTileEntitiesEnabled && isWhiteListed);
|
||||
final boolean isBlockAllowed = isFullCube || isWhiteListed;
|
||||
|
||||
if (isModel && isTileEntityAllowed && isBlockAllowed) {
|
||||
if (returnItem) {
|
||||
return itemStack;
|
||||
}
|
||||
|
||||
final ItemStack is = new ItemStack(this);
|
||||
final CompoundTag data = new CompoundTag();
|
||||
Identifier itemId = Registry.ITEM.getId(itemStack.getItem());
|
||||
data.putString(NBT_ITEM_ID, itemId.toString());
|
||||
is.setTag(data);
|
||||
return is;
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacadePart createPartFromItemStack(final ItemStack is, final AEPartLocation side) {
|
||||
final ItemStack in = this.getTextureItem(is);
|
||||
if (!in.isEmpty()) {
|
||||
return new FacadePart(is, side);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getTextureItem(ItemStack is) {
|
||||
CompoundTag nbt = is.getTag();
|
||||
|
||||
if (nbt == null) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
Identifier itemId = new Identifier(nbt.getString(NBT_ITEM_ID));
|
||||
Item baseItem = Registry.ITEM.getOrEmpty(itemId).orElse(null);
|
||||
|
||||
if (baseItem == null) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
return new ItemStack(baseItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getTextureBlockState(ItemStack is) {
|
||||
|
||||
ItemStack baseItemStack = this.getTextureItem(is);
|
||||
|
||||
if (baseItemStack.isEmpty()) {
|
||||
return Blocks.GLASS.getDefaultState();
|
||||
}
|
||||
|
||||
Block block = Block.getBlockFromItem(baseItemStack.getItem());
|
||||
|
||||
if (block == Blocks.AIR) {
|
||||
return Blocks.GLASS.getDefaultState();
|
||||
}
|
||||
|
||||
return block.getDefaultState();
|
||||
}
|
||||
|
||||
public ItemStack createFromID(final int id) {
|
||||
ItemStack facadeStack = AEApi.instance().definitions().items().facade().maybeStack(1).orElseThrow(
|
||||
() -> new MissingDefinitionException("Tried to create a facade, while facades are being deactivated."));
|
||||
|
||||
// Convert back to a registry name...
|
||||
Item item = Registry.ITEM.get(id);
|
||||
if (item == Items.AIR) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
Identifier longId = Registry.ITEM.getId(item);
|
||||
|
||||
final CompoundTag facadeTag = new CompoundTag();
|
||||
facadeTag.putString(NBT_ITEM_ID, longId.toString());
|
||||
facadeStack.setTag(facadeTag);
|
||||
|
||||
return facadeStack;
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Override
|
||||
public boolean useAlphaPass(final ItemStack is) {
|
||||
BlockState blockState = this.getTextureBlockState(is);
|
||||
|
||||
if (blockState == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return RenderLayers.getBlockLayer(blockState) == RenderLayer.getTranslucent()
|
||||
|| RenderLayers.getBlockLayer(blockState) == RenderLayer.getTranslucentNoCrumbling();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.items.parts;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemUsageContext;
|
||||
import net.minecraft.util.ActionResult;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.parts.IPartItem;
|
||||
import appeng.items.AEBaseItem;
|
||||
|
||||
public class PartItem<T extends IPart> extends AEBaseItem implements IPartItem<T> {
|
||||
|
||||
private final Function<ItemStack, T> factory;
|
||||
|
||||
public PartItem(Settings properties, Function<ItemStack, T> factory) {
|
||||
super(properties);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult useOnBlock(ItemUsageContext context) {
|
||||
PlayerEntity player = context.getPlayer();
|
||||
ItemStack held = player.getStackInHand(context.getHand());
|
||||
if (held.getItem() != this) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
return AEApi.instance().partHelper().placeBus(held, context.getBlockPos(), context.getSide(), player,
|
||||
context.getHand(), context.getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T createPart(ItemStack is) {
|
||||
return factory.apply(is);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.items.parts;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.bootstrap.IItemRendering;
|
||||
import appeng.bootstrap.ItemRenderingCustomizer;
|
||||
import appeng.client.render.StaticItemColor;
|
||||
|
||||
public class PartItemRendering extends ItemRenderingCustomizer {
|
||||
|
||||
private final AEColor color;
|
||||
|
||||
public PartItemRendering() {
|
||||
this.color = AEColor.TRANSPARENT;
|
||||
}
|
||||
|
||||
public PartItemRendering(AEColor color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void customize(IItemRendering rendering) {
|
||||
rendering.color(new StaticItemColor(color));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.items.parts;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This annotation is used to mark static fields or static methods that
|
||||
* return/contain models used for a part. They are automatically registered as
|
||||
* part of the part item registration.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD })
|
||||
public @interface PartModels {
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
|
||||
package appeng.items.parts;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.core.AELog;
|
||||
|
||||
/**
|
||||
* Helps with the reflection magic needed to gather all models for AE2 cable bus
|
||||
* parts.
|
||||
*/
|
||||
public class PartModelsHelper {
|
||||
|
||||
public static List<Identifier> createModels(Class<?> clazz) {
|
||||
List<Identifier> locations = new ArrayList<>();
|
||||
|
||||
// Check all static fields for used models
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (field.getAnnotation(PartModels.class) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Modifier.isStatic(field.getModifiers())) {
|
||||
AELog.error("The @PartModels annotation can only be used on static fields or methods. Was seen on: "
|
||||
+ field);
|
||||
continue;
|
||||
}
|
||||
|
||||
Object value;
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
value = field.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
AELog.error(e, "Cannot access field annotated with @PartModels: " + field);
|
||||
continue;
|
||||
}
|
||||
|
||||
convertAndAddLocation(field, value, locations);
|
||||
}
|
||||
|
||||
// Check all static methods for the annotation
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.getAnnotation(PartModels.class) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
AELog.error("The @PartModels annotation can only be used on static fields or methods. Was seen on: "
|
||||
+ method);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for parameter count
|
||||
if (method.getParameters().length != 0) {
|
||||
AELog.error(
|
||||
"The @PartModels annotation can only be used on static methods without parameters. Was seen on: "
|
||||
+ method);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure we can handle the return type
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (!Identifier.class.isAssignableFrom(returnType)
|
||||
&& !Collection.class.isAssignableFrom(returnType)) {
|
||||
AELog.error(
|
||||
"The @PartModels annotation can only be used on static methods that return a ResourceLocation or Collection of "
|
||||
+ "ResourceLocations. Was seen on: " + method);
|
||||
continue;
|
||||
}
|
||||
|
||||
Object value;
|
||||
try {
|
||||
method.setAccessible(true);
|
||||
value = method.invoke(null);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
AELog.error(e, "Failed to invoke the @PartModels annotated method " + method);
|
||||
continue;
|
||||
}
|
||||
|
||||
convertAndAddLocation(method, value, locations);
|
||||
}
|
||||
|
||||
if (clazz.getSuperclass() != null) {
|
||||
locations.addAll(createModels(clazz.getSuperclass()));
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
private static void convertAndAddLocation(Object source, Object value, List<Identifier> locations) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value instanceof Identifier) {
|
||||
locations.add((Identifier) value);
|
||||
} else if (value instanceof IPartModel) {
|
||||
locations.addAll(((IPartModel) value).getModels());
|
||||
} else if (value instanceof Collection) {
|
||||
// Check that each object is an IPartModel
|
||||
Collection<?> values = (Collection<?>) value;
|
||||
for (Object candidate : values) {
|
||||
if (!(candidate instanceof IPartModel)) {
|
||||
AELog.error("List of locations obtained from {} contains a non resource location: {}", source,
|
||||
candidate);
|
||||
continue;
|
||||
}
|
||||
|
||||
locations.addAll(((IPartModel) candidate).getModels());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package appeng.me.cache;
|
||||
|
||||
import appeng.api.networking.IGridCache;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.IGridStorage;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
// FIXME FABRIC DUMMY
|
||||
public class P2PCache implements IGridCache {
|
||||
@Override
|
||||
public void onUpdateTick() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNode(@Nonnull IGridNode gridNode, @Nonnull IGridHost machine) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNode(@Nonnull IGridNode gridNode, @Nonnull IGridHost machine) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplit(@Nonnull IGridStorage destinationStorage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onJoin(@Nonnull IGridStorage sourceStorage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateGridStorage(@Nonnull IGridStorage destinationStorage) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.me.helpers;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.GridNotification;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridBlock;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.crafting.ICraftingGrid;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.events.MENetworkPowerIdleChange;
|
||||
import appeng.api.networking.pathing.IPathingGrid;
|
||||
import appeng.api.networking.security.ISecurityGrid;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.networking.ticking.ITickManager;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IOrientable;
|
||||
import appeng.core.worlddata.WorldData;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.cache.P2PCache;
|
||||
import appeng.parts.networking.CablePart;
|
||||
import appeng.tile.AEBaseBlockEntity;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class AENetworkProxy implements IGridBlock {
|
||||
|
||||
private final IGridProxyable gp;
|
||||
private final boolean worldNode;
|
||||
private final String nbtName; // name
|
||||
private AEColor myColor = AEColor.TRANSPARENT;
|
||||
private CompoundTag data = null; // input
|
||||
private ItemStack myRepInstance = ItemStack.EMPTY;
|
||||
private boolean isReady = false;
|
||||
private IGridNode node = null;
|
||||
private EnumSet<Direction> validSides;
|
||||
private EnumSet<GridFlags> flags = EnumSet.noneOf(GridFlags.class);
|
||||
private double idleDraw = 1.0;
|
||||
private PlayerEntity owner;
|
||||
|
||||
public AENetworkProxy(final IGridProxyable te, final String nbtName, final ItemStack visual,
|
||||
final boolean inWorld) {
|
||||
this.gp = te;
|
||||
this.nbtName = nbtName;
|
||||
this.worldNode = inWorld;
|
||||
this.myRepInstance = visual;
|
||||
this.validSides = EnumSet.allOf(Direction.class);
|
||||
}
|
||||
|
||||
public void setVisualRepresentation(final ItemStack is) {
|
||||
this.myRepInstance = is;
|
||||
}
|
||||
|
||||
public void writeToNBT(final CompoundTag tag) {
|
||||
if (this.node != null) {
|
||||
this.node.saveToNBT(this.nbtName, tag);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValidSides(final EnumSet<Direction> validSides) {
|
||||
this.validSides = validSides;
|
||||
if (this.node != null) {
|
||||
this.node.updateState();
|
||||
}
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
if (this.gp instanceof AEBaseBlockEntity) {
|
||||
TickHandler.INSTANCE.addInit((AEBaseBlockEntity) this.gp);
|
||||
}
|
||||
}
|
||||
|
||||
public void onChunkUnloaded() {
|
||||
this.isReady = false;
|
||||
this.remove();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
this.isReady = false;
|
||||
if (this.node != null) {
|
||||
this.node.destroy();
|
||||
this.node = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void onReady() {
|
||||
this.isReady = true;
|
||||
|
||||
// send orientation based directionality to the node.
|
||||
if (this.gp instanceof IOrientable) {
|
||||
final IOrientable ori = (IOrientable) this.gp;
|
||||
if (ori.canBeRotated()) {
|
||||
ori.setOrientation(ori.getForward(), ori.getUp());
|
||||
}
|
||||
}
|
||||
|
||||
this.getNode();
|
||||
}
|
||||
|
||||
public IGridNode getNode() {
|
||||
if (this.node == null && Platform.isServer() && this.isReady) {
|
||||
this.node = AEApi.instance().grid().createGridNode(this);
|
||||
this.readFromNBT(this.data);
|
||||
this.node.updateState();
|
||||
}
|
||||
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public void readFromNBT(final CompoundTag tag) {
|
||||
this.data = tag;
|
||||
if (this.node != null && this.data != null) {
|
||||
this.node.loadFromNBT(this.nbtName, this.data);
|
||||
this.data = null;
|
||||
} else if (this.node != null && this.owner != null) {
|
||||
final GameProfile profile = this.owner.getGameProfile();
|
||||
final int playerID = WorldData.instance().playerData().getMePlayerId(profile);
|
||||
|
||||
this.node.setPlayerID(playerID);
|
||||
this.owner = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IPathingGrid getPath() throws GridAccessException {
|
||||
final IGrid grid = this.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
final IPathingGrid pg = grid.getCache(IPathingGrid.class);
|
||||
if (pg == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
return pg;
|
||||
}
|
||||
|
||||
/**
|
||||
* short cut!
|
||||
*
|
||||
* @return grid of node
|
||||
*
|
||||
* @throws GridAccessException of node or grid is null
|
||||
*/
|
||||
public IGrid getGrid() throws GridAccessException {
|
||||
if (this.node == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
final IGrid grid = this.node.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
return grid;
|
||||
}
|
||||
|
||||
public ITickManager getTick() throws GridAccessException {
|
||||
final IGrid grid = this.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
final ITickManager pg = grid.getCache(ITickManager.class);
|
||||
if (pg == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
return pg;
|
||||
}
|
||||
|
||||
public IStorageGrid getStorage() throws GridAccessException {
|
||||
final IGrid grid = this.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
final IStorageGrid pg = grid.getCache(IStorageGrid.class);
|
||||
|
||||
if (pg == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
return pg;
|
||||
}
|
||||
|
||||
public P2PCache getP2P() throws GridAccessException {
|
||||
final IGrid grid = this.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
final P2PCache pg = grid.getCache(P2PCache.class);
|
||||
|
||||
if (pg == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
return pg;
|
||||
}
|
||||
|
||||
public ISecurityGrid getSecurity() throws GridAccessException {
|
||||
final IGrid grid = this.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
final ISecurityGrid sg = grid.getCache(ISecurityGrid.class);
|
||||
|
||||
if (sg == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
public ICraftingGrid getCrafting() throws GridAccessException {
|
||||
final IGrid grid = this.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
final ICraftingGrid sg = grid.getCache(ICraftingGrid.class);
|
||||
|
||||
if (sg == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
|
||||
return sg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getIdlePowerUsage() {
|
||||
return this.idleDraw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<GridFlags> getFlags() {
|
||||
return this.flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorldAccessible() {
|
||||
return this.worldNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getLocation() {
|
||||
return this.gp.getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEColor getGridColor() {
|
||||
return this.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGridNotification(final GridNotification notification) {
|
||||
if (this.gp instanceof CablePart) {
|
||||
((CablePart) this.gp).markForUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetworkStatus(final IGrid grid, final int channelsInUse) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<Direction> getConnectableSides() {
|
||||
return this.validSides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridHost getMachine() {
|
||||
return this.gp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gridChanged() {
|
||||
this.gp.gridChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getMachineRepresentation() {
|
||||
return this.myRepInstance;
|
||||
}
|
||||
|
||||
public void setFlags(final GridFlags... requireChannel) {
|
||||
final EnumSet<GridFlags> flags = EnumSet.noneOf(GridFlags.class);
|
||||
|
||||
Collections.addAll(flags, requireChannel);
|
||||
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public void setIdlePowerUsage(final double idle) {
|
||||
this.idleDraw = idle;
|
||||
|
||||
if (this.node != null) {
|
||||
try {
|
||||
final IGrid g = this.getGrid();
|
||||
g.postEvent(new MENetworkPowerIdleChange(this.node));
|
||||
} catch (final GridAccessException e) {
|
||||
// not ready for this yet..
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return this.isReady;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
if (this.node == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.node.isActive();
|
||||
}
|
||||
|
||||
public boolean isPowered() {
|
||||
try {
|
||||
return this.getEnergy().isNetworkPowered();
|
||||
} catch (final GridAccessException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnergyGrid getEnergy() throws GridAccessException {
|
||||
final IGrid grid = this.getGrid();
|
||||
if (grid == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
final IEnergyGrid eg = grid.getCache(IEnergyGrid.class);
|
||||
if (eg == null) {
|
||||
throw new GridAccessException();
|
||||
}
|
||||
return eg;
|
||||
}
|
||||
|
||||
public void setOwner(final PlayerEntity player) {
|
||||
this.owner = player;
|
||||
}
|
||||
|
||||
public AEColor getColor() {
|
||||
return this.myColor;
|
||||
}
|
||||
|
||||
public void setColor(final AEColor myColor) {
|
||||
this.myColor = myColor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.crash.CrashReportSection;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
import net.fabricmc.api.Environment;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.definitions.IDefinitions;
|
||||
import appeng.api.implementations.IUpgradeableHost;
|
||||
import appeng.api.implementations.items.IMemoryCard;
|
||||
import appeng.api.implementations.items.MemoryCardMessages;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.parts.BusSupport;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.parts.PartItemStack;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.api.util.IConfigManager;
|
||||
import appeng.helpers.ICustomNameObject;
|
||||
import appeng.helpers.IPriorityHost;
|
||||
import appeng.me.helpers.AENetworkProxy;
|
||||
import appeng.me.helpers.IGridProxyable;
|
||||
import appeng.parts.networking.CablePart;
|
||||
import appeng.tile.inventory.AppEngInternalAEInventory;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.SettingsFrom;
|
||||
|
||||
public abstract class AEBasePart implements IPart, IGridProxyable, IActionHost, IUpgradeableHost, ICustomNameObject {
|
||||
|
||||
private final AENetworkProxy proxy;
|
||||
private final ItemStack is;
|
||||
private BlockEntity tile = null;
|
||||
private IPartHost host = null;
|
||||
private AEPartLocation side = null;
|
||||
|
||||
public AEBasePart(final ItemStack is) {
|
||||
Preconditions.checkNotNull(is);
|
||||
|
||||
this.is = is;
|
||||
this.proxy = new AENetworkProxy(this, "part", is, this instanceof CablePart);
|
||||
this.proxy.setValidSides(EnumSet.noneOf(Direction.class));
|
||||
}
|
||||
|
||||
public IPartHost getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getGridNode(final AEPartLocation dir) {
|
||||
return this.proxy.getNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType(final AEPartLocation dir) {
|
||||
return AECableType.GLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void securityBreak() {
|
||||
if (this.getItemStack().getCount() > 0 && this.getGridNode() != null) {
|
||||
final List<ItemStack> items = new ArrayList<>();
|
||||
items.add(this.is.copy());
|
||||
this.host.removePart(this.side, false);
|
||||
Platform.spawnDrops(this.tile.getWorld(), this.tile.getPos(), items);
|
||||
this.is.setCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected AEColor getColor() {
|
||||
if (this.host == null) {
|
||||
return AEColor.TRANSPARENT;
|
||||
}
|
||||
return this.host.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstalledUpgrades(final Upgrades u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity getTile() {
|
||||
return this.tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AENetworkProxy getProxy() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getLocation() {
|
||||
return new DimensionalCoord(this.tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gridChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getActionableNode() {
|
||||
return this.proxy.getNode();
|
||||
}
|
||||
|
||||
public void saveChanges() {
|
||||
this.host.markForSave();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getCustomInventoryName() {
|
||||
return this.getItemStack().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInventoryName() {
|
||||
return this.getItemStack().hasCustomName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntityCrashInfo(final CrashReportSection section) {
|
||||
section.add("Part Side", this.getSide());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(final PartItemStack type) {
|
||||
if (type == PartItemStack.NETWORK) {
|
||||
final ItemStack copy = this.is.copy();
|
||||
copy.setTag(null);
|
||||
return copy;
|
||||
}
|
||||
return this.is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConnectRedstone() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag data) {
|
||||
this.proxy.readFromNBT(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
this.proxy.writeToNBT(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingStrongPower() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingWeakPower() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToStream(final PacketByteBuf data) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readFromStream(final PacketByteBuf data) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getGridNode() {
|
||||
return this.proxy.getNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollision(final Entity entity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromWorld() {
|
||||
this.proxy.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToWorld() {
|
||||
this.proxy.onReady();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPartHostInfo(final AEPartLocation side, final IPartHost host, final BlockEntity tile) {
|
||||
this.setSide(side);
|
||||
this.tile = tile;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getExternalFacingNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void randomDisplayTick(final World world, final BlockPos pos, final Random r) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDrops(final List<ItemStack> drops, final boolean wrenched) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLadder(final LivingEntity entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConfigManager getConfigManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FixedItemInv getInventoryByName(final String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* depending on the from, different settings will be accepted, don't call this
|
||||
* with null
|
||||
*
|
||||
* @param from source of settings
|
||||
* @param compound compound of source
|
||||
*/
|
||||
private void uploadSettings(final SettingsFrom from, final CompoundTag compound) {
|
||||
if (compound != null) {
|
||||
final IConfigManager cm = this.getConfigManager();
|
||||
if (cm != null) {
|
||||
cm.readFromNBT(compound);
|
||||
}
|
||||
}
|
||||
|
||||
if (this instanceof IPriorityHost) {
|
||||
final IPriorityHost pHost = (IPriorityHost) this;
|
||||
pHost.setPriority(compound.getInt("priority"));
|
||||
}
|
||||
|
||||
final FixedItemInv inv = this.getInventoryByName("config");
|
||||
if (inv instanceof AppEngInternalAEInventory) {
|
||||
final AppEngInternalAEInventory target = (AppEngInternalAEInventory) inv;
|
||||
final AppEngInternalAEInventory tmp = new AppEngInternalAEInventory(null, target.getSlotCount());
|
||||
tmp.readFromNBT(compound, "config");
|
||||
for (int x = 0; x < tmp.getSlotCount(); x++) {
|
||||
target.forceSetInvStack(x, tmp.getInvStack(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* null means nothing to store...
|
||||
*
|
||||
* @param from source of settings
|
||||
*
|
||||
* @return compound of source
|
||||
*/
|
||||
private CompoundTag downloadSettings(final SettingsFrom from) {
|
||||
final CompoundTag output = new CompoundTag();
|
||||
|
||||
final IConfigManager cm = this.getConfigManager();
|
||||
if (cm != null) {
|
||||
cm.writeToNBT(output);
|
||||
}
|
||||
|
||||
if (this instanceof IPriorityHost) {
|
||||
final IPriorityHost pHost = (IPriorityHost) this;
|
||||
output.putInt("priority", pHost.getPriority());
|
||||
}
|
||||
|
||||
final FixedItemInv inv = this.getInventoryByName("config");
|
||||
if (inv instanceof AppEngInternalAEInventory) {
|
||||
((AppEngInternalAEInventory) inv).writeToNBT(output, "config");
|
||||
}
|
||||
|
||||
return output.isEmpty() ? null : output;
|
||||
}
|
||||
|
||||
public boolean useStandardMemoryCard() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean useMemoryCard(final PlayerEntity player) {
|
||||
final ItemStack memCardIS = player.inventory.getMainHandStack();
|
||||
|
||||
if (!memCardIS.isEmpty() && this.useStandardMemoryCard() && memCardIS.getItem() instanceof IMemoryCard) {
|
||||
final IMemoryCard memoryCard = (IMemoryCard) memCardIS.getItem();
|
||||
|
||||
ItemStack is = this.getItemStack(PartItemStack.NETWORK);
|
||||
|
||||
// Blocks and parts share the same soul!
|
||||
final IDefinitions definitions = AEApi.instance().definitions();
|
||||
if (definitions.parts().iface().isSameAs(is)) {
|
||||
Optional<ItemStack> iface = definitions.blocks().iface().maybeStack(1);
|
||||
if (iface.isPresent()) {
|
||||
is = iface.get();
|
||||
}
|
||||
}
|
||||
|
||||
final String name = is.getTranslationKey();
|
||||
|
||||
if (player.isInSneakingPose()) {
|
||||
final CompoundTag data = this.downloadSettings(SettingsFrom.MEMORY_CARD);
|
||||
if (data != null) {
|
||||
memoryCard.setMemoryCardContents(memCardIS, name, data);
|
||||
memoryCard.notifyUser(player, MemoryCardMessages.SETTINGS_SAVED);
|
||||
}
|
||||
} else {
|
||||
final String storedName = memoryCard.getSettingsName(memCardIS);
|
||||
final CompoundTag data = memoryCard.getData(memCardIS);
|
||||
if (name.equals(storedName)) {
|
||||
this.uploadSettings(SettingsFrom.MEMORY_CARD, data);
|
||||
memoryCard.notifyUser(player, MemoryCardMessages.SETTINGS_LOADED);
|
||||
} else {
|
||||
memoryCard.notifyUser(player, MemoryCardMessages.INVALID_MACHINE);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
if (this.useMemoryCard(player)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.onPartActivate(player, hand, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onShiftActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
if (this.useMemoryCard(player)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.onPartShiftActivate(player, hand, pos);
|
||||
}
|
||||
|
||||
public boolean onPartActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPartShiftActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlacement(final PlayerEntity player, final Hand hand, final ItemStack held,
|
||||
final AEPartLocation side) {
|
||||
this.proxy.setOwner(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBePlacedOn(final BusSupport what) {
|
||||
return what == BusSupport.CABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requireDynamicRender() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public AEPartLocation getSide() {
|
||||
return this.side;
|
||||
}
|
||||
|
||||
private void setSide(final AEPartLocation side) {
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
public ItemStack getItemStack() {
|
||||
return this.is;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
|
||||
public class BusCollisionHelper implements IPartCollisionHelper {
|
||||
|
||||
private final List<Box> boxes;
|
||||
|
||||
private final Direction x;
|
||||
private final Direction y;
|
||||
private final Direction z;
|
||||
|
||||
private final boolean isVisual;
|
||||
|
||||
public BusCollisionHelper(final List<Box> boxes, final Direction x, final Direction y, final Direction z,
|
||||
final boolean visual) {
|
||||
this.boxes = boxes;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.isVisual = visual;
|
||||
}
|
||||
|
||||
public BusCollisionHelper(final List<Box> boxes, final AEPartLocation s, final boolean visual) {
|
||||
this.boxes = boxes;
|
||||
this.isVisual = visual;
|
||||
|
||||
switch (s) {
|
||||
case DOWN:
|
||||
this.x = Direction.EAST;
|
||||
this.y = Direction.NORTH;
|
||||
this.z = Direction.DOWN;
|
||||
break;
|
||||
case UP:
|
||||
this.x = Direction.EAST;
|
||||
this.y = Direction.SOUTH;
|
||||
this.z = Direction.UP;
|
||||
break;
|
||||
case EAST:
|
||||
this.x = Direction.SOUTH;
|
||||
this.y = Direction.UP;
|
||||
this.z = Direction.EAST;
|
||||
break;
|
||||
case WEST:
|
||||
this.x = Direction.NORTH;
|
||||
this.y = Direction.UP;
|
||||
this.z = Direction.WEST;
|
||||
break;
|
||||
case NORTH:
|
||||
this.x = Direction.WEST;
|
||||
this.y = Direction.UP;
|
||||
this.z = Direction.NORTH;
|
||||
break;
|
||||
case SOUTH:
|
||||
this.x = Direction.EAST;
|
||||
this.y = Direction.UP;
|
||||
this.z = Direction.SOUTH;
|
||||
break;
|
||||
case INTERNAL:
|
||||
default:
|
||||
this.x = Direction.EAST;
|
||||
this.y = Direction.UP;
|
||||
this.z = Direction.SOUTH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
minX /= 16.0;
|
||||
minY /= 16.0;
|
||||
minZ /= 16.0;
|
||||
maxX /= 16.0;
|
||||
maxY /= 16.0;
|
||||
maxZ /= 16.0;
|
||||
|
||||
double aX = minX * this.x.getOffsetX() + minY * this.y.getOffsetX() + minZ * this.z.getOffsetX();
|
||||
double aY = minX * this.x.getOffsetY() + minY * this.y.getOffsetY() + minZ * this.z.getOffsetY();
|
||||
double aZ = minX * this.x.getOffsetZ() + minY * this.y.getOffsetZ() + minZ * this.z.getOffsetZ();
|
||||
|
||||
double bX = maxX * this.x.getOffsetX() + maxY * this.y.getOffsetX() + maxZ * this.z.getOffsetX();
|
||||
double bY = maxX * this.x.getOffsetY() + maxY * this.y.getOffsetY() + maxZ * this.z.getOffsetY();
|
||||
double bZ = maxX * this.x.getOffsetZ() + maxY * this.y.getOffsetZ() + maxZ * this.z.getOffsetZ();
|
||||
|
||||
if (this.x.getOffsetX() + this.y.getOffsetX() + this.z.getOffsetX() < 0) {
|
||||
aX += 1;
|
||||
bX += 1;
|
||||
}
|
||||
|
||||
if (this.x.getOffsetY() + this.y.getOffsetY() + this.z.getOffsetY() < 0) {
|
||||
aY += 1;
|
||||
bY += 1;
|
||||
}
|
||||
|
||||
if (this.x.getOffsetZ() + this.y.getOffsetZ() + this.z.getOffsetZ() < 0) {
|
||||
aZ += 1;
|
||||
bZ += 1;
|
||||
}
|
||||
|
||||
minX = Math.min(aX, bX);
|
||||
minY = Math.min(aY, bY);
|
||||
minZ = Math.min(aZ, bZ);
|
||||
maxX = Math.max(aX, bX);
|
||||
maxY = Math.max(aY, bY);
|
||||
maxZ = Math.max(aZ, bZ);
|
||||
|
||||
this.boxes.add(new Box(minX, minY, minZ, maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getWorldX() {
|
||||
return this.x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getWorldY() {
|
||||
return this.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getWorldZ() {
|
||||
return this.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBBCollision() {
|
||||
return !this.isVisual;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import appeng.api.implementations.parts.ICablePart;
|
||||
import appeng.api.parts.IFacadePart;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
|
||||
/**
|
||||
* Thin data storage to optimize memory usage for cables.
|
||||
*/
|
||||
public class CableBusStorage {
|
||||
|
||||
private ICablePart center;
|
||||
private IPart[] sides;
|
||||
private IFacadePart[] facades;
|
||||
|
||||
protected ICablePart getCenter() {
|
||||
return this.center;
|
||||
}
|
||||
|
||||
protected void setCenter(final ICablePart center) {
|
||||
this.center = center;
|
||||
}
|
||||
|
||||
protected IPart getSide(final AEPartLocation side) {
|
||||
final int x = side.ordinal();
|
||||
if (this.sides != null && this.sides.length > x) {
|
||||
return this.sides[x];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void setSide(final AEPartLocation side, final IPart part) {
|
||||
final int x = side.ordinal();
|
||||
|
||||
if (this.sides != null && this.sides.length > x && part == null) {
|
||||
this.sides[x] = null;
|
||||
this.sides = this.shrink(this.sides, true);
|
||||
} else if (part != null) {
|
||||
this.sides = this.grow(this.sides, x, true);
|
||||
this.sides[x] = part;
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T[] shrink(final T[] in, final boolean parts) {
|
||||
int newSize = -1;
|
||||
for (int x = 0; x < in.length; x++) {
|
||||
if (in[x] != null) {
|
||||
newSize = x;
|
||||
}
|
||||
}
|
||||
|
||||
if (newSize == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
newSize++;
|
||||
if (newSize == in.length) {
|
||||
return in;
|
||||
}
|
||||
|
||||
final T[] newArray = (T[]) (parts ? new IPart[newSize] : new IFacadePart[newSize]);
|
||||
System.arraycopy(in, 0, newArray, 0, newSize);
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private <T> T[] grow(final T[] in, final int newValue, final boolean parts) {
|
||||
if (in != null && in.length > newValue) {
|
||||
return in;
|
||||
}
|
||||
|
||||
final int newSize = newValue + 1;
|
||||
|
||||
final T[] newArray = (T[]) (parts ? new IPart[newSize] : new IFacadePart[newSize]);
|
||||
if (in != null) {
|
||||
System.arraycopy(in, 0, newArray, 0, in.length);
|
||||
}
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
public IFacadePart getFacade(final int x) {
|
||||
if (this.facades != null && this.facades.length > x) {
|
||||
return this.facades[x];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setFacade(final int x, @Nullable final IFacadePart facade) {
|
||||
if (this.facades != null && this.facades.length > x && facade == null) {
|
||||
this.facades[x] = null;
|
||||
this.facades = this.shrink(this.facades, false);
|
||||
} else {
|
||||
this.facades = this.grow(this.facades, x, false);
|
||||
this.facades[x] = facade;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Random;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
import net.fabricmc.api.Environment;
|
||||
|
||||
import appeng.api.parts.SelectedPart;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.client.render.cablebus.CableBusRenderState;
|
||||
|
||||
public interface ICableBusContainer {
|
||||
|
||||
int isProvidingStrongPower(Direction opposite);
|
||||
|
||||
int isProvidingWeakPower(Direction opposite);
|
||||
|
||||
boolean canConnectRedstone(EnumSet<Direction> of);
|
||||
|
||||
void onEntityCollision(Entity e);
|
||||
|
||||
boolean activate(PlayerEntity player, Hand hand, Vec3d vecFromPool);
|
||||
|
||||
boolean clicked(PlayerEntity player, Hand hand, Vec3d hitVec);
|
||||
|
||||
void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor);
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
SelectedPart selectPart(Vec3d v3);
|
||||
|
||||
boolean recolourBlock(Direction side, AEColor colour, PlayerEntity who);
|
||||
|
||||
boolean isLadder(LivingEntity entity);
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
void randomDisplayTick(World world, BlockPos pos, Random r);
|
||||
|
||||
int getLightValue();
|
||||
|
||||
CableBusRenderState getRenderState();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.parts.SelectedPart;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.client.render.cablebus.CableBusRenderState;
|
||||
|
||||
public class NullCableBusContainer implements ICableBusContainer {
|
||||
|
||||
@Override
|
||||
public int isProvidingStrongPower(final Direction opposite) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingWeakPower(final Direction opposite) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConnectRedstone(final EnumSet<Direction> of) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollision(final Entity e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean activate(final PlayerEntity player, final Hand hand, final Vec3d vecFromPool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectedPart selectPart(final Vec3d v3) {
|
||||
return new SelectedPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recolourBlock(final Direction side, final AEColor colour, final PlayerEntity who) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLadder(final LivingEntity entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(final World world, final BlockPos pos, final Random r) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CableBusRenderState getRenderState() {
|
||||
return new CableBusRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clicked(PlayerEntity player, Hand hand, Vec3d hitVec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.parts.IPartModel;
|
||||
|
||||
public class PartModel implements IPartModel {
|
||||
private final boolean isSolid;
|
||||
|
||||
private final List<Identifier> resources;
|
||||
|
||||
public PartModel(Identifier resource) {
|
||||
this(true, resource);
|
||||
}
|
||||
|
||||
public PartModel(Identifier... resources) {
|
||||
this(true, resources);
|
||||
}
|
||||
|
||||
public PartModel(boolean isSolid, Identifier resource) {
|
||||
this(isSolid, ImmutableList.of(resource));
|
||||
}
|
||||
|
||||
public PartModel(boolean isSolid, Identifier... resources) {
|
||||
this(isSolid, ImmutableList.copyOf(resources));
|
||||
}
|
||||
|
||||
public PartModel(List<Identifier> resources) {
|
||||
this(true, resources);
|
||||
}
|
||||
|
||||
public PartModel(boolean isSolid, List<Identifier> resources) {
|
||||
this.isSolid = isSolid;
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requireCableConnection() {
|
||||
return this.isSolid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Identifier> getModels() {
|
||||
return this.resources;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.definitions.IBlockDefinition;
|
||||
import appeng.api.definitions.IItems;
|
||||
import appeng.api.parts.*;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.PartPlacementPacket;
|
||||
import appeng.facade.IFacadeItem;
|
||||
import appeng.util.LookDirection;
|
||||
import appeng.util.Platform;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.*;
|
||||
import net.minecraft.sound.BlockSoundGroup;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.RayTraceContext;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class PartPlacement {
|
||||
|
||||
private static float eyeHeight = 0.0f;
|
||||
private static final ThreadLocal<Object> placing = new ThreadLocal<>();
|
||||
private static boolean wasCanceled = false;
|
||||
|
||||
static {
|
||||
|
||||
UseBlockCallback.EVENT.register(PartPlacement::onPlayerUseBlock);
|
||||
|
||||
}
|
||||
|
||||
public static ActionResult place(final ItemStack held, final BlockPos pos, Direction side,
|
||||
final PlayerEntity player, final Hand hand, final World world, PlaceType pass, final int depth) {
|
||||
if (depth > 3) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
|
||||
// FIXME: This was changed alot.
|
||||
final LookDirection dir = Platform.getPlayerRay(player);
|
||||
RayTraceContext rtc = new RayTraceContext(dir.getA(), dir.getB(), RayTraceContext.ShapeType.OUTLINE,
|
||||
RayTraceContext.FluidHandling.NONE, player);
|
||||
final BlockHitResult mop = world.rayTrace(rtc);
|
||||
ItemPlacementContext useContext = new ItemPlacementContext(new ItemUsageContext(player, hand, mop));
|
||||
|
||||
if (!held.isEmpty() && Platform.isWrench(player, held, pos) && player.isInSneakingPose()) {
|
||||
if (!Platform.hasPermissions(new DimensionalCoord(world, pos), player)) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
|
||||
final BlockEntity tile = world.getBlockEntity(pos);
|
||||
IPartHost host = null;
|
||||
|
||||
if (tile instanceof IPartHost) {
|
||||
host = (IPartHost) tile;
|
||||
}
|
||||
|
||||
if (host != null) {
|
||||
if (!world.isClient) {
|
||||
if (mop.getType() == HitResult.Type.BLOCK) {
|
||||
final List<ItemStack> is = new ArrayList<>();
|
||||
final SelectedPart sp = selectPart(player, host,
|
||||
mop.getPos().add(-mop.getPos().getX(), -mop.getPos().getY(), -mop.getPos().getZ()));
|
||||
|
||||
if (sp.part != null) {
|
||||
is.add(sp.part.getItemStack(PartItemStack.WRENCH));
|
||||
sp.part.getDrops(is, true);
|
||||
host.removePart(sp.side, false);
|
||||
}
|
||||
|
||||
if (sp.facade != null) {
|
||||
is.add(sp.facade.getItemStack());
|
||||
host.getFacadeContainer().removeFacade(host, sp.side);
|
||||
Platform.notifyBlocksOfNeighbors(world, pos);
|
||||
}
|
||||
|
||||
if (host.isEmpty()) {
|
||||
host.cleanup();
|
||||
}
|
||||
|
||||
if (!is.isEmpty()) {
|
||||
Platform.spawnDrops(world, pos, is);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.swingHand(hand);
|
||||
NetworkHandler.instance()
|
||||
.sendToServer(new PartPlacementPacket(pos, side, getEyeOffset(player), hand));
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
|
||||
BlockEntity tile = world.getBlockEntity(pos);
|
||||
IPartHost host = null;
|
||||
|
||||
if (tile instanceof IPartHost) {
|
||||
host = (IPartHost) tile;
|
||||
}
|
||||
|
||||
if (!held.isEmpty()) {
|
||||
final IFacadePart fp = isFacade(held, AEPartLocation.fromFacing(side));
|
||||
if (fp != null) {
|
||||
if (host != null) {
|
||||
if (!world.isClient) {
|
||||
if (host.getPart(AEPartLocation.INTERNAL) == null) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
|
||||
if (host.canAddPart(held, AEPartLocation.fromFacing(side))) {
|
||||
if (host.getFacadeContainer().addFacade(fp)) {
|
||||
host.markForSave();
|
||||
host.markForUpdate();
|
||||
if (!player.isCreative()) {
|
||||
held.increment(-1);
|
||||
if (held.getCount() == 0) {
|
||||
player.inventory.main.set(player.inventory.selectedSlot,
|
||||
ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
return ActionResult.CONSUME;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.swingHand(hand);
|
||||
NetworkHandler.instance()
|
||||
.sendToServer(new PartPlacementPacket(pos, side, getEyeOffset(player), hand));
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (held.isEmpty()) {
|
||||
if (host != null && player.isInSneakingPose() && world.isAir(pos)) {
|
||||
if (mop.getType() == HitResult.Type.BLOCK) {
|
||||
Vec3d hitVec = mop.getPos().add(-mop.getPos().getX(), -mop.getPos().getY(),
|
||||
-mop.getPos().getZ());
|
||||
final SelectedPart sPart = selectPart(player, host, hitVec);
|
||||
if (sPart != null && sPart.part != null) {
|
||||
if (sPart.part.onShiftActivate(player, hand, hitVec)) {
|
||||
if (world.isClient) {
|
||||
NetworkHandler.instance()
|
||||
.sendToServer(new PartPlacementPacket(pos, side, getEyeOffset(player), hand));
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (held.isEmpty() || !(held.getItem() instanceof IPartItem)) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
BlockPos te_pos = pos;
|
||||
|
||||
final IBlockDefinition multiPart = AEApi.instance().definitions().blocks().multiPart();
|
||||
if (host == null && pass == PlaceType.PLACE_ITEM) {
|
||||
Direction offset = null;
|
||||
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
// FIXME isReplacable on the block state allows for more control, but requires
|
||||
// an item use context
|
||||
if (!blockState.isAir() && !blockState.canReplace(useContext)) {
|
||||
offset = side;
|
||||
if (Platform.isServer()) {
|
||||
side = side.getOpposite();
|
||||
}
|
||||
}
|
||||
|
||||
te_pos = offset == null ? pos : pos.offset(offset);
|
||||
|
||||
tile = world.getBlockEntity(te_pos);
|
||||
if (tile instanceof IPartHost) {
|
||||
host = (IPartHost) tile;
|
||||
}
|
||||
|
||||
final Optional<ItemStack> maybeMultiPartStack = multiPart.maybeStack(1);
|
||||
final Optional<Block> maybeMultiPartBlock = multiPart.maybeBlock();
|
||||
final Optional<BlockItem> maybeMultiPartBlockItem = multiPart.maybeBlockItem();
|
||||
|
||||
final boolean hostIsNotPresent = host == null;
|
||||
final boolean multiPartPresent = maybeMultiPartBlock.isPresent() && maybeMultiPartStack.isPresent()
|
||||
&& maybeMultiPartBlockItem.isPresent();
|
||||
BlockState multiPartBlockState = maybeMultiPartBlock.get().getDefaultState();
|
||||
final boolean canMultiPartBePlaced = multiPartBlockState.canPlaceAt(world, te_pos);
|
||||
|
||||
// We cannot override the item stack of normal use context, so we use this hack
|
||||
ItemPlacementContext mpUseCtx = new ItemPlacementContext(
|
||||
new AutomaticItemPlacementContext(world, te_pos, side, maybeMultiPartStack.get(), side));
|
||||
|
||||
// FIXME: This is super-fishy and all needs to be re-checked. what does this
|
||||
// even do???
|
||||
if (hostIsNotPresent && multiPartPresent && canMultiPartBePlaced
|
||||
&& maybeMultiPartBlockItem.get().place(mpUseCtx) == ActionResult.SUCCESS) {
|
||||
if (!world.isClient) {
|
||||
tile = world.getBlockEntity(te_pos);
|
||||
|
||||
if (tile instanceof IPartHost) {
|
||||
host = (IPartHost) tile;
|
||||
}
|
||||
|
||||
pass = PlaceType.INTERACT_SECOND_PASS;
|
||||
} else {
|
||||
player.swingHand(hand);
|
||||
NetworkHandler.instance()
|
||||
.sendToServer(new PartPlacementPacket(pos, side, getEyeOffset(player), hand));
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
} else if (host != null && !host.canAddPart(held, AEPartLocation.fromFacing(side))) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (host == null) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
if (!host.canAddPart(held, AEPartLocation.fromFacing(side))) {
|
||||
if (pass == PlaceType.INTERACT_FIRST_PASS || pass == PlaceType.PLACE_ITEM) {
|
||||
te_pos = pos.offset(side);
|
||||
|
||||
final BlockState blkState = world.getBlockState(te_pos);
|
||||
|
||||
// FIXME: this is always true (host was de-referenced above)
|
||||
if (blkState.isAir() || blkState.canReplace(useContext) || host != null) {
|
||||
return place(held, te_pos, side.getOpposite(), player, hand, world,
|
||||
pass == PlaceType.INTERACT_FIRST_PASS ? PlaceType.INTERACT_SECOND_PASS
|
||||
: PlaceType.PLACE_ITEM,
|
||||
depth + 1);
|
||||
}
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
if (!world.isClient) {
|
||||
if (mop.getType() != HitResult.Type.MISS) {
|
||||
final SelectedPart sp = selectPart(player, host,
|
||||
mop.getPos().add(-mop.getPos().getX(), -mop.getPos().getY(), -mop.getPos().getZ()));
|
||||
|
||||
if (sp.part != null) {
|
||||
if (!player.isInSneakingPose() && sp.part.onActivate(player, hand, mop.getPos())) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final DimensionalCoord dc = host.getLocation();
|
||||
if (!Platform.hasPermissions(dc, player)) {
|
||||
return ActionResult.FAIL;
|
||||
}
|
||||
|
||||
final AEPartLocation mySide = host.addPart(held, AEPartLocation.fromFacing(side), player, hand);
|
||||
if (mySide != null) {
|
||||
multiPart.maybeBlock().ifPresent(multiPartBlock -> {
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
final BlockSoundGroup ss = multiPartBlock.getSoundGroup(blockState);
|
||||
|
||||
world.playSound(null, pos, ss.getPlaceSound(), SoundCategory.BLOCKS, (ss.getVolume() + 1.0F) / 2.0F,
|
||||
ss.getPitch() * 0.8F);
|
||||
});
|
||||
|
||||
if (!player.isCreative()) {
|
||||
held.increment(-1);
|
||||
if (held.getCount() == 0) {
|
||||
player.setStackInHand(hand, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.swingHand(hand);
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
private static float getEyeOffset(final PlayerEntity p) {
|
||||
if (p.world.isClient) {
|
||||
return Platform.getEyeOffset(p);
|
||||
}
|
||||
|
||||
return getEyeHeight();
|
||||
}
|
||||
|
||||
private static SelectedPart selectPart(final PlayerEntity player, final IPartHost host, final Vec3d pos) {
|
||||
AppEng.instance().updateRenderMode(player);
|
||||
final SelectedPart sp = host.selectPart(pos);
|
||||
AppEng.instance().updateRenderMode(null);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
public static IFacadePart isFacade(final ItemStack held, final AEPartLocation side) {
|
||||
if (held.getItem() instanceof IFacadeItem) {
|
||||
return ((IFacadeItem) held.getItem()).createPartFromItemStack(held, side);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void playerInteract(final MinecraftClient client) {
|
||||
wasCanceled = false;
|
||||
}
|
||||
|
||||
private static ActionResult onPlayerUseBlock(PlayerEntity player, World world, Hand hand, BlockHitResult hit) {
|
||||
|
||||
if (world.isClient || player.isSpectator()) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
if (placing.get() != null) {
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
placing.set(true);
|
||||
|
||||
final ItemStack held = player.getStackInHand(hand);
|
||||
if (place(held, hit.getBlockPos(), hit.getSide(), player, hand,
|
||||
player.world, PlaceType.INTERACT_FIRST_PASS, 0) == ActionResult.SUCCESS) {
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
placing.set(null);
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
// FIXME FABRIC public static void playerInteract(final PlayerInteractEvent event) {
|
||||
// FIXME FABRIC // Only handle the main hand event
|
||||
// FIXME FABRIC if (event.getHand() != Hand.MAIN_HAND) {
|
||||
// FIXME FABRIC return;
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC if (event instanceof PlayerInteractEvent.RightClickEmpty && event.getPlayer().world.isClient) {
|
||||
// FIXME FABRIC // re-check to see if this event was already channeled, cause these two events
|
||||
// FIXME FABRIC // are really stupid...
|
||||
// FIXME FABRIC final HitResult mop = Platform.rayTrace(event.getPlayer(), true, false);
|
||||
// FIXME FABRIC final MinecraftClient mc = MinecraftClient.getInstance();
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC final float f = 1.0F;
|
||||
// FIXME FABRIC final double d0 = mc.playerController.getBlockReachDistance();
|
||||
// FIXME FABRIC final Vec3d vec3 = mc.getRenderViewEntity().getEyePosition(f);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC if (mop instanceof BlockHitResult && mop.getPos().distanceTo(vec3) < d0) {
|
||||
// FIXME FABRIC BlockHitResult brtr = (BlockHitResult) mop;
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC final World w = event.getEntity().world;
|
||||
// FIXME FABRIC final BlockEntity te = w.getBlockEntity(brtr.getPos());
|
||||
// FIXME FABRIC if (te instanceof IPartHost && this.wasCanceled) {
|
||||
// FIXME FABRIC event.setCanceled(true);
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC } else {
|
||||
// FIXME FABRIC final ItemStack held = event.getPlayer().getStackInHand(event.getHand());
|
||||
// FIXME FABRIC final IItems items = AEApi.instance().definitions().items();
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC boolean supportedItem = items.memoryCard().isSameAs(held);
|
||||
// FIXME FABRIC supportedItem |= items.colorApplicator().isSameAs(held);
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC if (event.getPlayer().isInSneakingPose() && !held.isEmpty() && supportedItem) {
|
||||
// FIXME FABRIC NetworkHandler.instance().sendToServer(new ClickPacket(event.getHand()));
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC } else if (event instanceof PlayerInteractEvent.RightClickBlock && !event.getPlayer().world.isClient) {
|
||||
// FIXME FABRIC
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC }
|
||||
|
||||
private static float getEyeHeight() {
|
||||
return eyeHeight;
|
||||
}
|
||||
|
||||
public static void setEyeHeight(final float eyeHeight) {
|
||||
PartPlacement.eyeHeight = eyeHeight;
|
||||
}
|
||||
|
||||
public enum PlaceType {
|
||||
PLACE_ITEM, INTERACT_FIRST_PASS, INTERACT_SECOND_PASS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.misc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.parts.BusSupport;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.parts.PartItemStack;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.parts.PartModel;
|
||||
|
||||
public class CableAnchorPart implements IPart {
|
||||
|
||||
@PartModels
|
||||
public static final PartModel DEFAULT_MODELS = new PartModel(false,
|
||||
new Identifier(AppEng.MOD_ID, "part/cable_anchor"));
|
||||
|
||||
@PartModels
|
||||
public static final PartModel FACADE_MODELS = new PartModel(false,
|
||||
new Identifier(AppEng.MOD_ID, "part/cable_anchor_short"));
|
||||
|
||||
private ItemStack is = ItemStack.EMPTY;
|
||||
private IPartHost host = null;
|
||||
private AEPartLocation mySide = AEPartLocation.UP;
|
||||
|
||||
public CableAnchorPart(final ItemStack is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
if (this.host != null && this.host.getFacadeContainer().getFacade(this.mySide) != null) {
|
||||
bch.addBox(7, 7, 10, 9, 9, 14);
|
||||
} else {
|
||||
bch.addBox(7, 7, 10, 9, 9, 16);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(final PartItemStack wrenched) {
|
||||
return this.is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requireDynamicRender() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConnectRedstone() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLadder(final LivingEntity entity) {
|
||||
return this.mySide.yOffset == 0 && (entity.horizontalCollision || !entity.isOnGround());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onneighborUpdate(BlockView w, BlockPos pos, BlockPos neighbor) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingStrongPower() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int isProvidingWeakPower() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToStream(final PacketByteBuf data) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readFromStream(final PacketByteBuf data) throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getGridNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityCollision(final Entity entity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromWorld() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToWorld() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getExternalFacingNode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPartHostInfo(final AEPartLocation side, final IPartHost host, final BlockEntity tile) {
|
||||
this.host = host;
|
||||
this.mySide = side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShiftActivate(final PlayerEntity player, final Hand hand, final Vec3d pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDrops(final List<ItemStack> drops, final boolean wrenched) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomDisplayTick(final World world, final BlockPos pos, final Random r) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlacement(final PlayerEntity player, final Hand hand, final ItemStack held,
|
||||
final AEPartLocation side) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBePlacedOn(final BusSupport what) {
|
||||
return what == BusSupport.CABLE || what == BusSupport.DENSE_CABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
if (this.host != null && this.host.getFacadeContainer().getFacade(this.mySide) != null) {
|
||||
return FACADE_MODELS;
|
||||
} else {
|
||||
return DEFAULT_MODELS;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.api.AEApi;
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.definitions.IParts;
|
||||
import appeng.api.implementations.parts.ICablePart;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridConnection;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.parts.BusSupport;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.IReadOnlyCollection;
|
||||
import appeng.items.parts.ColoredPartItem;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.parts.AEBasePart;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class CablePart extends AEBasePart implements ICablePart {
|
||||
|
||||
private final int[] channelsOnSide = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
private EnumSet<AEPartLocation> connections = EnumSet.noneOf(AEPartLocation.class);
|
||||
private boolean powered = false;
|
||||
|
||||
public CablePart(final ItemStack is) {
|
||||
super(is);
|
||||
this.getProxy().setFlags(GridFlags.PREFERRED);
|
||||
this.getProxy().setIdlePowerUsage(0.0);
|
||||
if (is.getItem() instanceof ColoredPartItem) {
|
||||
ColoredPartItem<?> coloredPartItem = (ColoredPartItem<?>) is.getItem();
|
||||
this.getProxy().setColor(coloredPartItem.getColor());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BusSupport supportsBuses() {
|
||||
return BusSupport.CABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEColor getCableColor() {
|
||||
return this.getProxy().getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType() {
|
||||
return AECableType.GLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
if (cable == this.getCableConnectionType()) {
|
||||
return 4;
|
||||
} else if (cable.ordinal() >= this.getCableConnectionType().ordinal()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changeColor(final AEColor newColor, final PlayerEntity who) {
|
||||
if (this.getCableColor() != newColor) {
|
||||
ItemStack newPart = null;
|
||||
|
||||
final IParts parts = AEApi.instance().definitions().parts();
|
||||
|
||||
if (this.getCableConnectionType() == AECableType.GLASS) {
|
||||
newPart = parts.cableGlass().stack(newColor, 1);
|
||||
} else if (this.getCableConnectionType() == AECableType.COVERED) {
|
||||
newPart = parts.cableCovered().stack(newColor, 1);
|
||||
} else if (this.getCableConnectionType() == AECableType.SMART) {
|
||||
newPart = parts.cableSmart().stack(newColor, 1);
|
||||
} else if (this.getCableConnectionType() == AECableType.DENSE_COVERED) {
|
||||
newPart = parts.cableDenseCovered().stack(newColor, 1);
|
||||
} else if (this.getCableConnectionType() == AECableType.DENSE_SMART) {
|
||||
newPart = parts.cableDenseSmart().stack(newColor, 1);
|
||||
}
|
||||
|
||||
boolean hasPermission = true;
|
||||
|
||||
try {
|
||||
hasPermission = this.getProxy().getSecurity().hasPermission(who, SecurityPermissions.BUILD);
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
|
||||
if (newPart != null && hasPermission) {
|
||||
if (Platform.isClient()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.getHost().removePart(AEPartLocation.INTERNAL, true);
|
||||
this.getHost().addPart(newPart, AEPartLocation.INTERNAL, who, null);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValidSides(final EnumSet<Direction> sides) {
|
||||
this.getProxy().setValidSides(sides);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected(final Direction side) {
|
||||
return this.getConnections().contains(AEPartLocation.fromFacing(side));
|
||||
}
|
||||
|
||||
public void markForUpdate() {
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
bch.addBox(6.0, 6.0, 6.0, 10.0, 10.0, 10.0);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
final IGridNode n = this.getGridNode();
|
||||
if (n != null) {
|
||||
this.setConnections(n.getConnectedSides());
|
||||
} else {
|
||||
this.getConnections().clear();
|
||||
}
|
||||
}
|
||||
|
||||
final IPartHost ph = this.getHost();
|
||||
if (ph != null) {
|
||||
for (final AEPartLocation dir : AEPartLocation.SIDE_LOCATIONS) {
|
||||
final IPart p = ph.getPart(dir);
|
||||
if (p instanceof IGridHost) {
|
||||
final double dist = p.getCableConnectionLength(this.getCableConnectionType());
|
||||
|
||||
if (dist > 8) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (dir) {
|
||||
case DOWN:
|
||||
bch.addBox(6.0, dist, 6.0, 10.0, 6.0, 10.0);
|
||||
break;
|
||||
case EAST:
|
||||
bch.addBox(10.0, 6.0, 6.0, 16.0 - dist, 10.0, 10.0);
|
||||
break;
|
||||
case NORTH:
|
||||
bch.addBox(6.0, 6.0, dist, 10.0, 10.0, 6.0);
|
||||
break;
|
||||
case SOUTH:
|
||||
bch.addBox(6.0, 6.0, 10.0, 10.0, 10.0, 16.0 - dist);
|
||||
break;
|
||||
case UP:
|
||||
bch.addBox(6.0, 10.0, 6.0, 10.0, 16.0 - dist, 10.0);
|
||||
break;
|
||||
case WEST:
|
||||
bch.addBox(dist, 6.0, 6.0, 6.0, 10.0, 10.0);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final AEPartLocation of : this.getConnections()) {
|
||||
switch (of) {
|
||||
case DOWN:
|
||||
bch.addBox(6.0, 0.0, 6.0, 10.0, 6.0, 10.0);
|
||||
break;
|
||||
case EAST:
|
||||
bch.addBox(10.0, 6.0, 6.0, 16.0, 10.0, 10.0);
|
||||
break;
|
||||
case NORTH:
|
||||
bch.addBox(6.0, 6.0, 0.0, 10.0, 10.0, 6.0);
|
||||
break;
|
||||
case SOUTH:
|
||||
bch.addBox(6.0, 6.0, 10.0, 10.0, 10.0, 16.0);
|
||||
break;
|
||||
case UP:
|
||||
bch.addBox(6.0, 10.0, 6.0, 10.0, 16.0, 10.0);
|
||||
break;
|
||||
case WEST:
|
||||
bch.addBox(0.0, 6.0, 6.0, 6.0, 10.0, 10.0);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag data) {
|
||||
super.writeToNBT(data);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
final IGridNode node = this.getGridNode();
|
||||
|
||||
if (node != null) {
|
||||
int howMany = 0;
|
||||
for (final IGridConnection gc : node.getConnections()) {
|
||||
howMany = Math.max(gc.getUsedChannels(), howMany);
|
||||
}
|
||||
|
||||
data.putByte("usedChannels", (byte) howMany);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToStream(final PacketByteBuf data) throws IOException {
|
||||
int flags = 0;
|
||||
boolean[] writeSide = new boolean[Direction.values().length];
|
||||
int[] channelsPerSide = new int[Direction.values().length];
|
||||
|
||||
for (Direction thisSide : Direction.values()) {
|
||||
final IPart part = this.getHost().getPart(thisSide);
|
||||
if (part != null) {
|
||||
writeSide[thisSide.ordinal()] = true;
|
||||
int channels = 0;
|
||||
if (part.getGridNode() != null) {
|
||||
final IReadOnlyCollection<IGridConnection> set = part.getGridNode().getConnections();
|
||||
for (final IGridConnection gc : set) {
|
||||
channels = Math.max(channels, gc.getUsedChannels());
|
||||
}
|
||||
}
|
||||
channelsPerSide[thisSide.ordinal()] = channels;
|
||||
}
|
||||
}
|
||||
|
||||
IGridNode n = this.getGridNode();
|
||||
if (n != null) {
|
||||
for (final IGridConnection gc : n.getConnections()) {
|
||||
final AEPartLocation side = gc.getDirection(n);
|
||||
if (side != AEPartLocation.INTERNAL) {
|
||||
writeSide[side.ordinal()] = true;
|
||||
channelsPerSide[side.ordinal()] = gc.getUsedChannels();
|
||||
flags |= (1 << side.ordinal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.getProxy().getEnergy().isNetworkPowered()) {
|
||||
flags |= (1 << AEPartLocation.INTERNAL.ordinal());
|
||||
}
|
||||
} catch (final GridAccessException e) {
|
||||
// aww...
|
||||
}
|
||||
|
||||
data.writeByte((byte) flags);
|
||||
// Only write the used channels for sides where we have a part or another cable
|
||||
for (int i = 0; i < writeSide.length; i++) {
|
||||
if (writeSide[i]) {
|
||||
data.writeByte(channelsPerSide[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readFromStream(final PacketByteBuf data) throws IOException {
|
||||
int cs = data.readByte();
|
||||
final EnumSet<AEPartLocation> myC = this.getConnections().clone();
|
||||
final boolean wasPowered = this.powered;
|
||||
this.powered = false;
|
||||
boolean channelsChanged = false;
|
||||
|
||||
for (final AEPartLocation d : AEPartLocation.values()) {
|
||||
if (d == AEPartLocation.INTERNAL) {
|
||||
final int id = 1 << d.ordinal();
|
||||
if (id == (cs & id)) {
|
||||
this.powered = true;
|
||||
}
|
||||
} else {
|
||||
boolean conOnSide = (cs & (1 << d.ordinal())) != 0;
|
||||
if (conOnSide) {
|
||||
this.getConnections().add(d);
|
||||
} else {
|
||||
this.getConnections().remove(d);
|
||||
}
|
||||
|
||||
int ch = 0;
|
||||
|
||||
// Only read channels if there's a part on this side or a cable connection
|
||||
// This works only because cables are always read *last* from the packet update
|
||||
// for
|
||||
// a cable bus
|
||||
if (conOnSide || this.getHost().getPart(d) != null) {
|
||||
ch = (data.readByte()) & 0xFF;
|
||||
}
|
||||
|
||||
if (ch != this.getChannelsOnSide(d.ordinal())) {
|
||||
channelsChanged = true;
|
||||
this.setChannelsOnSide(d.ordinal(), ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !myC.equals(this.getConnections()) || wasPowered != this.powered || channelsChanged;
|
||||
}
|
||||
|
||||
int getChannelsOnSide(final int i) {
|
||||
return this.channelsOnSide[i];
|
||||
}
|
||||
|
||||
public int getChannelsOnSide(Direction side) {
|
||||
if (!this.powered) {
|
||||
return 0;
|
||||
}
|
||||
return this.channelsOnSide[side.ordinal()];
|
||||
}
|
||||
|
||||
void setChannelsOnSide(final int i, final int channels) {
|
||||
this.channelsOnSide[i] = channels;
|
||||
}
|
||||
|
||||
EnumSet<AEPartLocation> getConnections() {
|
||||
return this.connections;
|
||||
}
|
||||
|
||||
void setConnections(final EnumSet<AEPartLocation> connections) {
|
||||
this.connections = connections;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class CoveredCablePart extends CablePart {
|
||||
|
||||
public CoveredCablePart(final ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void channelUpdated(final MENetworkChannelsChanged c) {
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void powerRender(final MENetworkPowerStatusChange c) {
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType() {
|
||||
return AECableType.COVERED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
bch.addBox(5.0, 5.0, 5.0, 11.0, 11.0, 11.0);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
final IGridNode n = this.getGridNode();
|
||||
if (n != null) {
|
||||
this.setConnections(n.getConnectedSides());
|
||||
} else {
|
||||
this.getConnections().clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (final AEPartLocation of : this.getConnections()) {
|
||||
switch (of) {
|
||||
case DOWN:
|
||||
bch.addBox(5.0, 0.0, 5.0, 11.0, 5.0, 11.0);
|
||||
break;
|
||||
case EAST:
|
||||
bch.addBox(11.0, 5.0, 5.0, 16.0, 11.0, 11.0);
|
||||
break;
|
||||
case NORTH:
|
||||
bch.addBox(5.0, 5.0, 0.0, 11.0, 11.0, 5.0);
|
||||
break;
|
||||
case SOUTH:
|
||||
bch.addBox(5.0, 5.0, 11.0, 11.0, 11.0, 16.0);
|
||||
break;
|
||||
case UP:
|
||||
bch.addBox(5.0, 11.0, 5.0, 11.0, 16.0, 11.0);
|
||||
break;
|
||||
case WEST:
|
||||
bch.addBox(0.0, 5.0, 5.0, 5.0, 11.0, 11.0);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.util.AECableType;
|
||||
|
||||
public class CoveredDenseCablePart extends DenseCablePart {
|
||||
|
||||
public CoveredDenseCablePart(ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType() {
|
||||
return AECableType.DENSE_COVERED;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridHost;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.parts.BusSupport;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public abstract class DenseCablePart extends CablePart {
|
||||
|
||||
public DenseCablePart(final ItemStack is) {
|
||||
super(is);
|
||||
|
||||
this.getProxy().setFlags(GridFlags.DENSE_CAPACITY, GridFlags.PREFERRED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BusSupport supportsBuses() {
|
||||
return BusSupport.DENSE_CABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
final boolean noLadder = !bch.isBBCollision();
|
||||
final double min = noLadder ? 3.0 : 4.9;
|
||||
final double max = noLadder ? 13.0 : 11.1;
|
||||
|
||||
bch.addBox(min, min, min, max, max, max);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
final IGridNode n = this.getGridNode();
|
||||
if (n != null) {
|
||||
this.setConnections(n.getConnectedSides());
|
||||
} else {
|
||||
this.getConnections().clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (final AEPartLocation of : this.getConnections()) {
|
||||
if (this.isDense(of)) {
|
||||
switch (of) {
|
||||
case DOWN:
|
||||
bch.addBox(min, 0.0, min, max, min, max);
|
||||
break;
|
||||
case EAST:
|
||||
bch.addBox(max, min, min, 16.0, max, max);
|
||||
break;
|
||||
case NORTH:
|
||||
bch.addBox(min, min, 0.0, max, max, min);
|
||||
break;
|
||||
case SOUTH:
|
||||
bch.addBox(min, min, max, max, max, 16.0);
|
||||
break;
|
||||
case UP:
|
||||
bch.addBox(min, max, min, max, 16.0, max);
|
||||
break;
|
||||
case WEST:
|
||||
bch.addBox(0.0, min, min, min, max, max);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
switch (of) {
|
||||
case DOWN:
|
||||
bch.addBox(5.0, 0.0, 5.0, 11.0, 5.0, 11.0);
|
||||
break;
|
||||
case EAST:
|
||||
bch.addBox(11.0, 5.0, 5.0, 16.0, 11.0, 11.0);
|
||||
break;
|
||||
case NORTH:
|
||||
bch.addBox(5.0, 5.0, 0.0, 11.0, 11.0, 5.0);
|
||||
break;
|
||||
case SOUTH:
|
||||
bch.addBox(5.0, 5.0, 11.0, 11.0, 11.0, 16.0);
|
||||
break;
|
||||
case UP:
|
||||
bch.addBox(5.0, 11.0, 5.0, 11.0, 16.0, 11.0);
|
||||
break;
|
||||
case WEST:
|
||||
bch.addBox(0.0, 5.0, 5.0, 5.0, 11.0, 11.0);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDense(final AEPartLocation of) {
|
||||
final BlockEntity te = this.getTile().getWorld().getBlockEntity(this.getTile().getPos().offset(of.getFacing()));
|
||||
|
||||
if (te instanceof IGridHost) {
|
||||
final AECableType t = ((IGridHost) te).getCableConnectionType(of.getOpposite());
|
||||
return t.isDense();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void channelUpdated(final MENetworkChannelsChanged c) {
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void powerRender(final MENetworkPowerStatusChange c) {
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class GlassCablePart extends CablePart {
|
||||
|
||||
public GlassCablePart(final ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.GridFlags;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.energy.IEnergyGrid;
|
||||
import appeng.api.networking.energy.IEnergyGridProvider;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.parts.IPartHost;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.GridAccessException;
|
||||
import appeng.me.helpers.AENetworkProxy;
|
||||
import appeng.parts.AEBasePart;
|
||||
import appeng.parts.PartModel;
|
||||
|
||||
public class QuartzFiberPart extends AEBasePart implements IEnergyGridProvider {
|
||||
|
||||
@PartModels
|
||||
private static final IPartModel MODELS = new PartModel(new Identifier(AppEng.MOD_ID, "part/quartz_fiber"));
|
||||
|
||||
private final AENetworkProxy outerProxy = new AENetworkProxy(this, "outer",
|
||||
this.getProxy().getMachineRepresentation(), true);
|
||||
|
||||
public QuartzFiberPart(final ItemStack is) {
|
||||
super(is);
|
||||
this.getProxy().setIdlePowerUsage(0);
|
||||
this.getProxy().setFlags(GridFlags.CANNOT_CARRY);
|
||||
this.outerProxy.setIdlePowerUsage(0);
|
||||
this.outerProxy.setFlags(GridFlags.CANNOT_CARRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType(final AEPartLocation dir) {
|
||||
return AECableType.GLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
bch.addBox(6, 6, 10, 10, 10, 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(final CompoundTag extra) {
|
||||
super.readFromNBT(extra);
|
||||
this.outerProxy.readFromNBT(extra);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToNBT(final CompoundTag extra) {
|
||||
super.writeToNBT(extra);
|
||||
this.outerProxy.writeToNBT(extra);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromWorld() {
|
||||
super.removeFromWorld();
|
||||
this.outerProxy.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToWorld() {
|
||||
super.addToWorld();
|
||||
this.outerProxy.onReady();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPartHostInfo(final AEPartLocation side, final IPartHost host, final BlockEntity tile) {
|
||||
super.setPartHostInfo(side, host, tile);
|
||||
this.outerProxy.setValidSides(EnumSet.of(side.getFacing()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getExternalFacingNode() {
|
||||
return this.outerProxy.getNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlacement(final PlayerEntity player, final Hand hand, final ItemStack held,
|
||||
final AEPartLocation side) {
|
||||
super.onPlacement(player, hand, held, side);
|
||||
this.outerProxy.setOwner(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<IEnergyGridProvider> providers() {
|
||||
Collection<IEnergyGridProvider> providers = new ArrayList<>();
|
||||
|
||||
try {
|
||||
final IEnergyGrid eg = this.getProxy().getEnergy();
|
||||
|
||||
providers.add(eg);
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
|
||||
try {
|
||||
final IEnergyGrid eg = this.outerProxy.getEnergy();
|
||||
|
||||
providers.add(eg);
|
||||
} catch (final GridAccessException e) {
|
||||
// :P
|
||||
}
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double extractProviderPower(final double amt, final Actionable mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double injectProviderPower(final double amt, final Actionable mode) {
|
||||
return amt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProviderEnergyDemand(final double amt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProviderStoredEnergy() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProviderMaxEnergy() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModel getStaticModels() {
|
||||
return MODELS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.events.MENetworkChannelsChanged;
|
||||
import appeng.api.networking.events.MENetworkEventSubscribe;
|
||||
import appeng.api.networking.events.MENetworkPowerStatusChange;
|
||||
import appeng.api.parts.IPartCollisionHelper;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class SmartCablePart extends CablePart {
|
||||
|
||||
public SmartCablePart(final ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void channelUpdated(final MENetworkChannelsChanged c) {
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
@MENetworkEventSubscribe
|
||||
public void powerRender(final MENetworkPowerStatusChange c) {
|
||||
this.getHost().markForUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType() {
|
||||
return AECableType.SMART;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBoxes(final IPartCollisionHelper bch) {
|
||||
bch.addBox(5.0, 5.0, 5.0, 11.0, 11.0, 11.0);
|
||||
|
||||
if (Platform.isServer()) {
|
||||
final IGridNode n = this.getGridNode();
|
||||
if (n != null) {
|
||||
this.setConnections(n.getConnectedSides());
|
||||
} else {
|
||||
this.getConnections().clear();
|
||||
}
|
||||
}
|
||||
|
||||
for (final AEPartLocation of : this.getConnections()) {
|
||||
switch (of) {
|
||||
case DOWN:
|
||||
bch.addBox(5.0, 0.0, 5.0, 11.0, 5.0, 11.0);
|
||||
break;
|
||||
case EAST:
|
||||
bch.addBox(11.0, 5.0, 5.0, 16.0, 11.0, 11.0);
|
||||
break;
|
||||
case NORTH:
|
||||
bch.addBox(5.0, 5.0, 0.0, 11.0, 11.0, 5.0);
|
||||
break;
|
||||
case SOUTH:
|
||||
bch.addBox(5.0, 5.0, 11.0, 11.0, 11.0, 16.0);
|
||||
break;
|
||||
case UP:
|
||||
bch.addBox(5.0, 11.0, 5.0, 11.0, 16.0, 11.0);
|
||||
break;
|
||||
case WEST:
|
||||
bch.addBox(0.0, 5.0, 5.0, 5.0, 11.0, 11.0);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.parts.networking;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import appeng.api.util.AECableType;
|
||||
|
||||
public class SmartDenseCablePart extends DenseCablePart {
|
||||
|
||||
public SmartDenseCablePart(ItemStack is) {
|
||||
super(is);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType() {
|
||||
return AECableType.DENSE_SMART;
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import appeng.util.Platform;
|
||||
import appeng.util.SettingsFrom;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
@@ -55,12 +56,36 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AEBaseBlockEntity extends BlockEntity implements IOrientable, ICommonTile, ICustomNameObject, BlockEntityClientSerializable, RenderAttachmentBlockEntity, AttributeProvider {
|
||||
|
||||
// FIXME: should probably remove at start of next server tick!
|
||||
static {
|
||||
ServerChunkEvents.CHUNK_UNLOAD.register((serverWorld, worldChunk) -> {
|
||||
List<AEBaseBlockEntity> entitiesToRemove = null;
|
||||
for (BlockEntity value : worldChunk.getBlockEntities().values()) {
|
||||
if (value instanceof AEBaseBlockEntity) {
|
||||
if (entitiesToRemove == null) {
|
||||
entitiesToRemove = new ArrayList<>();
|
||||
}
|
||||
entitiesToRemove.add((AEBaseBlockEntity) value);
|
||||
}
|
||||
}
|
||||
if (entitiesToRemove != null) {
|
||||
for (AEBaseBlockEntity blockEntity : entitiesToRemove) {
|
||||
blockEntity.onChunkUnloaded();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void onChunkUnloaded() {
|
||||
}
|
||||
|
||||
private static final ThreadLocal<WeakReference<AEBaseBlockEntity>> DROP_NO_ITEMS = new ThreadLocal<>();
|
||||
private static final Map<Class<? extends BlockEntity>, IStackSrc> ITEM_STACKS = new HashMap<>();
|
||||
private int renderFragment = 0;
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.tile.networking;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import alexiil.mc.lib.attributes.AttributeList;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.parts.IFacadeContainer;
|
||||
import appeng.api.parts.IPart;
|
||||
import appeng.api.parts.LayerFlags;
|
||||
import appeng.api.parts.SelectedPart;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.api.util.AEPartLocation;
|
||||
import appeng.api.util.DimensionalCoord;
|
||||
import appeng.client.render.cablebus.CableBusRenderState;
|
||||
import appeng.helpers.AEMultiTile;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.parts.CableBusContainer;
|
||||
import appeng.tile.AEBaseBlockEntity;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public class CableBusBlockEntity extends AEBaseBlockEntity implements AEMultiTile {
|
||||
|
||||
private CableBusContainer cb = new CableBusContainer(this);
|
||||
|
||||
private int oldLV = -1; // on re-calculate light when it changes
|
||||
|
||||
public CableBusBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromTag(BlockState state, final CompoundTag data) {
|
||||
super.fromTag(state, data);
|
||||
this.getCableBus().readFromNBT(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag toTag(final CompoundTag data) {
|
||||
super.toTag(data);
|
||||
this.getCableBus().writeToNBT(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean readFromStream(final PacketByteBuf data) throws IOException {
|
||||
final boolean c = super.readFromStream(data);
|
||||
boolean ret = this.getCableBus().readFromStream(data);
|
||||
|
||||
final int newLV = this.getCableBus().getLightValue();
|
||||
if (newLV != this.oldLV) {
|
||||
this.oldLV = newLV;
|
||||
this.world.getLightingProvider().checkBlock(this.pos);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
this.updateTileSetting();
|
||||
return ret || c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeToStream(final PacketByteBuf data) throws IOException {
|
||||
super.writeToStream(data);
|
||||
this.getCableBus().writeToStream(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes this tile to the TESR version if any of the parts require dynamic
|
||||
* rendering.
|
||||
*/
|
||||
protected void updateTileSetting() {
|
||||
// FIXME: potentially invalidate voxel shape cache?
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getSquaredRenderDistance() {
|
||||
return 900.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRemoved() {
|
||||
super.markRemoved();
|
||||
this.getCableBus().removeFromWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelRemoval() {
|
||||
super.cancelRemoval();
|
||||
TickHandler.INSTANCE.addInit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGridNode getGridNode(final AEPartLocation dir) {
|
||||
return this.getCableBus().getGridNode(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AECableType getCableConnectionType(final AEPartLocation side) {
|
||||
return this.getCableBus().getCableConnectionType(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCableConnectionLength(AECableType cable) {
|
||||
return this.getCableBus().getCableConnectionLength(cable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkUnloaded() {
|
||||
super.onChunkUnloaded();
|
||||
this.getCableBus().removeFromWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markForUpdate() {
|
||||
if (this.world == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int newLV = this.getCableBus().getLightValue();
|
||||
if (newLV != this.oldLV) {
|
||||
this.oldLV = newLV;
|
||||
this.world.getLightingProvider().checkBlock(this.pos);
|
||||
}
|
||||
|
||||
super.markForUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRotated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDrops(final World w, final BlockPos pos, final List drops) {
|
||||
this.getCableBus().getDrops(drops);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNoDrops(final World w, final BlockPos pos, final List<ItemStack> drops) {
|
||||
this.getCableBus().getNoDrops(drops);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReady() {
|
||||
super.onReady();
|
||||
if (this.getCableBus().isEmpty()) {
|
||||
if (this.world.getBlockEntity(this.pos) == this) {
|
||||
this.world.breakBlock(this.pos, true);
|
||||
}
|
||||
} else {
|
||||
this.getCableBus().addToWorld();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFacadeContainer getFacadeContainer() {
|
||||
return this.getCableBus().getFacadeContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAddPart(final ItemStack is, final AEPartLocation side) {
|
||||
return this.getCableBus().canAddPart(is, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEPartLocation addPart(final ItemStack is, final AEPartLocation side, final PlayerEntity player,
|
||||
final Hand hand) {
|
||||
return this.getCableBus().addPart(is, side, player, hand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPart getPart(final AEPartLocation side) {
|
||||
return this.cb.getPart(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPart getPart(final Direction side) {
|
||||
return this.getCableBus().getPart(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePart(final AEPartLocation side, final boolean suppressUpdate) {
|
||||
this.getCableBus().removePart(side, suppressUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionalCoord getLocation() {
|
||||
return new DimensionalCoord(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AEColor getColor() {
|
||||
return this.getCableBus().getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearContainer() {
|
||||
this.setCableBus(new CableBusContainer(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlocked(final Direction side) {
|
||||
// TODO 1.10.2-R - Stuff.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectedPart selectPart(final Vec3d pos) {
|
||||
return this.getCableBus().selectPart(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markForSave() {
|
||||
this.saveChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void partChanged() {
|
||||
this.notifyNeighbors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRedstone(final AEPartLocation side) {
|
||||
return this.getCableBus().hasRedstone(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.getCableBus().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<LayerFlags> getLayerFlags() {
|
||||
return this.getCableBus().getLayerFlags();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
this.getWorld().removeBlock(this.pos, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors() {
|
||||
if (this.world != null && this.world.isChunkLoaded(this.pos) && !CableBusContainer.isLoading()) {
|
||||
Platform.notifyBlocksOfNeighbors(this.world, this.pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInWorld() {
|
||||
return this.getCableBus().isInWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean recolourBlock(final Direction side, final AEColor colour, final PlayerEntity who) {
|
||||
return this.getCableBus().recolourBlock(side, colour, who);
|
||||
}
|
||||
|
||||
public CableBusContainer getCableBus() {
|
||||
return this.cb;
|
||||
}
|
||||
|
||||
private void setCableBus(final CableBusContainer cb) {
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllAttributes(World world, BlockPos pos, BlockState state, AttributeList<?> to) {
|
||||
super.addAllAttributes(world, pos, state, to);
|
||||
|
||||
for (AEPartLocation location : AEPartLocation.values()) {
|
||||
IPart part = this.cb.getPart(location);
|
||||
if (part != null) {
|
||||
part.addAllAttributes(to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CableBusRenderState getRenderAttachmentData() {
|
||||
World world = getWorld();
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CableBusRenderState renderState = this.cb.getRenderState();
|
||||
renderState.setWorld(world);
|
||||
renderState.setPos(pos);
|
||||
return renderState;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
||||
*
|
||||
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
||||
*/
|
||||
|
||||
package appeng.tile.networking;
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.api.parts.IPart;
|
||||
|
||||
public class CableBusTESR extends BlockEntityRenderer<CableBusBlockEntity> {
|
||||
|
||||
public CableBusTESR(BlockEntityRenderDispatcher rendererDispatcherIn) {
|
||||
super(rendererDispatcherIn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(CableBusBlockEntity te, float partialTicks, MatrixStack ms, VertexConsumerProvider buffers,
|
||||
int combinedLightIn, int combinedOverlayIn) {
|
||||
if (!te.getCableBus().isRequiresDynamicRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Direction facing : Direction.values()) {
|
||||
IPart part = te.getPart(facing);
|
||||
if (part != null && part.requireDynamicRender()) {
|
||||
part.renderDynamic(partialTicks, ms, buffers, combinedLightIn, combinedOverlayIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package team.chisel.ctm.api;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* To be implemented on blocks that "hide" another block inside, so connected textures can still be accomplished.
|
||||
*/
|
||||
public interface IFacade {
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getFacade(BlockView, BlockPos, Direction, BlockPos)}
|
||||
*/
|
||||
@Nonnull
|
||||
@Deprecated
|
||||
BlockState getFacade(@Nonnull BlockView world, @Nonnull BlockPos pos, @Nullable Direction side);
|
||||
|
||||
/**
|
||||
* Gets the blockstate this facade appears as.
|
||||
*
|
||||
* @param world
|
||||
* {@link World}
|
||||
* @param pos
|
||||
* The Blocks position
|
||||
* @param side
|
||||
* The side being rendered, NOT the side being connected from.
|
||||
* <p>
|
||||
* This value can be null if no side is specified. Please handle this appropriately.
|
||||
* @param connection
|
||||
* The position of the block being connected to.
|
||||
* @return The blockstate which your block appears as.
|
||||
*/
|
||||
@Nonnull
|
||||
default BlockState getFacade(@Nonnull BlockView world, @Nonnull BlockPos pos, @Nullable Direction side, @Nonnull BlockPos connection) {
|
||||
return getFacade(world, pos, side);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"loader": "appliedenergistics2:cable_bus"
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
{
|
||||
"parent": "appliedenergistics2:block/cable_bus"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user