Lots of fixes

This commit is contained in:
Sebastian Hartte
2020-07-23 02:38:32 +02:00
parent 1933b4b10d
commit 9fcfbf31be
100 changed files with 1771 additions and 1866 deletions
@@ -141,7 +141,7 @@ public class AEBaseBlockItem extends BlockItem {
}
if (tile instanceof IGridProxyable) {
// FIXME FABRIC ((IGridProxyable) tile).getProxy().setOwner(player);
((IGridProxyable) tile).getProxy().setOwner(player);
}
tile.onPlacement(context);
@@ -28,6 +28,8 @@ import javax.annotation.Nullable;
import alexiil.mc.lib.attributes.AttributeList;
import alexiil.mc.lib.attributes.AttributeProvider;
import alexiil.mc.lib.attributes.item.FixedItemInv;
import appeng.block.networking.CableBusBlock;
import appeng.tile.networking.CableBusBlockEntity;
import com.google.common.collect.Lists;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
@@ -206,7 +208,7 @@ public abstract class AEBaseTileBlock<T extends AEBaseBlockEntity> extends AEBas
return ActionResult.FAIL;
}
if (/* FIXME FABRIC tile instanceof CableBusBlockEntity || */ tile instanceof SkyChestBlockEntity) {
if (tile instanceof CableBusBlockEntity || tile instanceof SkyChestBlockEntity) {
return ActionResult.FAIL;
}
@@ -233,7 +235,7 @@ public abstract class AEBaseTileBlock<T extends AEBaseBlockEntity> extends AEBas
return ActionResult.FAIL;
}
if (heldItem.getItem() instanceof IMemoryCard /* FIXME FABRIC && !(this instanceof CableBusBlock)*/) {
if (heldItem.getItem() instanceof IMemoryCard && !(this instanceof CableBusBlock)) {
final IMemoryCard memoryCard = (IMemoryCard) heldItem.getItem();
final AEBaseBlockEntity tileEntity = this.getBlockEntity(world, pos);
@@ -18,25 +18,21 @@
package appeng.block.crafting;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.StateManager;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import appeng.block.AEBaseTileBlock;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.CraftingCPUContainer;
import appeng.tile.crafting.CraftingBlockEntity;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public abstract class AbstractCraftingUnitBlock<T extends CraftingBlockEntity> extends AEBaseTileBlock<T> {
public static final BooleanProperty FORMED = BooleanProperty.of("formed");
@@ -57,16 +53,6 @@ public abstract class AbstractCraftingUnitBlock<T extends CraftingBlockEntity> e
builder.add(FORMED);
}
@Override
public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn,
BlockPos currentPos, BlockPos facingPos) {
TileEntity te = worldIn.getTileEntity(currentPos);
if (te != null) {
te.requestModelDataUpdate();
}
return super.updatePostPlacement(stateIn, facing, facingState, worldIn, currentPos, facingPos);
}
@Override
public void neighborUpdate(final BlockState state, final World worldIn, final BlockPos pos, final Block blockIn,
final BlockPos fromPos, boolean isMoving) {
@@ -64,7 +64,7 @@ import appeng.util.Platform;
public class ChargerBlock extends AEBaseTileBlock<ChargerBlockEntity> {
public ChargerBlock() {
super(defaultProps(Material.METAL).solidBlock((state, world, pos) -> false));
super(defaultProps(Material.METAL).nonOpaque());
}
@Override
@@ -29,6 +29,8 @@ import appeng.client.render.cablebus.CableBusBakedModel;
import appeng.client.render.cablebus.CableBusBreakingParticle;
import appeng.client.render.cablebus.CableBusRenderState;
import appeng.core.AppEng;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.ClickPacket;
import appeng.helpers.AEMaterials;
import appeng.integration.abstraction.IAEFacade;
import appeng.parts.ICableBusContainer;
@@ -331,9 +333,8 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
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));
NetworkHandler.instance().sendToServer(new ClickPacket(pos, brtr.getSide(), (float) hitVec.x,
(float) hitVec.y, (float) hitVec.z, Hand.MAIN_HAND, true));
}
}
}
@@ -58,10 +58,7 @@ public class WirelessBlock extends AEBaseTileBlock<WirelessBlockEntity> {
public static final EnumProperty<State> STATE = EnumProperty.of("state", State.class);
public WirelessBlock() {
super(defaultProps(AEMaterials.GLASS)
.nonOpaque()
.solidBlock((state, world, pos) -> false)
);
super(defaultProps(AEMaterials.GLASS).nonOpaque());
this.setDefaultState(this.getDefaultState().with(STATE, State.OFF));
}
@@ -42,8 +42,7 @@ import appeng.util.Platform;
public class PaintSplotchesBlock extends AEBaseTileBlock<PaintSplotchesBlockEntity> {
public PaintSplotchesBlock() {
super(defaultProps(Material.WATER, MaterialColor.CLEAR).solidBlock((state, world, pos) -> false)
.air());
super(defaultProps(Material.WATER, MaterialColor.CLEAR).nonOpaque().air());
}
@Override
@@ -41,7 +41,7 @@ public class MatrixFrameBlock extends AEBaseBlock {
private static final Material MATERIAL = new Material(MaterialColor.CLEAR, false, true, true, false, false, false, PistonBehavior.PUSH_ONLY);
public MatrixFrameBlock() {
super(Settings.of(MATERIAL).strength(-1.0F, 6000000.0F).solidBlock((state, world, pos) -> false).dropsNothing());
super(Settings.of(MATERIAL).strength(-1.0F, 6000000.0F).nonOpaque().dropsNothing());
}
@Override
+142 -15
View File
@@ -8,16 +8,94 @@ import appeng.bootstrap.ModelsReloadCallback;
import appeng.bootstrap.components.IClientSetupComponent;
import appeng.bootstrap.components.IItemColorRegistrationComponent;
import appeng.bootstrap.components.IModelBakeComponent;
import appeng.client.gui.implementations.*;
import appeng.client.gui.implementations.CellWorkbenchScreen;
import appeng.client.gui.implementations.ChestScreen;
import appeng.client.gui.implementations.CondenserScreen;
import appeng.client.gui.implementations.CraftAmountScreen;
import appeng.client.gui.implementations.CraftConfirmScreen;
import appeng.client.gui.implementations.CraftingCPUScreen;
import appeng.client.gui.implementations.CraftingStatusScreen;
import appeng.client.gui.implementations.CraftingTermScreen;
import appeng.client.gui.implementations.DriveScreen;
import appeng.client.gui.implementations.FormationPlaneScreen;
import appeng.client.gui.implementations.GrinderScreen;
import appeng.client.gui.implementations.IOPortScreen;
import appeng.client.gui.implementations.InscriberScreen;
import appeng.client.gui.implementations.InterfaceScreen;
import appeng.client.gui.implementations.InterfaceTerminalScreen;
import appeng.client.gui.implementations.LevelEmitterScreen;
import appeng.client.gui.implementations.MEMonitorableScreen;
import appeng.client.gui.implementations.MEPortableCellScreen;
import appeng.client.gui.implementations.MolecularAssemblerScreen;
import appeng.client.gui.implementations.NetworkStatusScreen;
import appeng.client.gui.implementations.NetworkToolScreen;
import appeng.client.gui.implementations.PatternTermScreen;
import appeng.client.gui.implementations.PriorityScreen;
import appeng.client.gui.implementations.QNBScreen;
import appeng.client.gui.implementations.QuartzKnifeScreen;
import appeng.client.gui.implementations.SecurityStationScreen;
import appeng.client.gui.implementations.SkyChestScreen;
import appeng.client.gui.implementations.SpatialIOPortScreen;
import appeng.client.gui.implementations.StorageBusScreen;
import appeng.client.gui.implementations.UpgradeableScreen;
import appeng.client.gui.implementations.VibrationChamberScreen;
import appeng.client.gui.implementations.WirelessScreen;
import appeng.client.gui.implementations.WirelessTermScreen;
import appeng.client.render.FacadeItemModel;
import appeng.client.render.SimpleModelLoader;
import appeng.client.render.cablebus.CableBusModelLoader;
import appeng.client.render.cablebus.P2PTunnelFrequencyModel;
import appeng.client.render.crafting.CraftingCubeModel;
import appeng.client.render.effects.*;
import appeng.client.render.model.*;
import appeng.client.render.effects.ChargedOreFX;
import appeng.client.render.effects.CraftingFx;
import appeng.client.render.effects.EnergyFx;
import appeng.client.render.effects.LightningArcFX;
import appeng.client.render.effects.LightningFX;
import appeng.client.render.effects.MatterCannonFX;
import appeng.client.render.effects.ParticleTypes;
import appeng.client.render.effects.VibrantFX;
import appeng.client.render.model.BiometricCardModel;
import appeng.client.render.model.ColorApplicatorModel;
import appeng.client.render.model.DriveModel;
import appeng.client.render.model.GlassModel;
import appeng.client.render.model.MemoryCardModel;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.spatial.SpatialPylonModel;
import appeng.client.render.tesr.InscriberTESR;
import appeng.client.render.tesr.SkyChestTESR;
import appeng.container.implementations.*;
import appeng.container.implementations.CellWorkbenchContainer;
import appeng.container.implementations.ChestContainer;
import appeng.container.implementations.CondenserContainer;
import appeng.container.implementations.CraftAmountContainer;
import appeng.container.implementations.CraftConfirmContainer;
import appeng.container.implementations.CraftingCPUContainer;
import appeng.container.implementations.CraftingStatusContainer;
import appeng.container.implementations.CraftingTermContainer;
import appeng.container.implementations.DriveContainer;
import appeng.container.implementations.FormationPlaneContainer;
import appeng.container.implementations.GrinderContainer;
import appeng.container.implementations.IOPortContainer;
import appeng.container.implementations.InscriberContainer;
import appeng.container.implementations.InterfaceContainer;
import appeng.container.implementations.InterfaceTerminalContainer;
import appeng.container.implementations.LevelEmitterContainer;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.container.implementations.MEPortableCellContainer;
import appeng.container.implementations.MolecularAssemblerContainer;
import appeng.container.implementations.NetworkStatusContainer;
import appeng.container.implementations.NetworkToolContainer;
import appeng.container.implementations.PatternTermContainer;
import appeng.container.implementations.PriorityContainer;
import appeng.container.implementations.QNBContainer;
import appeng.container.implementations.QuartzKnifeContainer;
import appeng.container.implementations.SecurityStationContainer;
import appeng.container.implementations.SkyChestContainer;
import appeng.container.implementations.SpatialIOPortContainer;
import appeng.container.implementations.StorageBusContainer;
import appeng.container.implementations.UpgradeableContainer;
import appeng.container.implementations.VibrationChamberContainer;
import appeng.container.implementations.WirelessContainer;
import appeng.container.implementations.WirelessTermContainer;
import appeng.core.Api;
import appeng.core.ApiDefinitions;
import appeng.core.AppEng;
@@ -25,10 +103,26 @@ import appeng.core.AppEngBase;
import appeng.core.features.registries.PartModels;
import appeng.core.sync.network.ClientNetworkHandler;
import appeng.core.worlddata.WorldData;
import appeng.entity.*;
import appeng.fluids.client.gui.*;
import appeng.fluids.container.*;
import appeng.entity.ChargedQuartzEntity;
import appeng.entity.GrowingCrystalEntity;
import appeng.entity.SingularityEntity;
import appeng.entity.TinyTNTPrimedEntity;
import appeng.entity.TinyTNTPrimedRenderer;
import appeng.fluids.client.gui.FluidFormationPlaneScreen;
import appeng.fluids.client.gui.FluidIOScreen;
import appeng.fluids.client.gui.FluidInterfaceScreen;
import appeng.fluids.client.gui.FluidLevelEmitterScreen;
import appeng.fluids.client.gui.FluidStorageBusScreen;
import appeng.fluids.client.gui.FluidTerminalScreen;
import appeng.fluids.container.FluidFormationPlaneContainer;
import appeng.fluids.container.FluidIOContainer;
import appeng.fluids.container.FluidInterfaceContainer;
import appeng.fluids.container.FluidLevelEmitterContainer;
import appeng.fluids.container.FluidStorageBusContainer;
import appeng.fluids.container.FluidTerminalContainer;
import appeng.hooks.ClientTickHandler;
import appeng.parts.automation.PlaneModel;
import appeng.tile.crafting.MolecularAssemblerRenderer;
import appeng.util.Platform;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@@ -53,7 +147,11 @@ import net.minecraft.util.hit.HitResult;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -240,6 +338,18 @@ public final class AppEngClient extends AppEngBase {
private void registerModelProviders() {
ModelLoadingRegistry.INSTANCE.registerAppender((resourceManager, consumer) -> {
consumer.accept(MolecularAssemblerRenderer.LIGHTS_MODEL);
});
ModelLoadingRegistry.INSTANCE.registerVariantProvider((resourceManager) -> {
return (modelIdentifier, modelProviderContext) -> {
if (MolecularAssemblerRenderer.LIGHTS_MODEL.equals(modelIdentifier)) {
return modelProviderContext.loadModel(new Identifier(modelIdentifier.getNamespace(), modelIdentifier.getPath()));
}
return null;
};
});
ModelLoadingRegistry.INSTANCE.registerResourceProvider(rm -> new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
addBuiltInModel("block/quartz_glass", GlassModel::new);
@@ -249,14 +359,24 @@ public final class AppEngClient extends AppEngBase {
addBuiltInModel("item/memory_card", MemoryCardModel::new);
addBuiltInModel("item/biometric_card", BiometricCardModel::new);
addBuiltInModel("block/drive", DriveModel::new);
addBuiltInModel("color_applicator", ColorApplicatorModel::new); // FIXME need to wire this up
addBuiltInModel("color_applicator", ColorApplicatorModel::new); // FIXME need to wire this up (this might just not be needed)
addBuiltInModel("block/spatial_pylon", SpatialPylonModel::new);
addBuiltInModel("block/paint", PaintSplotchesModel::new);
addBuiltInModel("block/qnb/qnb_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, "part_plane"),
// FIXME FABRIC PlaneModelLoader.INSTANCE);
addBuiltInModel("block/qnb/qnb_formed", QnbFormedModel::new);
addBuiltInModel("part/p2p/p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
addBuiltInModel("item/facade", FacadeItemModel::new);
addPlaneModel("part/annihilation_plane", "part/annihilation_plane");
addPlaneModel("part/annihilation_plane_on", "part/annihilation_plane_on");
addPlaneModel("part/identity_annihilation_plane", "part/identity_annihilation_plane");
addPlaneModel("part/identity_annihilation_plane_on", "part/identity_annihilation_plane_on");
addPlaneModel("part/fluid_annihilation_plane", "part/fluid_annihilation_plane");
addPlaneModel("part/fluid_annihilation_plane_on", "part/fluid_annihilation_plane_on");
addPlaneModel("part/fluid_formation_plane", "part/fluid_formation_plane");
addPlaneModel("part/fluid_formation_plane_on", "part/fluid_formation_plane_on");
addPlaneModel("part/formation_plane", "part/formation_plane");
addPlaneModel("part/formation_plane_on", "part/formation_plane_on");
addBuiltInModel("block/crafting/1k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_1K));
addBuiltInModel("block/crafting/4k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_4K));
addBuiltInModel("block/crafting/16k_storage_formed", () -> new CraftingCubeModel(AbstractCraftingUnitBlock.CraftingUnitType.STORAGE_16K));
@@ -267,9 +387,16 @@ public final class AppEngClient extends AppEngBase {
// FIXME FABRIC ModelLoaderRegistry.registerLoader(new Identifier(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE);
}
private static void addPlaneModel(String planeName, String frontTexture) {
Identifier frontTextureId = AppEng.makeId(frontTexture);
Identifier sidesTextureId = AppEng.makeId("part/plane_sides");
Identifier backTextureId = AppEng.makeId("part/transition_plane_back");
addBuiltInModel(planeName, () -> new PlaneModel(frontTextureId, sidesTextureId, backTextureId));
}
private static <T extends UnbakedModel> void addBuiltInModel(String id, Supplier<T> modelFactory) {
ModelLoadingRegistry.INSTANCE.registerResourceProvider(
resourceManager -> new SimpleModelLoader<T>(AppEng.makeId(id), modelFactory)
resourceManager -> new SimpleModelLoader<>(AppEng.makeId(id), modelFactory)
);
}
@@ -18,43 +18,9 @@
package appeng.client.gui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import appeng.mixins.SlotMixin;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Style;
import net.minecraft.util.Formatting;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.text.Text;
import alexiil.mc.lib.attributes.fluid.render.FluidRenderFace;
import alexiil.mc.lib.attributes.fluid.render.FluidVolumeRenderer;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.client.gui.widgets.CustomSlotWidget;
@@ -85,6 +51,41 @@ import appeng.core.sync.packets.SwapSlotsPacket;
import appeng.fluids.client.render.FluidStackSizeRenderer;
import appeng.fluids.container.slots.IMEFluidSlot;
import appeng.helpers.InventoryAction;
import appeng.mixins.SlotMixin;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.widget.AbstractButtonWidget;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScreen<T> {
@@ -189,7 +190,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
}
final Text msg = tooltip.getMessage();
if (msg != null && !msg.isEmpty()) {
if (msg != null && !msg.getString().isEmpty()) {
this.drawTooltip(matrices, x + 11, y + 4, msg);
}
}
@@ -328,7 +329,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
// TODO 1.9.4 aftermath - Whole SlotActionType thing, to be checked.
@Override
protected void onMouseClick(final Slot slot, final int slotIdx, final int mouseButton,
final SlotActionType clickType) {
final SlotActionType clickType) {
final PlayerEntity player = getPlayer();
if (slot instanceof FakeSlot) {
@@ -510,7 +511,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
}
protected int getSlotIndex(Slot slot) {
return ((SlotMixin)slot).getIndex();
return ((SlotMixin) slot).getIndex();
}
protected boolean checkHotbarKeys(int keyCode, int scanCode) {
@@ -652,7 +653,16 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
final IAEFluidStack fs = slot.getAEFluidStack();
if (fs != null && this.isPowered()) {
fs.getFluidStack().renderGuiRect(s.x, s.y, s.x + 16, s.y + 16);
List<FluidRenderFace> faces = new ArrayList<>();
faces.add(FluidRenderFace.createFlatFaceZ(0, 0, 0, 16, 16, 0, 1 / 16., false, false));
matrices.push();
matrices.translate(s.x, s.y, 0);
FluidVolume fluidStack = fs.getFluidStack();
fluidStack.render(faces, FluidVolumeRenderer.VCPS, matrices);
RenderSystem.runAsFancy(FluidVolumeRenderer.VCPS::draw);
matrices.pop();
this.fluidStackSizeRenderer.renderStackSize(this.textRenderer, fs, s.x, s.y);
} else if (!this.isPowered()) {
@@ -786,7 +796,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
public void tick() {
super.tick();
for (IGuiEventListener child : children) {
for (Element child : children) {
if (child instanceof ITickingWidget) {
((ITickingWidget) child).tick();
}
@@ -20,9 +20,7 @@ package appeng.client.gui.implementations;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
@@ -57,7 +57,7 @@ public class LevelEmitterScreen extends UpgradeableScreen<LevelEmitterContainer>
this::onLevelChange);
this.level.setTextFieldBounds(25, 44, 75);
this.level.addButtons(children::add, this::addButton);
container.setTextField(this.level);
handler.setTextField(this.level);
}
private void onLevelChange(long level) {
@@ -100,7 +100,7 @@ public class LevelEmitterScreen extends UpgradeableScreen<LevelEmitterContainer>
if (notCraftingMode) {
if (currentLevelMode == LevelType.ENERGY_LEVEL) {
this.font.drawString(PowerUnits.AE.textComponent().getString(), 110, 44, COLOR_DARK_GRAY);
this.textRenderer.draw(matrices, PowerUnits.AE.textComponent().getString(), 110, 44, COLOR_DARK_GRAY);
}
}
}
@@ -3,15 +3,17 @@ package appeng.client.gui.implementations;
import java.util.function.Consumer;
import java.util.function.LongConsumer;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.IGuiEventListener;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.widget.ButtonWidget;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.NumberEntryType;
import appeng.client.gui.widgets.ITickingWidget;
import appeng.client.gui.widgets.NumberBox;
import appeng.core.AEConfig;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.LiteralText;
/**
* A utility widget that consists of a text-field to enter a number with
@@ -26,14 +28,14 @@ public class NumberEntryWidget implements ITickingWidget {
private final NumberBox level;
private final NumberEntryType type;
private Button plus1;
private Button plus10;
private Button plus100;
private Button plus1000;
private Button minus1;
private Button minus10;
private Button minus100;
private Button minus1000;
private ButtonWidget plus1;
private ButtonWidget plus10;
private ButtonWidget plus100;
private ButtonWidget plus1000;
private ButtonWidget minus1;
private ButtonWidget minus10;
private ButtonWidget minus100;
private ButtonWidget minus1000;
public NumberEntryWidget(AEBaseScreen<?> parent, int x, int y, int width, int height, NumberEntryType type,
LongConsumer changeListener) {
@@ -42,20 +44,19 @@ public class NumberEntryWidget implements ITickingWidget {
this.y = y;
this.type = type;
FontRenderer font = parent.getMinecraft().fontRenderer;
int inputX = parent.getGuiLeft() + x;
int inputY = parent.getGuiTop() + y;
this.level = new NumberBox(font, inputX, inputY, width, font.FONT_HEIGHT, type.getInputType(), changeListener);
this.level.setEnableBackgroundDrawing(false);
this.level.setMaxStringLength(16);
this.level.setTextColor(0xFFFFFF);
TextRenderer font = parent.getClient().textRenderer;
int inputX = parent.getX() + x;
int inputY = parent.getY() + y;
this.level = new NumberBox(font, inputX, inputY, width, font.fontHeight, type.getInputType(), changeListener);
this.level.setHasBorder(false);
this.level.setMaxLength(16);
this.level.setEditableColor(0xFFFFFF);
this.level.setVisible(true);
this.level.setFocused2(true);
parent.setFocusedDefault(this.level);
parent.setInitialFocus(this.level);
}
public void setActive(boolean active) {
this.level.setEnabled(active);
this.level.active = active;
this.plus1.active = active;
this.plus10.active = active;
this.plus100.active = active;
@@ -67,8 +68,8 @@ public class NumberEntryWidget implements ITickingWidget {
}
public void setTextFieldBounds(int x, int y, int width) {
this.level.x = parent.getGuiLeft() + x;
this.level.y = parent.getGuiTop() + y;
this.level.x = parent.getX() + x;
this.level.y = parent.getY() + y;
this.level.setWidth(width);
}
@@ -76,28 +77,28 @@ public class NumberEntryWidget implements ITickingWidget {
this.level.setMinValue(minValue);
}
public void addButtons(Consumer<IGuiEventListener> addChildren, Consumer<Button> addButton) {
public void addButtons(Consumer<Element> addChildren, Consumer<ButtonWidget> addButton) {
final int[] steps = AEConfig.instance().getNumberEntrySteps(type);
int a = steps[0];
int b = steps[1];
int c = steps[2];
int d = steps[3];
int left = parent.getGuiLeft() + x;
int top = parent.getGuiTop() + y;
int left = parent.getX() + x;
int top = parent.getY() + y;
addButton.accept(this.plus1 = new Button(left, top, 22, 20, "+" + a, btn -> addQty(a)));
addButton.accept(this.plus10 = new Button(left + 28, top, 28, 20, "+" + b, btn -> addQty(b)));
addButton.accept(this.plus100 = new Button(left + 62, top, 32, 20, "+" + c, btn -> addQty(c)));
addButton.accept(this.plus1000 = new Button(left + 100, top, 38, 20, "+" + d, btn -> addQty(d)));
addButton.accept(this.plus1 = new ButtonWidget(left, top, 22, 20, new LiteralText("+" + a), btn -> addQty(a)));
addButton.accept(this.plus10 = new ButtonWidget(left + 28, top, 28, 20, new LiteralText("+" + b), btn -> addQty(b)));
addButton.accept(this.plus100 = new ButtonWidget(left + 62, top, 32, 20, new LiteralText("+" + c), btn -> addQty(c)));
addButton.accept(this.plus1000 = new ButtonWidget(left + 100, top, 38, 20, new LiteralText("+" + d), btn -> addQty(d)));
// Placing this here will give a sensible tab order
addChildren.accept(this.level);
addButton.accept(this.minus1 = new Button(left, top + 42, 22, 20, "-" + a, btn -> addQty(-a)));
addButton.accept(this.minus10 = new Button(left + 28, top + 42, 28, 20, "-" + b, btn -> addQty(-b)));
addButton.accept(this.minus100 = new Button(left + 62, top + 42, 32, 20, "-" + c, btn -> addQty(-c)));
addButton.accept(this.minus1000 = new Button(left + 100, top + 42, 38, 20, "-" + d, btn -> addQty(-d)));
addButton.accept(this.minus1 = new ButtonWidget(left, top + 42, 22, 20, new LiteralText("-" + a), btn -> addQty(-a)));
addButton.accept(this.minus10 = new ButtonWidget(left + 28, top + 42, 28, 20, new LiteralText("-" + b), btn -> addQty(-b)));
addButton.accept(this.minus100 = new ButtonWidget(left + 62, top + 42, 32, 20, new LiteralText("-" + c), btn -> addQty(-c)));
addButton.accept(this.minus1000 = new ButtonWidget(left + 100, top + 42, 38, 20, new LiteralText("-" + d), btn -> addQty(-d)));
}
private void addQty(final long i) {
@@ -106,8 +107,8 @@ public class NumberEntryWidget implements ITickingWidget {
this.level.setText(String.valueOf(Math.max(minValue, currentValue + i)));
}
public void render(int mouseX, int mouseY, float partialTicks) {
this.level.render(mouseX, mouseY, partialTicks);
public void render(MatrixStack matrices, int mouseX, int mouseY, float partialTicks) {
this.level.render(matrices, mouseX, mouseY, partialTicks);
}
public void setValue(long value, boolean skipNotify) {
@@ -49,7 +49,7 @@ public class PriorityScreen extends AEBaseScreen<PriorityContainer> {
this.priority = new NumberEntryWidget(this, 20, 30, 138, 62, NumberEntryType.PRIORITY, this::onPriorityChange);
this.priority.setTextFieldBounds(62, 57, 50);
this.priority.setMinValue(Integer.MIN_VALUE);
container.setTextField(this.priority);
handler.setTextField(this.priority);
this.priority.addButtons(children::add, this::addButton);
this.subGui.addBackButton(this::addButton, 154, 0);
@@ -1,12 +1,13 @@
package appeng.client.gui.widgets;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.Screen;
/**
* Indicates that a widget (anything that is in the {@link Screen#children()}
* list) should receive callbacks every tick.
*/
public interface ITickingWidget {
public interface ITickingWidget extends Element {
void tick();
@@ -38,7 +38,7 @@ public class NumberBox extends TextFieldWidget {
final Class<?> type, LongConsumer changeListener) {
super(fontRenderer, x, y, width, height, new LiteralText("0"));
this.setText("0");
setResponder(this::onTextChanged);
setChangedListener(this::onTextChanged);
this.lastValue = 0;
this.changeListener = changeListener;
if (type == int.class || type == Integer.class) {
@@ -315,7 +315,7 @@ public class SettingToggleButton<T extends Enum<T>> extends IconButton {
return new LiteralText(name + '\n' + sb);
}
return "";
return LiteralText.EMPTY;
}
public String getFillVar() {
@@ -93,7 +93,7 @@ public class ToggleButton extends ButtonWidget implements ITooltip {
return new LiteralText(name + '\n' + sb);
}
return "";
return LiteralText.EMPTY;
}
@Override
@@ -0,0 +1,109 @@
/*
* 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;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.block.BlockState;
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.Sprite;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
/**
* @author DrummerMC
* @version rv6 - 2018-01-22
* @since rv6 2018-01-22
*/
public class DummyFluidBakedModel implements BakedModel, FabricBakedModel {
private final FluidVolume volume;
public DummyFluidBakedModel(FluidVolume volume) {
this.volume = volume;
}
@Override
public boolean isVanillaAdapter() {
return false;
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
// Not used as an item model
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
volume.renderGuiRect(0, 0, 16, 16);
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
return Collections.emptyList();
}
@Override
public boolean useAmbientOcclusion() {
return false;
}
@Override
public boolean hasDepth() {
return false;
}
@Override
public boolean isSideLit() {
return false;
}
@Override
public boolean isBuiltin() {
return false;
}
@Override
public Sprite getSprite() {
return null;
}
@Override
public ModelTransformation getTransformation() {
return null;
}
@Override
public ModelOverrideList getOverrides() {
return ModelOverrideList.EMPTY;
}
}
@@ -0,0 +1,87 @@
/*
* 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
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.item.ItemStack;
import net.minecraft.util.math.Direction;
import appeng.client.render.cablebus.FacadeBuilder;
/**
* This model used the provided FacadeBuilder to "slice" the item quads for the
* facade provided.
*
* @author covers1624
*/
public class FacadeBakedItemModel extends ForwardingBakedModel implements FabricBakedModel {
private final ItemStack textureStack;
private final FacadeBuilder facadeBuilder;
private List<BakedQuad> quads = null;
protected FacadeBakedItemModel(BakedModel base, ItemStack textureStack, FacadeBuilder facadeBuilder) {
this.wrapped = base;
this.textureStack = textureStack;
this.facadeBuilder = facadeBuilder;
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
super.emitItemQuads(stack, randomSupplier, context);
if (quads == null) {
quads = new ArrayList<>();
quads.addAll(this.facadeBuilder.buildFacadeItemQuads(this.textureStack, Direction.NORTH));
quads = Collections.unmodifiableList(quads);
}
}
@Override
public boolean hasDepth() {
return false;
}
@Override
public boolean isSideLit() {
return false;
}
@Override
public boolean isBuiltin() {
return false;
}
@Override
public ModelOverrideList getOverrides() {
return ModelOverrideList.EMPTY;
}
}
@@ -0,0 +1,75 @@
/*
* 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 appeng.client.render.cablebus.FacadeBuilder;
import appeng.items.parts.FacadeItem;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import java.util.Objects;
import java.util.Random;
import java.util.function.Supplier;
/**
* This baked model class is used as a dispatcher to redirect the renderer to
* the *real* model that should be used based on the item stack. A custom Item
* Override List is used to accomplish this.
*/
public class FacadeDispatcherBakedModel extends ForwardingBakedModel {
private final FacadeBuilder facadeBuilder;
private final Int2ObjectMap<FacadeBakedItemModel> cache = new Int2ObjectArrayMap<>();
public FacadeDispatcherBakedModel(BakedModel baseModel, FacadeBuilder facadeBuilder) {
this.wrapped = baseModel;
this.facadeBuilder = facadeBuilder;
}
@Override
public boolean isVanillaAdapter() {
return false;
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
if (!(stack.getItem() instanceof FacadeItem)) {
return;
}
FacadeItem itemFacade = (FacadeItem) stack.getItem();
ItemStack textureItem = itemFacade.getTextureItem(stack);
int itemId = Item.getRawId(textureItem.getItem());
int hash = Objects.hash(itemId, textureItem.getTag());
FacadeBakedItemModel model = FacadeDispatcherBakedModel.this.cache.get(hash);
if (model == null) {
model = new FacadeBakedItemModel(FacadeDispatcherBakedModel.this.wrapped, textureItem,
FacadeDispatcherBakedModel.this.facadeBuilder);
FacadeDispatcherBakedModel.this.cache.put(hash, model);
}
context.fallbackConsumer().accept(model);
}
}
@@ -0,0 +1,57 @@
/*
* 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 appeng.client.render.cablebus.FacadeBuilder;
import appeng.core.AppEng;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;
/**
* The model class for facades. Since facades wrap existing models, they don't
* declare any dependencies here other than the cable anchor.
*/
public class FacadeItemModel implements BasicUnbakedModel {
// We use this to get the default item transforms and make our lives easier
private static final Identifier MODEL_BASE = new Identifier(AppEng.MOD_ID, "item/facade_base");
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
BakedModel bakedBaseModel = loader.bake(MODEL_BASE, rotationContainer);
FacadeBuilder facadeBuilder = new FacadeBuilder(loader);
return new FacadeDispatcherBakedModel(bakedBaseModel, facadeBuilder);
}
@Override
public Collection<Identifier> getModelDependencies() {
return Collections.singleton(MODEL_BASE);
}
}
@@ -18,6 +18,7 @@
package appeng.client.render.cablebus;
import appeng.api.parts.IDynamicPartBakedModel;
import appeng.api.parts.IPartModel;
import appeng.api.util.AECableType;
import appeng.api.util.AEColor;
@@ -25,17 +26,13 @@ import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
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;
@@ -49,8 +46,14 @@ import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import javax.annotation.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.function.Supplier;
@Environment(EnvType.CLIENT)
@@ -125,7 +128,11 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
}
context.pushTransform(QuadRotator.get(facing, Direction.UP));
if (bakedModel instanceof FabricBakedModel) {
if (bakedModel instanceof IDynamicPartBakedModel) {
((IDynamicPartBakedModel) bakedModel).emitQuads(blockView, state, pos, randomSupplier, context,
facing, partModelData);
}
else if (bakedModel instanceof FabricBakedModel) {
((FabricBakedModel) bakedModel).emitBlockQuads(blockView, state, pos, randomSupplier, context);
} else {
context.fallbackConsumer().accept(bakedModel);
@@ -134,7 +141,8 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
}
}
// FIXME this.facadeBuilder.buildFacadeQuads(layer, renderState, randomSupplier, context, this.partModels::get);
Mesh mesh = this.facadeBuilder.getFacadeMesh(renderState, randomSupplier, this.partModels::get);
context.meshConsumer().accept(mesh);
}
// Determines whether a cable is connected to exactly two sides that are
@@ -67,7 +67,7 @@ public class CableBusModel implements BasicUnbakedModel {
Map<Identifier, BakedModel> partModels = this.loadPartModels(loader, rotationContainer);
CableBuilder cableBuilder = new CableBuilder(textureGetter);
FacadeBuilder facadeBuilder = new FacadeBuilder();
FacadeBuilder facadeBuilder = new FacadeBuilder(loader);
// This should normally not be used, but we *have* to provide a particle texture
// or otherwise damage models will
@@ -0,0 +1,85 @@
/*
* 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 javax.annotation.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.fluid.FluidState;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockRenderView;
import net.minecraft.world.chunk.light.LightingProvider;
import net.minecraft.world.level.ColorResolver;
/**
* This is used to retrieve the ExtendedState of a block for facade rendering.
* It fakes the block at BlockPos provided as the BlockState provided.
*
* @author covers1624
*/
public class FacadeBlockAccess implements BlockRenderView {
private final BlockRenderView world;
private final BlockPos pos;
private final Direction side;
private final BlockState state;
public FacadeBlockAccess(BlockRenderView world, BlockPos pos, Direction side, BlockState state) {
this.world = world;
this.pos = pos;
this.side = side;
this.state = state;
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pos) {
return this.world.getBlockEntity(pos);
}
@Override
public BlockState getBlockState(BlockPos pos) {
if (this.pos == pos) {
return this.state;
}
return this.world.getBlockState(pos);
}
@Override
public FluidState getFluidState(BlockPos pos) {
return world.getFluidState(pos);
}
@Override
public LightingProvider getLightingProvider() {
return world.getLightingProvider();
}
@Override
public float getBrightness(Direction direction, boolean shaded) {
return world.getBrightness(direction, shaded);
}
@Override
public int getColor(BlockPos pos, ColorResolver colorResolver) {
return world.getColor(pos, colorResolver);
}
}
@@ -18,8 +18,42 @@
package appeng.client.render.cablebus;
import appeng.api.util.AEAxisAlignedBB;
import appeng.core.Api;
import appeng.parts.misc.CableAnchorPart;
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadClamper;
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadCornerKicker;
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadFaceStripper;
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadReInterpolator;
import appeng.thirdparty.codechicken.lib.model.pipeline.transformers.QuadTinter;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
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.ModelHelper;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.render.block.BlockRenderManager;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.render.model.ModelRotation;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.Axis;
import net.minecraft.world.BlockRenderView;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -28,31 +62,6 @@ 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.util.AEAxisAlignedBB;
import appeng.core.Api;
import appeng.parts.misc.CableAnchorPart;
/**
* The FacadeBuilder builds for facades..
*
@@ -60,43 +69,93 @@ import appeng.parts.misc.CableAnchorPart;
*/
public class FacadeBuilder {
private final Renderer renderer = RendererAccess.INSTANCE.getRenderer();
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[] {
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) };
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[] {
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) };
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);
private final Map<Direction, Mesh> cableAnchorStilts;
public void buildFacadeQuads(RenderLayer layer, CableBusRenderState renderState, Supplier<Random> rand,
RenderContext context, Function<Identifier, BakedModel> modelLookup) {
public FacadeBuilder(ModelLoader modelLoader) {
cableAnchorStilts = buildCableAnchorStems(modelLoader);
}
/**
* Build a map of pre-rotated cable anchor stilts, which are the shortened cable anchors that
* will still be visible for facades attached to a cable.
*/
private Map<Direction, Mesh> buildCableAnchorStems(ModelLoader modelLoader) {
Map<Direction, Mesh> stems = new EnumMap<>(Direction.class);
List<BakedModel> cableAnchorParts = new ArrayList<>();
for (Identifier model : CableAnchorPart.FACADE_MODELS.getModels()) {
BakedModel cableAnchor = modelLoader.bake(model, ModelRotation.X0_Y0);
cableAnchorParts.add(cableAnchor);
}
// Create pre-rotated variants of the cable anchor stems
for (Direction side : Direction.values()) {
RenderContext.QuadTransform rotator = QuadRotator.get(side, Direction.UP);
MeshBuilder meshBuilder = renderer.meshBuilder();
QuadEmitter emitter = meshBuilder.getEmitter();
for (BakedModel model : cableAnchorParts) {
for (int cullFaceIdx = 0; cullFaceIdx <= ModelHelper.NULL_FACE_ID; cullFaceIdx++) {
Direction cullFace = ModelHelper.faceFromIndex(cullFaceIdx);
List<BakedQuad> quads = model.getQuads(null, cullFace, new Random());
for (BakedQuad quad : quads) {
emitter.fromVanilla(quad.getVertexData(), 0, false);
emitter.cullFace(cullFace);
emitter.nominalFace(quad.getFace());
if (!rotator.transform(emitter)) {
continue;
}
emitter.emit();
}
}
}
stems.put(side, meshBuilder.build());
}
return stems;
}
// private final ThreadLocal<BakedPipeline> pipelines = ThreadLocal.withInitial(() -> BakedPipeline.builder()
// // Clamper is responsible for clamping the vertex to the bounds specified.
// .addElement("clamper", QuadClamper.FACTORY)
// // Strips faces if they match a mask.
// .addElement("face_stripper", QuadFaceStripper.FACTORY)
// // Kicks the edge inner corners in, solves Z fighting
// .addElement("corner_kicker", QuadCornerKicker.FACTORY)
// // Re-Interpolates the UV's for the quad.
// .addElement("interp", QuadReInterpolator.FACTORY)
// // Tints the quad if we need it to. Disabled by default.
// .addElement("tinter", QuadTinter.FACTORY, false)
// // Overrides the quad's alpha if we are forcing transparent facades.
// .addElement("transparent", QuadAlphaOverride.FACTORY, false, e -> e.setAlphaOverride(0x4C / 255F)).build()//
// );
public Mesh getFacadeMesh(CableBusRenderState renderState,
Supplier<Random> rand,
Function<Identifier, BakedModel> modelLookup) {
//FIXME BakedPipeline pipeline = this.pipelines.get();
//FIXME Quad collectorQuad = this.collectors.get();
boolean transparent = Api.instance().partHelper().getCableRenderMode().transparentFacades;
@@ -108,32 +167,29 @@ public class FacadeBuilder {
BlockColors blockColors = MinecraftClient.getInstance().getBlockColors();
boolean thinFacades = isUseThinFacades(partBoxes);
MeshBuilder meshBuilder = renderer.meshBuilder();
QuadEmitter emitter = meshBuilder.getEmitter();
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;
if (renderStilt) {
cableAnchorStilts.get(entry.getKey()).forEach(quad -> {
quad.copyTo(emitter);
emitter.emit();
});
}
BlockState blockState = facadeRenderState.getSourceBlock();
// If we aren't forcing transparency let the block decide if it should render.
if (!transparent && layer != null) {
// FIXME FABRIC if (!transparent && layer != null) {
// FIXME FABRIC only one layer per block
// FIXME FABRIC if (!RenderLayers.canRenderInLayer(blockState, layer)) {
// FIXME FABRIC continue;
// FIXME FABRIC }
}
// FIXME FABRIC }
Box fullBounds = thinFacades ? THIN_FACADE_BOXES[sideIndex] : THICK_FACADE_BOXES[sideIndex];
Box facadeBox = fullBounds;
@@ -179,97 +235,114 @@ public class FacadeBuilder {
}
}
// calculate the side mask.
int facadeMask = 0;
for (Entry<Direction, FacadeRenderState> ent : facadeStates.entrySet()) {
Direction s = ent.getKey();
if (s.getAxis() != side.getAxis()) {
FacadeRenderState otherState = ent.getValue();
if (!otherState.isTransparent()) {
facadeMask |= 1 << s.ordinal();
}
}
}
AEAxisAlignedBB cutOutBox = getCutOutBox(facadeBox, partBoxes);
List<Box> holeStrips = getBoxes(facadeBox, cutOutBox, side.getAxis());
// FIXME BlockRenderView facadeAccess = new FacadeBlockAccess(parentWorld, pos, side, blockState);
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 }
BlockRenderManager dispatcher = MinecraftClient.getInstance().getBlockRenderManager();
BakedModel model = dispatcher.getModel(blockState);
QuadFaceStripper faceStripper = new QuadFaceStripper(fullBounds, facadeMask);
// Setup the kicker.
QuadCornerKicker kicker = new QuadCornerKicker();
kicker.setSide(sideIndex);
kicker.setFacadeMask(facadeMask);
kicker.setBox(fullBounds);
kicker.setThickness(thinFacades ? THIN_THICKNESS : THICK_THICKNESS);
QuadReInterpolator interpolator = new QuadReInterpolator();
for (int cullFaceIdx = 0; cullFaceIdx <= ModelHelper.NULL_FACE_ID; cullFaceIdx++) {
Direction cullFace = ModelHelper.faceFromIndex(cullFaceIdx);
List<BakedQuad> quads = model.getQuads(blockState, cullFace, rand.get());
for (BakedQuad quad : quads) {
QuadTinter quadTinter = null;
// Prebake the color tint into the quad
if (quad.getColorIndex() != -1) {
quadTinter = new QuadTinter(blockColors.getColor(blockState, facadeAccess, pos, quad.getColorIndex()));
}
for (Box box : holeStrips) {
emitter.fromVanilla(quad.getVertexData(), 0, false);
emitter.cullFace(cullFace);
emitter.nominalFace(quad.getFace());
interpolator.setInputQuad(emitter);
QuadClamper clamper = new QuadClamper(box);
if (!clamper.transform(emitter)) {
continue;
}
// Strips faces if they match a mask.
if (!faceStripper.transform(emitter)) {
continue;
}
// Kicks the edge inner corners in, solves Z fighting
if (!kicker.transform(emitter)) {
continue;
}
interpolator.transform(emitter);
// Tints the quad if we need it to. Disabled by default.
if (quadTinter != null) {
quadTinter.transform(emitter);
}
// // Overrides the quad's alpha if we are forcing transparent facades.
// .addElement("transparent", QuadAlphaOverride.FACTORY, false, e -> e.setAlphaOverride(0x4C / 255F)).build()//
emitter.emit();
}
}
}
// FIXME FABRIC List<BakedQuad> modelQuads = new ArrayList<>();
// FIXME FABRIC modelQuads.addAll(gatherQuads(model, blockState, rand));
// 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 // 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 }
}
return meshBuilder.build();
}
/**
@@ -362,7 +435,6 @@ public class FacadeBuilder {
* @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) {
@@ -0,0 +1,134 @@
package appeng.client.render.cablebus;
import appeng.api.parts.IDynamicPartBakedModel;
import appeng.api.util.AEColor;
import appeng.util.Platform;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
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.render.RenderContext;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import javax.annotation.Nullable;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
public class P2PTunnelFrequencyBakedModel implements IDynamicPartBakedModel {
private final Renderer renderer = RendererAccess.INSTANCE.getRenderer();
private final Sprite texture;
private final static Cache<Long, Mesh> modelCache = CacheBuilder.newBuilder().maximumSize(100).build();
private static final int[][] QUAD_OFFSETS = new int[][]{{4, 10, 2}, {10, 10, 2}, {4, 4, 2}, {10, 4, 2}};
public P2PTunnelFrequencyBakedModel(final Sprite texture) {
this.texture = texture;
}
@Override
public void emitQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context,
Direction partSide, @Nullable Object modelData) {
if (!(modelData instanceof Long)) {
return;
}
long frequency = (long) modelData;
Mesh frequencyMesh = getFrequencyModel(frequency);
if (frequencyMesh != null) {
context.meshConsumer().accept(frequencyMesh);
}
}
@Override
public ModelTransformation getTransformation() {
return ModelTransformation.NONE;
}
private Mesh createFrequencyMesh(final short frequency, final boolean active) {
MeshBuilder meshBuilder = renderer.meshBuilder();
final AEColor[] colors = Platform.p2p().toColors(frequency);
final CubeBuilder cb = new CubeBuilder(meshBuilder.getEmitter());
cb.setTexture(this.texture);
cb.useStandardUV();
cb.setRenderFullBright(active);
for (int i = 0; i < 4; ++i) {
final int[] offs = QUAD_OFFSETS[i];
for (int j = 0; j < 4; ++j) {
final float[] cv = colors[j].dye.getColorComponents();
if (active) {
cb.setColorRGB(cv[0], cv[1], cv[2]);
} else {
cb.setColorRGB(cv[0] * 0.5f, cv[1] * 0.5f, cv[2] * 0.5f);
}
final int startx = j % 2;
final int starty = 1 - j / 2;
cb.addCube(offs[0] + startx, offs[1] + starty, offs[2], offs[0] + startx + 1, offs[1] + starty + 1,
offs[2] + 1);
}
}
return meshBuilder.build();
}
private Mesh getFrequencyModel(long partFlags) {
try {
return modelCache.get(partFlags, () -> {
short frequency = (short) (partFlags & 0xffffL);
boolean active = (partFlags & 0x10000L) != 0;
return this.createFrequencyMesh(frequency, active);
});
} catch (ExecutionException e) {
return null;
}
}
@Override
public boolean useAmbientOcclusion() {
return false;
}
@Override
public boolean hasDepth() {
return false;
}
@Override
public boolean isSideLit() {
return false;
}
@Override
public boolean isBuiltin() {
return true;
}
@Override
public Sprite getSprite() {
return this.texture;
}
@Override
public ModelOverrideList getOverrides() {
return ModelOverrideList.EMPTY;
}
}
@@ -0,0 +1,34 @@
package appeng.client.render.cablebus;
import appeng.client.render.BasicUnbakedModel;
import appeng.core.AppEng;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.function.Function;
import java.util.stream.Stream;
public class P2PTunnelFrequencyModel implements BasicUnbakedModel {
private static final SpriteIdentifier TEXTURE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "part/p2p_tunnel_frequency"));
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
final Sprite texture = textureGetter.apply(TEXTURE);
return new P2PTunnelFrequencyBakedModel(texture);
}
@Override
public Stream<SpriteIdentifier> getAdditionalTextures() {
return Stream.of(TEXTURE);
}
}
@@ -81,7 +81,7 @@ public class CraftingCPUContainer extends AEBaseContainer
}
if (te instanceof CraftingBlockEntity) {
this.setCPU(((CraftingTileEntity) te).getCluster());
this.setCPU(((CraftingBlockEntity) te).getCluster());
}
if (this.getNetwork() == null && Platform.isServer()) {
+262 -12
View File
@@ -1,8 +1,14 @@
package appeng.core;
import appeng.core.Api;
import appeng.api.config.Upgrades;
import appeng.api.definitions.IBlocks;
import appeng.api.definitions.IItems;
import appeng.api.definitions.IParts;
import appeng.api.features.AEFeature;
import appeng.api.features.IRegistryContainer;
import appeng.api.features.IWirelessTermHandler;
import appeng.api.features.IWorldGen;
import appeng.api.movable.IMovableRegistry;
import appeng.api.networking.IGridCacheRegistry;
import appeng.api.networking.crafting.ICraftingGrid;
import appeng.api.networking.energy.IEnergyGrid;
@@ -17,28 +23,82 @@ import appeng.bootstrap.components.ITileEntityRegistrationComponent;
import appeng.client.render.effects.ParticleTypes;
import appeng.container.AEBaseContainer;
import appeng.container.ContainerOpener;
import appeng.container.implementations.*;
import appeng.container.implementations.CellWorkbenchContainer;
import appeng.container.implementations.ChestContainer;
import appeng.container.implementations.CondenserContainer;
import appeng.container.implementations.CraftAmountContainer;
import appeng.container.implementations.CraftConfirmContainer;
import appeng.container.implementations.CraftingCPUContainer;
import appeng.container.implementations.CraftingStatusContainer;
import appeng.container.implementations.CraftingTermContainer;
import appeng.container.implementations.DriveContainer;
import appeng.container.implementations.FormationPlaneContainer;
import appeng.container.implementations.GrinderContainer;
import appeng.container.implementations.IOPortContainer;
import appeng.container.implementations.InscriberContainer;
import appeng.container.implementations.InterfaceContainer;
import appeng.container.implementations.InterfaceTerminalContainer;
import appeng.container.implementations.LevelEmitterContainer;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.container.implementations.MEPortableCellContainer;
import appeng.container.implementations.MolecularAssemblerContainer;
import appeng.container.implementations.NetworkStatusContainer;
import appeng.container.implementations.NetworkToolContainer;
import appeng.container.implementations.PatternTermContainer;
import appeng.container.implementations.PriorityContainer;
import appeng.container.implementations.QNBContainer;
import appeng.container.implementations.QuartzKnifeContainer;
import appeng.container.implementations.SecurityStationContainer;
import appeng.container.implementations.SkyChestContainer;
import appeng.container.implementations.SpatialIOPortContainer;
import appeng.container.implementations.StorageBusContainer;
import appeng.container.implementations.UpgradeableContainer;
import appeng.container.implementations.VibrationChamberContainer;
import appeng.container.implementations.WirelessContainer;
import appeng.container.implementations.WirelessTermContainer;
import appeng.core.features.registries.P2PTunnelRegistry;
import appeng.core.features.registries.cell.BasicCellHandler;
import appeng.core.features.registries.cell.BasicItemCellGuiHandler;
import appeng.core.features.registries.cell.CreativeCellHandler;
import appeng.core.localization.GuiText;
import appeng.core.stats.AdvancementTriggers;
import appeng.core.stats.AeStats;
import appeng.core.sync.BasePacket;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.network.TargetPoint;
import appeng.fluids.container.*;
import appeng.fluids.container.FluidFormationPlaneContainer;
import appeng.fluids.container.FluidIOContainer;
import appeng.fluids.container.FluidInterfaceContainer;
import appeng.fluids.container.FluidLevelEmitterContainer;
import appeng.fluids.container.FluidStorageBusContainer;
import appeng.fluids.container.FluidTerminalContainer;
import appeng.fluids.registries.BasicFluidCellGuiHandler;
import appeng.forge.data.AE2DataGenerators;
import appeng.hooks.ToolItemHook;
import appeng.items.tools.NetworkToolItem;
import appeng.me.cache.*;
import appeng.mixins.CriteriaRegisterMixin;
import appeng.hooks.RegisterDimensionTypeCallback;
import appeng.recipes.handlers.*;
import appeng.hooks.ToolItemHook;
import appeng.items.parts.FacadeItem;
import appeng.items.tools.NetworkToolItem;
import appeng.me.cache.CraftingGridCache;
import appeng.me.cache.EnergyGridCache;
import appeng.me.cache.GridStorageCache;
import appeng.me.cache.P2PCache;
import appeng.me.cache.PathGridCache;
import appeng.me.cache.SecurityCache;
import appeng.me.cache.SpatialPylonCache;
import appeng.me.cache.TickManagerCache;
import appeng.mixins.CriteriaRegisterMixin;
import appeng.recipes.game.DisassembleRecipe;
import appeng.recipes.game.FacadeRecipe;
import appeng.recipes.handlers.GrinderRecipe;
import appeng.recipes.handlers.GrinderRecipeSerializer;
import appeng.recipes.handlers.InscriberRecipe;
import appeng.recipes.handlers.InscriberRecipeSerializer;
import appeng.recipes.handlers.QuartzKnifeRecipeSerializer;
import appeng.server.AECommand;
import appeng.spatial.SpatialDimensionManager;
import appeng.spatial.StorageCellBiome;
import appeng.spatial.StorageChunkGenerator;
import appeng.tile.AEBaseBlockEntity;
import appeng.worldgen.ChargedQuartzOreConfig;
import appeng.worldgen.ChargedQuartzOreFeature;
import appeng.worldgen.meteorite.MeteoriteStructure;
@@ -47,6 +107,25 @@ import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BannerBlockEntity;
import net.minecraft.block.entity.BeaconBlockEntity;
import net.minecraft.block.entity.BrewingStandBlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.CommandBlockBlockEntity;
import net.minecraft.block.entity.ComparatorBlockEntity;
import net.minecraft.block.entity.DaylightDetectorBlockEntity;
import net.minecraft.block.entity.DispenserBlockEntity;
import net.minecraft.block.entity.DropperBlockEntity;
import net.minecraft.block.entity.EnchantingTableBlockEntity;
import net.minecraft.block.entity.EndPortalBlockEntity;
import net.minecraft.block.entity.EnderChestBlockEntity;
import net.minecraft.block.entity.FurnaceBlockEntity;
import net.minecraft.block.entity.HopperBlockEntity;
import net.minecraft.block.entity.MobSpawnerBlockEntity;
import net.minecraft.block.entity.PistonBlockEntity;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.block.entity.SignBlockEntity;
import net.minecraft.block.entity.SkullBlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
@@ -55,6 +134,7 @@ import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeType;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.tag.BlockTags;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
@@ -136,6 +216,177 @@ public abstract class AppEngBase implements AppEng {
registries.cell().addCellGuiHandler(new BasicFluidCellGuiHandler());
registries.matterCannon().registerAmmoItem(api.definitions().materials().matterBall().item(), 32);
// TODO: Do not use the internal API
ApiDefinitions definitions = Api.INSTANCE.definitions();
final IParts parts = definitions.parts();
final IBlocks blocks = definitions.blocks();
final IItems items = definitions.items();
// Block and part interface have different translation keys, but support the
// same upgrades
String interfaceGroup = parts.iface().asItem().getTranslationKey();
String itemIoBusGroup = GuiText.IOBuses.getTranslationKey();
String fluidIoBusGroup = GuiText.IOBusesFluids.getTranslationKey();
String storageCellGroup = GuiText.IOBusesFluids.getTranslationKey();
// default settings..
((P2PTunnelRegistry) registries.p2pTunnel()).configure();
// Interface
Upgrades.CRAFTING.registerItem(parts.iface(), 1, interfaceGroup);
Upgrades.CRAFTING.registerItem(blocks.iface(), 1, interfaceGroup);
// IO Port!
Upgrades.SPEED.registerItem(blocks.iOPort(), 3);
Upgrades.REDSTONE.registerItem(blocks.iOPort(), 1);
// Level Emitter!
Upgrades.FUZZY.registerItem(parts.levelEmitter(), 1);
Upgrades.CRAFTING.registerItem(parts.levelEmitter(), 1);
// Import Bus
Upgrades.FUZZY.registerItem(parts.importBus(), 1, itemIoBusGroup);
Upgrades.REDSTONE.registerItem(parts.importBus(), 1, itemIoBusGroup);
Upgrades.CAPACITY.registerItem(parts.importBus(), 2, itemIoBusGroup);
Upgrades.SPEED.registerItem(parts.importBus(), 4, itemIoBusGroup);
// Fluid Import Bus
Upgrades.CAPACITY.registerItem(parts.fluidImportBus(), 2, fluidIoBusGroup);
Upgrades.REDSTONE.registerItem(parts.fluidImportBus(), 1, fluidIoBusGroup);
Upgrades.SPEED.registerItem(parts.fluidImportBus(), 4, fluidIoBusGroup);
// Export Bus
Upgrades.FUZZY.registerItem(parts.exportBus(), 1, itemIoBusGroup);
Upgrades.REDSTONE.registerItem(parts.exportBus(), 1, itemIoBusGroup);
Upgrades.CAPACITY.registerItem(parts.exportBus(), 2, itemIoBusGroup);
Upgrades.SPEED.registerItem(parts.exportBus(), 4, itemIoBusGroup);
Upgrades.CRAFTING.registerItem(parts.exportBus(), 1, itemIoBusGroup);
// Fluid Export Bus
Upgrades.CAPACITY.registerItem(parts.fluidExportBus(), 2, fluidIoBusGroup);
Upgrades.REDSTONE.registerItem(parts.fluidExportBus(), 1, fluidIoBusGroup);
Upgrades.SPEED.registerItem(parts.fluidExportBus(), 4, fluidIoBusGroup);
// Storage Cells
Upgrades.FUZZY.registerItem(items.cell1k(), 1, storageCellGroup);
Upgrades.INVERTER.registerItem(items.cell1k(), 1, storageCellGroup);
Upgrades.FUZZY.registerItem(items.cell4k(), 1, storageCellGroup);
Upgrades.INVERTER.registerItem(items.cell4k(), 1, storageCellGroup);
Upgrades.FUZZY.registerItem(items.cell16k(), 1, storageCellGroup);
Upgrades.INVERTER.registerItem(items.cell16k(), 1, storageCellGroup);
Upgrades.FUZZY.registerItem(items.cell64k(), 1, storageCellGroup);
Upgrades.INVERTER.registerItem(items.cell64k(), 1, storageCellGroup);
Upgrades.FUZZY.registerItem(items.portableCell(), 1, storageCellGroup);
Upgrades.INVERTER.registerItem(items.portableCell(), 1, storageCellGroup);
Upgrades.FUZZY.registerItem(items.viewCell(), 1);
Upgrades.INVERTER.registerItem(items.viewCell(), 1);
// Storage Bus
Upgrades.FUZZY.registerItem(parts.storageBus(), 1);
Upgrades.INVERTER.registerItem(parts.storageBus(), 1);
Upgrades.CAPACITY.registerItem(parts.storageBus(), 5);
// Storage Bus Fluids
Upgrades.INVERTER.registerItem(parts.fluidStorageBus(), 1);
Upgrades.CAPACITY.registerItem(parts.fluidStorageBus(), 5);
// Formation Plane
Upgrades.FUZZY.registerItem(parts.formationPlane(), 1);
Upgrades.INVERTER.registerItem(parts.formationPlane(), 1);
Upgrades.CAPACITY.registerItem(parts.formationPlane(), 5);
// Matter Cannon
Upgrades.FUZZY.registerItem(items.massCannon(), 1);
Upgrades.INVERTER.registerItem(items.massCannon(), 1);
Upgrades.SPEED.registerItem(items.massCannon(), 4);
// Molecular Assembler
Upgrades.SPEED.registerItem(blocks.molecularAssembler(), 5);
// Inscriber
Upgrades.SPEED.registerItem(blocks.inscriber(), 3);
// Wireless Terminal Handler
items.wirelessTerminal().maybeItem()
.ifPresent(terminal -> registries.wireless().registerWirelessHandler((IWirelessTermHandler) terminal));
// Charge Rates
items.chargedStaff().maybeItem()
.ifPresent(chargedStaff -> registries.charger().addChargeRate(chargedStaff, 320d));
items.portableCell().maybeItem()
.ifPresent(chargedStaff -> registries.charger().addChargeRate(chargedStaff, 800d));
items.colorApplicator().maybeItem()
.ifPresent(colorApplicator -> registries.charger().addChargeRate(colorApplicator, 800d));
items.wirelessTerminal().maybeItem().ifPresent(terminal -> registries.charger().addChargeRate(terminal, 8000d));
items.entropyManipulator().maybeItem()
.ifPresent(entropyManipulator -> registries.charger().addChargeRate(entropyManipulator, 8000d));
items.massCannon().maybeItem().ifPresent(massCannon -> registries.charger().addChargeRate(massCannon, 8000d));
blocks.energyCell().maybeItem().ifPresent(cell -> registries.charger().addChargeRate(cell, 8000d));
blocks.energyCellDense().maybeItem().ifPresent(cell -> registries.charger().addChargeRate(cell, 16000d));
// FIXME // add villager trading to black smiths for a few basic materials
// FIXME if( AEConfig.instance().isFeatureEnabled( AEFeature.VILLAGER_TRADING ) )
// FIXME {
// FIXME // TODO: VILLAGER TRADING
// FIXME // VillagerRegistry.instance().getRegisteredVillagers().registerVillageTradeHandler( 3, new AETrading() );
// FIXME }
final IMovableRegistry mr = registries.movable();
/*
* You can't move bed rock.
*/
mr.blacklistBlock(net.minecraft.block.Blocks.BEDROCK);
/*
* White List Vanilla...
*/
mr.whiteListBlockEntity(BannerBlockEntity.class);
mr.whiteListBlockEntity(BeaconBlockEntity.class);
mr.whiteListBlockEntity(BrewingStandBlockEntity.class);
mr.whiteListBlockEntity(ChestBlockEntity.class);
mr.whiteListBlockEntity(CommandBlockBlockEntity.class);
mr.whiteListBlockEntity(ComparatorBlockEntity.class);
mr.whiteListBlockEntity(DaylightDetectorBlockEntity.class);
mr.whiteListBlockEntity(DispenserBlockEntity.class);
mr.whiteListBlockEntity(DropperBlockEntity.class);
mr.whiteListBlockEntity(EnchantingTableBlockEntity.class);
mr.whiteListBlockEntity(EnderChestBlockEntity.class);
mr.whiteListBlockEntity(EndPortalBlockEntity.class);
mr.whiteListBlockEntity(FurnaceBlockEntity.class);
mr.whiteListBlockEntity(HopperBlockEntity.class);
mr.whiteListBlockEntity(MobSpawnerBlockEntity.class);
mr.whiteListBlockEntity(PistonBlockEntity.class);
mr.whiteListBlockEntity(ShulkerBoxBlockEntity.class);
mr.whiteListBlockEntity(SignBlockEntity.class);
mr.whiteListBlockEntity(SkullBlockEntity.class);
/*
* Whitelist AE2
*/
mr.whiteListBlockEntity(AEBaseBlockEntity.class);
/*
* world gen
*/
for (final IWorldGen.WorldGenType type : IWorldGen.WorldGenType.values()) {
// FIXME: registries.worldgen().disableWorldGenForProviderID( type,
// StorageWorldProvider.class );
registries.worldgen().disableWorldGenForDimension(type, DimensionType.THE_NETHER_REGISTRY_KEY.getValue());
}
// whitelist from config
for (final String dimension : AEConfig.instance().getMeteoriteDimensionWhitelist()) {
registries.worldgen().enableWorldGenForDimension(IWorldGen.WorldGenType.METEORITES,
new Identifier(dimension));
}
}
protected void registerParticleTypes() {
@@ -167,10 +418,9 @@ public abstract class AppEngBase implements AppEng {
Registry.register(Registry.RECIPE_SERIALIZER, AppEng.makeId("quartz_knife"), QuartzKnifeRecipeSerializer.INSTANCE);
Registry.register(Registry.RECIPE_SERIALIZER, AppEng.makeId("grinder"), GrinderRecipeSerializer.INSTANCE);
Registry.register(Registry.RECIPE_SERIALIZER, AppEng.makeId("inscriber"), InscriberRecipeSerializer.INSTANCE);
// FIXME FABRIC FacadeItem facadeItem = (FacadeItem) Api.INSTANCE.definitions().items().facade().item();
// FIXME FABRIC r.registerAll(DisassembleRecipe.SERIALIZER,
// FIXME FABRIC FacadeRecipe.getSerializer(facadeItem));
Registry.register(Registry.RECIPE_SERIALIZER, AppEng.makeId("disassemble"), DisassembleRecipe.SERIALIZER);
FacadeItem facadeItem = (FacadeItem) Api.INSTANCE.definitions().items().facade().item();
Registry.register(Registry.RECIPE_SERIALIZER, AppEng.makeId("facade"), FacadeRecipe.getSerializer(facadeItem));
}
@Override
+1 -1
View File
@@ -41,7 +41,7 @@ public final class CreativeTab {
.icon(() -> {
final IDefinitions definitions = Api.instance().definitions();
final IBlocks blocks = definitions.blocks();
return blocks.quartzOre().stack(1); // FIXME FABRIC blocks.controller().stack(1);
return blocks.controller().stack(1);
})
.appendItems(CreativeTab::fill)
.build();
@@ -27,6 +27,7 @@ import alexiil.mc.lib.attributes.fluid.FluidAttributes;
import alexiil.mc.lib.attributes.fluid.FluidExtractable;
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import appeng.crafting.CraftingLink;
import appeng.fluids.util.FluidList;
import com.google.common.base.Preconditions;
import com.google.common.collect.ClassToInstanceMap;
@@ -99,8 +100,7 @@ public class ApiStorage implements IStorageHelper {
Preconditions.checkNotNull(data);
Preconditions.checkNotNull(req);
// FIXME FABRIC return new CraftingLink(data, req);
throw new IllegalStateException();
return new CraftingLink(data, req);
}
@Override
@@ -173,7 +173,7 @@ public final class ApiBlocks implements IBlocks {
.sounds(BlockSoundGroup.GLASS)
.nonOpaque()
.allowsSpawning((state, world, pos, type) -> false)
.solidBlock((state, world, pos) -> false)
.nonOpaque()
.suffocates((state, world, pos) -> false)
.blockVision((state, world, pos) -> false);
}
@@ -249,7 +249,7 @@ public final class ApiBlocks implements IBlocks {
AbstractBlock.Settings skyStoneChestProps = defaultProps(Material.STONE)
.strength(50, 150)
.solidBlock((state, world, pos) -> false);
.nonOpaque();
TileEntityDefinition skyChestTile = registry
.tileEntity("sky_chest", SkyChestBlockEntity.class, SkyChestBlockEntity::new)
@@ -281,7 +281,7 @@ public final class ApiBlocks implements IBlocks {
this.crank = registry
.block("crank",
() -> new CrankBlock(
defaultProps(Material.WOOD).breakByTool(FabricToolTags.AXES, 0).solidBlock((state, world, pos) -> false)))
defaultProps(Material.WOOD).breakByTool(FabricToolTags.AXES, 0).nonOpaque()))
.features(AEFeature.GRIND_STONE)
.tileEntity(registry.tileEntity("crank", CrankBlockEntity.class, CrankBlockEntity::new)
.rendering(new TileEntityRenderingCustomizer<CrankBlockEntity>() {
@@ -292,7 +292,7 @@ public final class ApiBlocks implements IBlocks {
}
}).build())
.build();
this.inscriber = registry.block("inscriber", () -> new InscriberBlock(defaultProps(Material.METAL).solidBlock((state, world, pos) -> false)))
this.inscriber = registry.block("inscriber", () -> new InscriberBlock(defaultProps(Material.METAL).nonOpaque()))
.features(AEFeature.INSCRIBER)
.tileEntity(registry.tileEntity("inscriber", InscriberBlockEntity.class, InscriberBlockEntity::new)
.rendering(new InscriberRendering()).build())
@@ -486,7 +486,7 @@ public final class ApiBlocks implements IBlocks {
}).build();
this.molecularAssembler = registry
.block("molecular_assembler", () -> new MolecularAssemblerBlock(defaultProps(Material.METAL).solidBlock((state, world, pos) -> false)))
.block("molecular_assembler", () -> new MolecularAssemblerBlock(defaultProps(Material.METAL).nonOpaque()))
.features(AEFeature.MOLECULAR_ASSEMBLER).rendering(new BlockRenderingCustomizer() {
@Environment(EnvType.CLIENT)
@Override
@@ -97,8 +97,7 @@ public final class WirelessRegistry implements IWirelessTermRegistry {
}
if (handler.hasPower(player, 0.5, item)) {
// FIXME FABRIC ContainerOpener.openContainer(WirelessTermContainer.TYPE, player, ContainerLocator.forHand(player, hand));
throw new IllegalStateException();
ContainerOpener.openContainer(WirelessTermContainer.TYPE, player, ContainerLocator.forHand(player, hand));
} else {
player.sendSystemMessage(PlayerMessages.DeviceNotPowered.get(), Util.NIL_UUID);
}
@@ -18,6 +18,8 @@
package appeng.entity;
import appeng.client.EffectType;
import appeng.items.misc.CrystalSeedItem;
import net.minecraft.block.BlockState;
import net.minecraft.block.Material;
import net.minecraft.block.entity.BlockEntity;
@@ -116,8 +118,8 @@ public final class GrowingCrystalEntity extends AEBaseItemEntity {
if (this.progress_1000 >= len) {
this.progress_1000 = 0;
// FIXME FABRIC AppEng.instance().spawnEffect(EffectType.Vibrant, this.world, this.getX(), this.getY() + 0.2,
// FIXME FABRIC this.getZ(), null);
AppEng.instance().spawnEffect(EffectType.Vibrant, this.world, this.getX(), this.getY() + 0.2,
this.getZ(), null);
}
} else {
if (this.progress_1000 > 1000) {
@@ -174,11 +176,10 @@ public final class GrowingCrystalEntity extends AEBaseItemEntity {
@Override
public void applyBuoyancy() {
ItemStack item = getStack();
throw new IllegalStateException();
// FIXME FABRIC if (item.getItem() instanceof CrystalSeedItem) {
// FIXME FABRIC return;
// FIXME FABRIC }
// FIXME FABRIC super.applyBuoyancy();
if (item.getItem() instanceof CrystalSeedItem) {
return;
}
super.applyBuoyancy();
}
}
@@ -35,12 +35,12 @@ public class FluidLevelEmitterScreen extends UpgradeableScreen<FluidLevelEmitter
this.level = new NumberEntryWidget(this, 20, 17, 138, 62, NumberEntryType.LEVEL_FLUID_VOLUME,
this::onLevelChange);
this.level.setTextFieldBounds(25, 44, 75);
container.setTextField(this.level);
handler.setTextField(this.level);
this.level.addButtons(children::add, this::addButton);
final int y = 40;
final int x = 80 + 57;
this.guiSlots.add(new FluidSlotWidget(this.container.getFluidConfigInventory(), 0, 0, x, y));
this.guiSlots.add(new FluidSlotWidget(this.handler.getFluidConfigInventory(), 0, 0, x, y));
}
@Override
@@ -57,10 +57,10 @@ public class FluidLevelEmitterScreen extends UpgradeableScreen<FluidLevelEmitter
}
@Override
public void drawFG(int offsetX, int offsetY, int mouseX, int mouseY) {
super.drawFG(offsetX, offsetY, mouseX, mouseY);
public void drawFG(MatrixStack matrices, int offsetX, int offsetY, int mouseX, int mouseY) {
super.drawFG(matrices, offsetX, offsetY, mouseX, mouseY);
this.font.drawString(GuiText.FluidLevelEmitterUnit.getLocal(), 110, 44, COLOR_DARK_GRAY);
this.textRenderer.draw(matrices, GuiText.FluidLevelEmitterUnit.getLocal(), 110, 44, COLOR_DARK_GRAY);
}
@Override
@@ -1,24 +1,23 @@
package appeng.fluids.client.gui.widgets;
import java.math.RoundingMode;
import java.util.Collections;
import alexiil.mc.lib.attributes.Simulation;
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
import alexiil.mc.lib.attributes.fluid.FluidExtractable;
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import alexiil.mc.lib.attributes.fluid.GroupedFluidInvView;
import alexiil.mc.lib.attributes.fluid.volume.FluidKey;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import appeng.api.storage.data.IAEFluidStack;
import appeng.client.gui.widgets.CustomSlotWidget;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.FluidSlotPacket;
import appeng.fluids.util.AEFluidStack;
import appeng.fluids.util.IAEFluidTank;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.Set;
public class FluidSlotWidget extends CustomSlotWidget {
private final IAEFluidTank fluids;
@@ -50,9 +49,11 @@ public class FluidSlotWidget extends CustomSlotWidget {
if (clickStack.isEmpty() || mouseButton == 1) {
this.setFluidStack(null);
} else if (mouseButton == 0) {
FluidExtractable extractable = FluidAttributes.EXTRACTABLE.getFirstOrNull(clickStack);
if (extractable != null && extractable.couldExtractAnything()) {
FluidVolume volume = extractable.attemptAnyExtraction(FluidAmount.MAX_VALUE, Simulation.ACTION);
GroupedFluidInvView groupView = FluidAttributes.GROUPED_INV_VIEW.get(clickStack);
Set<FluidKey> fluids = groupView.getStoredFluids();
if (!fluids.isEmpty()) {
FluidKey firstFluid = groupView.getStoredFluids().iterator().next();
FluidVolume volume = firstFluid.withAmount(groupView.getAmount_F(firstFluid));
this.setFluidStack(AEFluidStack.fromFluidVolume(volume, RoundingMode.DOWN));
}
}
@@ -88,7 +88,7 @@ public class FluidTankWidget extends AbstractButtonWidget implements ITooltip {
return desc.copy().append("\n").append(amountToText);
}
return "";
return LiteralText.EMPTY;
}
@Override
@@ -25,9 +25,12 @@ import java.nio.BufferOverflowException;
import javax.annotation.Nonnull;
import alexiil.mc.lib.attributes.Simulation;
import alexiil.mc.lib.attributes.fluid.FixedFluidInv;
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
import alexiil.mc.lib.attributes.fluid.FluidExtractable;
import alexiil.mc.lib.attributes.fluid.FluidInsertable;
import alexiil.mc.lib.attributes.fluid.GroupedFluidInv;
import alexiil.mc.lib.attributes.fluid.SingleFluidTank;
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
import alexiil.mc.lib.attributes.fluid.filter.ExactFluidFilter;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
@@ -327,9 +330,10 @@ public class FluidTerminalContainer extends AEBaseContainer
}
// Check how much we can store in the item
FluidVolume volumeAllowed = insertable.attemptInsertion(this.clientRequestedTargetFluid.getFluidStack().withAmount(FluidAmount.MAX_VALUE), Simulation.SIMULATE);
FluidVolume volumeOverflow = insertable.attemptInsertion(this.clientRequestedTargetFluid.getFluidStack().withAmount(FluidAmount.ofWhole(Long.MAX_VALUE)), Simulation.SIMULATE);
FluidAmount amountAllowed = FluidAmount.ofWhole(Long.MAX_VALUE).saturatedSub(volumeOverflow.amount());
final IAEFluidStack stack = AEFluidStack.fromFluidVolume(this.clientRequestedTargetFluid.getFluidStack().withAmount(volumeAllowed.amount()), RoundingMode.DOWN);
final IAEFluidStack stack = AEFluidStack.fromFluidVolume(this.clientRequestedTargetFluid.getFluidStack().withAmount(amountAllowed), RoundingMode.DOWN);
if (stack == null) {
return; // Might be nothing allowed...
}
@@ -342,13 +346,13 @@ public class FluidTerminalContainer extends AEBaseContainer
}
// How much could fit into the container
volumeAllowed = insertable.attemptInsertion(canPull.getFluidStack(), Simulation.SIMULATE);
if (volumeAllowed.isEmpty()) {
volumeOverflow = insertable.attemptInsertion(canPull.getFluidStack(), Simulation.SIMULATE);
if (!volumeOverflow.isEmpty()) {
return;
}
// Now actually pull out of the system
stack.setStackSize(volumeAllowed.amount().asLong(1000, RoundingMode.DOWN));
stack.setStackSize(canPull.getStackSize());
final IAEFluidStack pulled = Platform.poweredExtraction(this.getPowerSource(), this.monitor, stack,
this.getActionSource());
if (pulled == null || pulled.getStackSize() < 1) {
@@ -358,11 +362,11 @@ public class FluidTerminalContainer extends AEBaseContainer
}
// Actually fill
final FluidVolume reallyFilled = insertable.attemptInsertion(pulled.getFluidStack(), Simulation.ACTION);
volumeOverflow = insertable.attemptInsertion(pulled.getFluidStack(), Simulation.ACTION);
if (!reallyFilled.amount().equals(volumeAllowed.amount())) {
AELog.error("Fluid item [%s] reported a different possible amount than it actually accepted.",
held.getName());
if (!volumeOverflow.isEmpty()) {
AELog.error("Fluid item [%s] reported a different possible amount than it actually accepted. Overflow: %s.",
held, volumeOverflow);
}
player.inventory.setCursorStack(container.get());
@@ -4,7 +4,7 @@ package appeng.fluids.parts;
import alexiil.mc.lib.attributes.Simulation;
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import appeng.core.Api;
import alexiil.mc.lib.attributes.fluid.world.FluidWorldUtil;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.config.IncludeExclude;
@@ -42,16 +42,14 @@ import net.minecraft.block.FluidBlock;
import net.minecraft.block.FluidFillable;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.screen.ScreenHandlerType;
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.minecraft.world.WorldAccess;
import javax.annotation.Nonnull;
import java.math.RoundingMode;
@@ -116,7 +114,7 @@ public class FluidFormationPlanePart extends AbstractFormationPlanePart<IAEFluid
final BlockPos pos = te.getPos().offset(side.getFacing());
FluidVolume volume = input.getFluidStack();
FluidVolume remainder = fill(w, pos, volume, type == Actionable.MODULATE ? Simulation.ACTION : Simulation.SIMULATE);
FluidVolume remainder = FluidWorldUtil.fill(w, pos, volume, type == Actionable.MODULATE ? Simulation.ACTION : Simulation.SIMULATE);
if (remainder.getAmount_F().isLessThan(volume.getAmount_F())) {
// calculate the effective amount consumed
// round UP here because we might otherwise duplicate fluids
@@ -132,62 +130,6 @@ public class FluidFormationPlanePart extends AbstractFormationPlanePart<IAEFluid
}
}
// FIXME https://github.com/AlexIIL/LibBlockAttributes/pull/21
/**
* Attempts to fill the given block with a bucket's worth of fluid
* @return The remainder of the given fluid volume after placing a bucket
*/
public static FluidVolume fill(WorldAccess world, BlockPos pos, FluidVolume volume, Simulation simulation) {
if (volume.getAmount_F().isLessThan(FluidAmount.BUCKET)) {
return volume; // Need at least a buckets worth
}
Fluid fluid = volume.getRawFluid();
if (fluid == null) {
return volume; // Can't be placed if it doesn't have an associated vanilla fluid
}
// This code assumes that placing a fluid in the world will always consume a bucket's worth
boolean success = false;
BlockState state = world.getBlockState(pos);
Block block = state.getBlock();
if (state.isAir()) {
// The easiest case, probably
if (simulation == Simulation.ACTION) {
BlockState fluidStillState = fluid.getDefaultState().getBlockState();
world.setBlockState(pos, fluidStillState, 3);
}
success = true;
} else if (block instanceof FluidFillable) {
// FluidFillable includes waterloggable blocks, but not cauldrons, etc.
FluidFillable fillable = (FluidFillable) block;
if (simulation == Simulation.SIMULATE) {
success = fillable.canFillWithFluid(world, pos, state, fluid);
} else {
success = fillable.tryFillWithFluid(world, pos, state, fluid.getDefaultState());
}
} else if (block instanceof FluidBlock) {
FluidState fluidState = world.getFluidState(pos);
// Top up a non-still fluid block, but this consumes a full bucket regardless of the level
if (!fluidState.isStill() && fluidState.getFluid() == fluid) {
if (simulation == Simulation.ACTION) {
world.setBlockState(pos, fluid.getDefaultState().getBlockState(), 3);
}
success = true;
}
}
if (success) {
// Reduce by one bucket
return volume.copy().withAmount(volume.getAmount_F().roundedSub(FluidAmount.ONE, RoundingMode.DOWN));
} else {
return volume;
}
}
@Override
public void onFluidInventoryChanged(IAEFluidTank inv, int slot) {
if (inv == this.config) {
@@ -195,6 +137,13 @@ public class FluidFormationPlanePart extends AbstractFormationPlanePart<IAEFluid
}
}
protected boolean isBlocking(BlockView w, BlockPos pos) {
// Mirror the restrictions from the fill method
BlockState state = w.getBlockState(pos);
Block block = state.getBlock();
return !state.isAir() && !(block instanceof FluidFillable) && !(block instanceof FluidBlock);
}
@Override
public void readFromNBT(final CompoundTag data) {
super.readFromNBT(data);
@@ -19,7 +19,6 @@
package appeng.fluids.util;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import alexiil.mc.lib.attributes.fluid.amount.FluidAmount;
import alexiil.mc.lib.attributes.fluid.volume.FluidKey;
@@ -48,10 +47,8 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
private static final String NBT_REQUESTABLE = "req";
private static final String NBT_CRAFTABLE = "craft";
private static final String NBT_FLUID_ID = "f";
private static final String NBT_FLUID_TAG = "ft";
private final FluidKey fluid;
private CompoundTag tagCompound;
private AEFluidStack(final AEFluidStack fluidStack) {
this.fluid = fluidStack.fluid;
@@ -60,18 +57,13 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
// priority = is.priority;
this.setCraftable(fluidStack.isCraftable());
this.setCountRequestable(fluidStack.getCountRequestable());
if (fluidStack.hasTagCompound()) {
this.tagCompound = fluidStack.tagCompound.copy();
}
}
private AEFluidStack(@Nonnull FluidKey fluid, long amount, @Nullable CompoundTag tag) {
private AEFluidStack(@Nonnull FluidKey fluid, long amount) {
this.fluid = Preconditions.checkNotNull(fluid);
this.setStackSize(amount);
this.setCraftable(false);
this.setCountRequestable(0);
this.tagCompound = tag;
}
public static AEFluidStack fromFluidVolume(final FluidVolume input, RoundingMode roundingMode) {
@@ -84,14 +76,9 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
throw new IllegalArgumentException("Fluid is null.");
}
CompoundTag tag = input.toTag();
if (tag.isEmpty()) {
tag = null;
}
long amount = input.amount().asLong(1000, roundingMode);
return new AEFluidStack(fluid, amount, tag);
return new AEFluidStack(fluid, amount);
}
public static IAEFluidStack fromNBT(final CompoundTag data) {
@@ -101,14 +88,9 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
return null;
}
CompoundTag tag = null;
if (data.contains(NBT_FLUID_TAG, NbtType.COMPOUND)) {
tag = data.getCompound(NBT_FLUID_TAG);
}
long amount = data.getLong(NBT_STACKSIZE);
AEFluidStack fluidStack = new AEFluidStack(fluid, amount, tag);
AEFluidStack fluidStack = new AEFluidStack(fluid, amount);
fluidStack.setCountRequestable(data.getLong(NBT_REQUESTABLE));
fluidStack.setCraftable(data.getBoolean(NBT_CRAFTABLE));
return fluidStack;
@@ -127,9 +109,6 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
@Override
public void writeToNBT(final CompoundTag data) {
data.put(NBT_FLUID_ID, this.fluid.toTag());
if (this.hasTagCompound()) {
data.put(NBT_FLUID_TAG, this.tagCompound);
}
data.putLong(NBT_STACKSIZE, this.getStackSize());
data.putLong(NBT_REQUESTABLE, this.getCountRequestable());
data.putBoolean(NBT_CRAFTABLE, this.isCraftable());
@@ -162,12 +141,7 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
if (this.fluid != other.fluid) {
return this.fluid.entry.getId().compareTo(other.fluid.entry.getId());
}
if (Platform.itemComparisons().isNbtTagEqual(this.tagCompound, other.tagCompound)) {
return 0;
}
return this.tagCompound.hashCode() - other.tagCompound.hashCode();
return 0;
}
@Override
@@ -175,7 +149,6 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
final int prime = 31;
int result = 1;
result = prime * result + ((this.fluid == null) ? 0 : this.fluid.hashCode());
result = prime * result + ((this.tagCompound == null) ? 0 : this.tagCompound.hashCode());
return result;
}
@@ -184,29 +157,28 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
public boolean equals(final Object other) {
if (other instanceof AEFluidStack) {
final AEFluidStack is = (AEFluidStack) other;
return is.fluid == this.fluid && Platform.itemComparisons().isNbtTagEqual(this.tagCompound, is.tagCompound);
return is.fluid == this.fluid;
} else if (other instanceof FluidVolume) {
final FluidVolume is = (FluidVolume) other;
return is.getFluidKey() == this.fluid
&& Platform.itemComparisons().isNbtTagEqual(this.tagCompound, is.toTag());
return is.getFluidKey() == this.fluid;
}
return false;
}
@Override
public String toString() {
return this.getStackSize() + "x" + this.getFluidStack().getFluidKey().entry.getId() + " " + this.tagCompound;
return this.getStackSize() + "x" + this.getFluidStack().getFluidKey().entry.getId();
}
@Override
public boolean hasTagCompound() {
return this.tagCompound != null;
return false;
}
@Override
public FluidVolume getFluidStack() {
FluidAmount amount = FluidAmount.of(this.getStackSize(), 1000);
return this.fluid.readVolume(tagCompound).withAmount(amount);
return this.fluid.withAmount(amount);
}
@Override
@@ -234,11 +206,10 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
final boolean isCraftable = buffer.readBoolean();
FluidKey fluid = FluidKey.fromTag(buffer.readCompoundTag());
CompoundTag compoundTag = buffer.readCompoundTag();
final long amount = buffer.readVarLong();
final long countRequestable = buffer.readVarLong();
final AEFluidStack fluidStack = new AEFluidStack(fluid, amount, compoundTag);
final AEFluidStack fluidStack = new AEFluidStack(fluid, amount);
fluidStack.setCountRequestable(countRequestable);
fluidStack.setCraftable(isCraftable);
return fluidStack;
@@ -248,7 +219,6 @@ public final class AEFluidStack extends AEStack<IAEFluidStack> implements IAEFlu
public void writeToPacket(final PacketByteBuf buffer) {
buffer.writeBoolean(this.isCraftable());
buffer.writeCompoundTag(fluid.toTag());
buffer.writeCompoundTag(tagCompound);
buffer.writeVarLong(this.getStackSize());
buffer.writeVarLong(this.getCountRequestable());
}
@@ -1,13 +1,24 @@
package appeng.hooks;
import alexiil.mc.lib.attributes.fluid.FluidAttributes;
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
import appeng.client.render.DummyFluidBakedModel;
import appeng.fluids.items.FluidDummyItem;
import appeng.items.misc.EncodedPatternItem;
import appeng.mixins.ItemRendererAccessor;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.client.util.math.AffineTransformation;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
public final class ItemRendererHooks {
@@ -22,7 +33,11 @@ public final class ItemRendererHooks {
* if shift is held.
*/
public static boolean onRenderGuiItemModel(ItemRenderer renderer, ItemStack stack, int x, int y, BakedModel model) {
if (stack.getItem() instanceof EncodedPatternItem && OVERRIDING_FOR.get() != stack) {
if (OVERRIDING_FOR.get() == stack) {
return false; // Don't allow recursive model replacements
}
if (stack.getItem() instanceof EncodedPatternItem) {
boolean shiftHeld = Screen.hasShiftDown();
ClientWorld world = MinecraftClient.getInstance().world;
if (shiftHeld && world != null) {
@@ -31,18 +46,28 @@ public final class ItemRendererHooks {
if (!output.isEmpty()) {
BakedModel realModel = MinecraftClient.getInstance().getItemRenderer().getModels()
.getModel(output);
ItemRendererAccessor self = (ItemRendererAccessor) renderer;
OVERRIDING_FOR.set(stack);
try {
self.callRenderGuiItemModel(stack, x, y, realModel);
} finally {
OVERRIDING_FOR.remove();
}
renderInstead(renderer, stack, x, y, realModel);
return true;
}
}
} else if (stack.getItem() instanceof FluidDummyItem) {
FluidDummyItem itemFacade = (FluidDummyItem) stack.getItem();
FluidVolume fluidStack = itemFacade.getFluidStack(stack);
renderInstead(renderer, stack, x, y, new DummyFluidBakedModel(fluidStack));
return true;
}
return false;
}
private static void renderInstead(ItemRenderer renderer, ItemStack stack, int x, int y, BakedModel realModel) {
ItemRendererAccessor self = (ItemRendererAccessor) renderer;
OVERRIDING_FOR.set(stack);
try {
self.callRenderGuiItemModel(stack, x, y, realModel);
} finally {
OVERRIDING_FOR.remove();
}
}
}
+47 -19
View File
@@ -18,23 +18,7 @@
package appeng.hooks;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Stopwatch;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import net.minecraft.world.World;
import appeng.api.networking.IGridNode;
import appeng.api.util.AEColor;
import appeng.core.AEConfig;
import appeng.core.AELog;
@@ -44,14 +28,32 @@ import appeng.me.Grid;
import appeng.tile.AEBaseBlockEntity;
import appeng.util.IWorldCallable;
import appeng.util.Platform;
import com.google.common.base.Stopwatch;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
public class TickHandler {
private static final TickHandler INSTANCE = new TickHandler();
private static TickHandler INSTANCE;
private final Queue<IWorldCallable<?>> serverQueue = new ArrayDeque<>();
private final Multimap<World, CraftingJob> craftingJobs = LinkedListMultimap.create();
private final Map<WorldAccess, Queue<IWorldCallable<?>>> callQueue = new WeakHashMap<>();
@@ -60,11 +62,16 @@ public class TickHandler {
private final HashMap<Integer, PlayerColor> srvPlayerColors = new HashMap<>();
public TickHandler() {
if (INSTANCE != null) {
throw new IllegalStateException("There can only be a single tick handler.");
}
INSTANCE = this;
// Register for all the tick events we care about
ServerTickEvents.END_SERVER_TICK.register(this::onAfterServerTick);
ServerTickEvents.START_WORLD_TICK.register(this::onBeforeWorldTick);
ServerTickEvents.END_WORLD_TICK.register(this::onAfterWorldTick);
ServerLifecycleEvents.SERVER_STOPPING.register(this::onServerStopping);
}
public static TickHandler instance() {
@@ -147,6 +154,27 @@ public class TickHandler {
// FIXME FABRIC }
// FIXME FABRIC }
/**
* This is primarily useful for an integrated server being stopped, and can be fully replaced by the event
* above once world unload events hit.
*/
private void onServerStopping(MinecraftServer server) {
final List<IGridNode> toDestroy = new ArrayList<>();
this.server.updateNetworks();
for (final Grid g : this.server.networks) {
for (final IGridNode n : g.getNodes()) {
WorldAccess nodeWorld = n.getWorld();
if (nodeWorld instanceof ServerWorld && ((ServerWorld) nodeWorld).getServer() == server) {
toDestroy.add(n);
}
}
}
for (final IGridNode n : toDestroy) {
n.destroy();
}
}
private void onBeforeWorldTick(ServerWorld world) {
final Queue<IWorldCallable<?>> queue = this.callQueue.get(world);
this.processQueue(queue, world);
@@ -20,7 +20,10 @@ package appeng.items.tools;
import java.util.List;
import appeng.block.AEBaseTileBlock;
import appeng.hooks.AEToolItem;
import net.fabricmc.api.EnvType;
import net.minecraft.block.BlockState;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
@@ -29,6 +32,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.*;
import net.minecraft.text.Text;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.world.World;
import net.fabricmc.api.Environment;
@@ -40,7 +44,7 @@ import appeng.core.localization.PlayerMessages;
import appeng.items.AEBaseItem;
import appeng.util.Platform;
public class MemoryCardItem extends AEBaseItem implements IMemoryCard {
public class MemoryCardItem extends AEBaseItem implements AEToolItem, IMemoryCard {
private static final AEColor[] DEFAULT_COLOR_CODE = new AEColor[] { AEColor.TRANSPARENT, AEColor.TRANSPARENT,
AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT, AEColor.TRANSPARENT,
@@ -158,15 +162,21 @@ public class MemoryCardItem extends AEBaseItem implements IMemoryCard {
}
@Override
public ActionResult useOnBlock(ItemUsageContext context) {
public ActionResult onItemUseFirst(ItemStack stack, ItemUsageContext context) {
if (context.getPlayer().isInSneakingPose()) {
// Bypass the memory card's own use handler and go straight to the block
if (!context.getPlayer().world.isClient) {
this.clearCard(context.getPlayer(), context.getWorld(), context.getHand());
BlockState state = context.getWorld().getBlockState(context.getBlockPos());
ActionResult useResult = state.onUse(context.getWorld(), context.getPlayer(), context.getHand(),
new BlockHitResult(context.getHitPos(), context.getSide(), context.getBlockPos(), context.hitsInsideBlock()));
if (!useResult.isAccepted()) {
clearCard(context.getPlayer(), context.getWorld(), context.getHand());
}
}
return ActionResult.SUCCESS;
} else {
return super.useOnBlock(context);
}
return ActionResult.PASS;
}
@Override
@@ -180,15 +190,10 @@ public class MemoryCardItem extends AEBaseItem implements IMemoryCard {
return super.use(w, player, hand);
}
// FIXME FABRIC probably needs a custom mixin
// FIXME FABRIC @Override
// FIXME FABRIC public boolean doesSneakBypassUse(ItemStack stack, WorldView world, BlockPos pos, PlayerEntity player) {
// FIXME FABRIC return true;
// FIXME FABRIC }
private void clearCard(final PlayerEntity player, final World w, final Hand hand) {
final IMemoryCard mem = (IMemoryCard) player.getStackInHand(hand).getItem();
mem.notifyUser(player, MemoryCardMessages.SETTINGS_CLEARED);
player.getStackInHand(hand).setTag(null);
}
}
@@ -109,6 +109,7 @@ public class NetworkToolItem extends AEBaseItem implements IGuiItem, IAEWrench,
}
// FIXME FABRIC: No direct equivalent
// FIXME FABRIC: Might already be handled by onItemUseFirst though
// FIXME FABRIC @Override
// FIXME FABRIC public boolean doesSneakBypassUse(ItemStack stack, WorldView world, BlockPos pos, PlayerEntity player) {
// FIXME FABRIC return true;
@@ -19,6 +19,9 @@
package appeng.items.tools.quartz;
import appeng.container.ContainerLocator;
import appeng.container.ContainerOpener;
import appeng.container.implementations.QuartzKnifeContainer;
import appeng.items.contents.QuartzKnifeObj;
import appeng.mixins.RemainderSetter;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
@@ -48,8 +51,7 @@ public class QuartzCuttingKnifeItem extends AEBaseItem implements IGuiItem {
@Override
public TypedActionResult<ItemStack> use(final World w, final PlayerEntity p, final Hand hand) {
if (Platform.isServer()) {
// FIXME FABRIC ContainerOpener.openContainer(QuartzKnifeContainer.TYPE, p, ContainerLocator.forHand(p, hand));
throw new IllegalStateException();
ContainerOpener.openContainer(QuartzKnifeContainer.TYPE, p, ContainerLocator.forHand(p, hand));
}
p.swingHand(hand);
return new TypedActionResult<>(ActionResult.SUCCESS, p.getStackInHand(hand));
@@ -58,7 +60,6 @@ public class QuartzCuttingKnifeItem extends AEBaseItem implements IGuiItem {
@Override
public IGuiItemObject getGuiObject(final ItemStack is, int playerInventorySlot, final World world,
final BlockPos pos) {
// FIXME FABRIC return new QuartzKnifeObj(is);
throw new IllegalStateException();
return new QuartzKnifeObj(is);
}
}
+4 -5
View File
@@ -64,11 +64,10 @@ public class GridStorage implements IGridStorage {
}
public void saveState() {
throw new IllegalStateException();
// FIXME FABRIC final Grid currentGrid = (Grid) this.getGrid();
// FIXME FABRIC if (currentGrid != null) {
// FIXME FABRIC currentGrid.saveState();
// FIXME FABRIC }
final Grid currentGrid = (Grid) this.getGrid();
if (currentGrid != null) {
currentGrid.saveState();
}
}
public IGrid getGrid() {
@@ -95,8 +95,8 @@ public abstract class MBCalculator<TTile extends IAEMultiBlock<TCluster>, TClust
}
try {
final BlockPos.Mutable min = new BlockPos.Mutable(loc);
final BlockPos.Mutable max = new BlockPos.Mutable(loc);
final BlockPos.Mutable min = loc.mutableCopy();
final BlockPos.Mutable max = loc.mutableCopy();
// find size of MB structure...
while (this.isValidTileAt(world, min.getX() - 1, min.getY(), min.getZ())) {
@@ -259,7 +259,7 @@ public abstract class MBCalculator<TTile extends IAEMultiBlock<TCluster>, TClust
return false;
}
for (BlockPos p : BlockPos.getAllInBoxMutable(minX, minY, minZ, maxX, maxY, maxZ)) {
for (BlockPos p : BlockPos.iterate(minX, minY, minZ, maxX, maxY, maxZ)) {
final BlockEntity te = w.getBlockEntity(p);
if (this.isValidTile(te)) {
return true;
@@ -33,9 +33,9 @@ import appeng.me.cluster.IAEMultiBlock;
import appeng.me.cluster.MBCalculator;
import appeng.tile.crafting.CraftingBlockEntity;
public class CraftingCPUCalculator extends MBCalculator<CraftingTileEntity, CraftingCPUCluster> {
public class CraftingCPUCalculator extends MBCalculator<CraftingBlockEntity, CraftingCPUCluster> {
public CraftingCPUCalculator(final CraftingTileEntity t) {
public CraftingCPUCalculator(final CraftingBlockEntity t) {
super(t);
}
@@ -65,7 +65,7 @@ public class CraftingCPUCalculator extends MBCalculator<CraftingTileEntity, Craf
public boolean verifyInternalStructure(final World w, final BlockPos min, final BlockPos max) {
boolean storage = false;
for (BlockPos blockPos : BlockPos.getAllInBoxMutable(min, max)) {
for (BlockPos blockPos : BlockPos.iterate(min, max)) {
final IAEMultiBlock<?> te = (IAEMultiBlock<?>) w.getBlockEntity(blockPos);
if (te == null || !te.isValid()) {
@@ -82,7 +82,7 @@ public class CraftingCPUCalculator extends MBCalculator<CraftingTileEntity, Craf
@Override
public void updateTiles(final CraftingCPUCluster c, final World w, final BlockPos min, final BlockPos max) {
for (BlockPos blockPos : BlockPos.getAllInBoxMutable(min, max)) {
for (BlockPos blockPos : BlockPos.iterate(min, max)) {
final CraftingBlockEntity te = (CraftingBlockEntity) w.getBlockEntity(blockPos);
te.updateStatus(c);
c.addTile(te);
@@ -90,7 +90,7 @@ public class CraftingCPUCalculator extends MBCalculator<CraftingTileEntity, Craf
c.done();
final Iterator<CraftingTileEntity> i = c.getTiles();
final Iterator<CraftingBlockEntity> i = c.getTiles();
while (i.hasNext()) {
final IGridHost gh = i.next();
final IGridNode n = gh.getGridNode(AEPartLocation.INTERNAL);
@@ -183,7 +183,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
}
@Override
public Iterator<CraftingTileEntity> getTiles() {
public Iterator<CraftingBlockEntity> getTiles() {
return this.tiles.iterator();
}
@@ -30,9 +30,9 @@ import appeng.me.cluster.IAEMultiBlock;
import appeng.me.cluster.MBCalculator;
import appeng.tile.qnb.QuantumBridgeBlockEntity;
public class QuantumCalculator extends MBCalculator<QuantumBridgeTileEntity, QuantumCluster> {
public class QuantumCalculator extends MBCalculator<QuantumBridgeBlockEntity, QuantumCluster> {
public QuantumCalculator(final QuantumBridgeTileEntity t) {
public QuantumCalculator(final QuantumBridgeBlockEntity t) {
super(t);
}
@@ -60,8 +60,8 @@ public class QuantumCalculator extends MBCalculator<QuantumBridgeTileEntity, Qua
byte num = 0;
for (BlockPos p : BlockPos.getAllInBoxMutable(min, max)) {
final IAEMultiBlock<?> te = (IAEMultiBlock<?>) w.getTileEntity(p);
for (BlockPos p : BlockPos.iterate(min, max)) {
final IAEMultiBlock<?> te = (IAEMultiBlock<?>) w.getBlockEntity(p);
if (te == null || !te.isValid()) {
return false;
@@ -87,7 +87,7 @@ public class QuantumCalculator extends MBCalculator<QuantumBridgeTileEntity, Qua
byte num = 0;
byte ringNum = 0;
for (BlockPos p : BlockPos.getAllInBoxMutable(min, max)) {
for (BlockPos p : BlockPos.iterate(min, max)) {
final QuantumBridgeBlockEntity te = (QuantumBridgeBlockEntity) w.getBlockEntity(p);
num++;
@@ -20,6 +20,7 @@ package appeng.me.cluster.implementations;
import java.util.Iterator;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
@@ -234,7 +235,7 @@ public class QuantumCluster implements ILocatable, IAECluster {
}
@Override
public Iterator<QuantumBridgeTileEntity> getTiles() {
public Iterator<QuantumBridgeBlockEntity> getTiles() {
return new ChainedIterator<>(this.getRing()[0], this.getRing()[1], this.getRing()[2], this.getRing()[3],
this.getRing()[4], this.getRing()[5], this.getRing()[6], this.getRing()[7], this.center);
}
@@ -26,9 +26,9 @@ import appeng.me.cluster.IAEMultiBlock;
import appeng.me.cluster.MBCalculator;
import appeng.tile.spatial.SpatialPylonBlockEntity;
public class SpatialPylonCalculator extends MBCalculator<SpatialPylonTileEntity, SpatialPylonCluster> {
public class SpatialPylonCalculator extends MBCalculator<SpatialPylonBlockEntity, SpatialPylonCluster> {
public SpatialPylonCalculator(final SpatialPylonTileEntity t) {
public SpatialPylonCalculator(final SpatialPylonBlockEntity t) {
super(t);
}
@@ -47,8 +47,8 @@ public class SpatialPylonCalculator extends MBCalculator<SpatialPylonTileEntity,
@Override
public boolean verifyInternalStructure(final World w, final BlockPos min, final BlockPos max) {
for (BlockPos p : BlockPos.getAllInBoxMutable(min, max)) {
final IAEMultiBlock<?> te = (IAEMultiBlock<?>) w.getTileEntity(p);
for (BlockPos p : BlockPos.iterate(min, max)) {
final IAEMultiBlock<?> te = (IAEMultiBlock<?>) w.getBlockEntity(p);
if (te == null || !te.isValid()) {
return false;
@@ -60,8 +60,8 @@ public class SpatialPylonCalculator extends MBCalculator<SpatialPylonTileEntity,
@Override
public void updateTiles(final SpatialPylonCluster c, final World w, final BlockPos min, final BlockPos max) {
for (BlockPos p : BlockPos.getAllInBoxMutable(min, max)) {
final SpatialPylonTileEntity te = (SpatialPylonTileEntity) w.getTileEntity(p);
for (BlockPos p : BlockPos.iterate(min, max)) {
final SpatialPylonBlockEntity te = (SpatialPylonBlockEntity) w.getBlockEntity(p);
te.updateStatus(c);
c.getLine().add(te);
}
@@ -87,7 +87,7 @@ public class SpatialPylonCluster implements IAECluster {
}
@Override
public Iterator<SpatialPylonTileEntity> getTiles() {
public Iterator<SpatialPylonBlockEntity> getTiles() {
return this.getLine().iterator();
}
@@ -171,10 +171,14 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
final BlockPos tePos = te.getPos().offset(side.getFacing());
this.blocked = !w.getBlockState(tePos).getMaterial().isReplaceable();
this.blocked = isBlocking(w, tePos);
}
}
protected boolean isBlocking(BlockView w, BlockPos pos) {
return !w.getBlockState(pos).getMaterial().isReplaceable();
}
@Override
public float getCableConnectionLength(AECableType cable) {
return 1;
@@ -0,0 +1,136 @@
/*
* 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.automation;
import appeng.api.parts.IDynamicPartBakedModel;
import appeng.client.render.cablebus.CubeBuilder;
import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
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.render.RenderContext;
import net.minecraft.block.BlockState;
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.Sprite;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
/**
* Built-in model for annihilation planes that supports connected textures.
*/
public class PlaneBakedModel implements BakedModel, IDynamicPartBakedModel {
private static final PlaneConnections DEFAULT_PERMUTATION = PlaneConnections.of(false, false, false, false);
private final Sprite frontTexture;
private final Map<PlaneConnections, Mesh> meshes;
PlaneBakedModel(Sprite frontTexture, Sprite sidesTexture, Sprite backTexture) {
this.frontTexture = frontTexture;
Renderer renderer = RendererAccess.INSTANCE.getRenderer();
meshes = new HashMap<>(PlaneConnections.PERMUTATIONS.size());
// Create all possible permutations (16)
for (PlaneConnections permutation : PlaneConnections.PERMUTATIONS) {
MeshBuilder meshBuilder = renderer.meshBuilder();
CubeBuilder builder = new CubeBuilder(meshBuilder.getEmitter());
builder.setTextures(sidesTexture, sidesTexture, frontTexture, backTexture, sidesTexture, sidesTexture);
// Keep the orientation of the X axis in mind here. When looking at a quad
// facing north from the front,
// The X-axis points left
int minX = permutation.isRight() ? 0 : 1;
int maxX = permutation.isLeft() ? 16 : 15;
int minY = permutation.isDown() ? 0 : 1;
int maxY = permutation.isUp() ? 16 : 15;
builder.addCube(minX, minY, 0, maxX, maxY, 1);
this.meshes.put(permutation, meshBuilder.build());
}
}
@Override
public void emitQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context, Direction partSide, @Nullable Object modelData) {
PlaneConnections connections = DEFAULT_PERMUTATION;
if (modelData instanceof PlaneConnections) {
connections = (PlaneConnections) modelData;
}
context.meshConsumer().accept(this.meshes.get(connections));
}
@Override
public ModelTransformation getTransformation() {
return ModelTransformation.NONE;
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, Random rand) {
return Collections.emptyList();
}
@Override
public boolean useAmbientOcclusion() {
return false;
}
@Override
public boolean hasDepth() {
return false;
}
@Override
public boolean isSideLit() {
return false;
}
@Override
public boolean isBuiltin() {
return false;
}
@Override
public Sprite getSprite() {
return this.frontTexture;
}
@Override
public ModelOverrideList getOverrides() {
return ModelOverrideList.EMPTY;
}
}
@@ -0,0 +1,64 @@
/*
* 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.automation;
import appeng.client.render.BasicUnbakedModel;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* Built-in model for annihilation planes that supports connected textures.
*/
public class PlaneModel implements BasicUnbakedModel {
private final SpriteIdentifier frontTexture;
private final SpriteIdentifier sidesTexture;
private final SpriteIdentifier backTexture;
public PlaneModel(Identifier frontTexture, Identifier sidesTexture, Identifier backTexture) {
this.frontTexture = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, frontTexture);
this.sidesTexture = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, sidesTexture);
this.backTexture = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX, backTexture);
}
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
Sprite frontSprite = textureGetter.apply(this.frontTexture);
Sprite sidesSprite = textureGetter.apply(this.sidesTexture);
Sprite backSprite = textureGetter.apply(this.backTexture);
return new PlaneBakedModel(frontSprite, sidesSprite, backSprite);
}
@Override
public Stream<SpriteIdentifier> getAdditionalTextures() {
return Stream.of(frontTexture, sidesTexture, backTexture);
}
}
@@ -0,0 +1,161 @@
/*
* 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.recipes.game;
import appeng.api.definitions.IBlocks;
import appeng.api.definitions.IDefinitions;
import appeng.api.definitions.IItemDefinition;
import appeng.api.definitions.IItems;
import appeng.api.definitions.IMaterials;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.core.Api;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.SpecialCraftingRecipe;
import net.minecraft.recipe.SpecialRecipeSerializer;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public final class DisassembleRecipe extends SpecialCraftingRecipe {
public static final RecipeSerializer<DisassembleRecipe> SERIALIZER = new SpecialRecipeSerializer<>(
DisassembleRecipe::new);
private static final ItemStack MISMATCHED_STACK = ItemStack.EMPTY;
private final Map<IItemDefinition, IItemDefinition> cellMappings;
private final Map<IItemDefinition, IItemDefinition> nonCellMappings;
public DisassembleRecipe(Identifier id) {
super(id);
final IDefinitions definitions = Api.instance().definitions();
final IBlocks blocks = definitions.blocks();
final IItems items = definitions.items();
final IMaterials mats = definitions.materials();
this.cellMappings = new HashMap<>(4);
this.nonCellMappings = new HashMap<>(5);
this.cellMappings.put(items.cell1k(), mats.cell1kPart());
this.cellMappings.put(items.cell4k(), mats.cell4kPart());
this.cellMappings.put(items.cell16k(), mats.cell16kPart());
this.cellMappings.put(items.cell64k(), mats.cell64kPart());
this.nonCellMappings.put(items.encodedPattern(), mats.blankPattern());
this.nonCellMappings.put(blocks.craftingStorage1k(), mats.cell1kPart());
this.nonCellMappings.put(blocks.craftingStorage4k(), mats.cell4kPart());
this.nonCellMappings.put(blocks.craftingStorage16k(), mats.cell16kPart());
this.nonCellMappings.put(blocks.craftingStorage64k(), mats.cell64kPart());
}
@Override
public boolean matches(@Nonnull final CraftingInventory inv, @Nonnull final World w) {
return !this.getOutput(inv).isEmpty();
}
@Nonnull
private ItemStack getOutput(final Inventory inventory) {
int itemCount = 0;
ItemStack output = MISMATCHED_STACK;
for (int slotIndex = 0; slotIndex < inventory.size(); slotIndex++) {
final ItemStack stackInSlot = inventory.getStack(slotIndex);
if (!stackInSlot.isEmpty()) {
// needs a single input in the recipe
itemCount++;
if (itemCount > 1) {
return MISMATCHED_STACK;
}
// handle storage cells
Optional<ItemStack> maybeCellOutput = this.getCellOutput(stackInSlot);
if (maybeCellOutput.isPresent()) {
ItemStack storageCellStack = maybeCellOutput.get();
// make sure the storage cell stackInSlot empty...
final IMEInventory<IAEItemStack> cellInv = Api.instance().registries().cell().getCellInventory(
stackInSlot, null, Api.instance().storage().getStorageChannel(IItemStorageChannel.class));
if (cellInv != null) {
final IItemList<IAEItemStack> list = cellInv.getAvailableItems(
Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createList());
if (!list.isEmpty()) {
return ItemStack.EMPTY;
}
}
output = storageCellStack;
}
// handle crafting storage blocks
output = this.getNonCellOutput(stackInSlot).orElse(output);
}
}
return output;
}
@Nonnull
private Optional<ItemStack> getCellOutput(final ItemStack compared) {
for (final Map.Entry<IItemDefinition, IItemDefinition> entry : this.cellMappings.entrySet()) {
if (entry.getKey().isSameAs(compared)) {
return entry.getValue().maybeStack(1);
}
}
return Optional.empty();
}
@Nonnull
private Optional<ItemStack> getNonCellOutput(final ItemStack compared) {
for (final Map.Entry<IItemDefinition, IItemDefinition> entry : this.nonCellMappings.entrySet()) {
if (entry.getKey().isSameAs(compared)) {
return entry.getValue().maybeStack(1);
}
}
return Optional.empty();
}
@Nonnull
@Override
public ItemStack craft(@Nonnull final CraftingInventory inv) {
return this.getOutput(inv);
}
@Override
public boolean fits(int i, int i1) {
return false;
}
@Nonnull
@Override
public RecipeSerializer<DisassembleRecipe> getSerializer() {
return SERIALIZER;
}
}
@@ -0,0 +1,96 @@
/*
* 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.recipes.game;
import appeng.api.definitions.IComparableDefinition;
import appeng.api.definitions.IDefinitions;
import appeng.core.Api;
import appeng.core.AppEng;
import appeng.items.parts.FacadeItem;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.SpecialCraftingRecipe;
import net.minecraft.recipe.SpecialRecipeSerializer;
import net.minecraft.util.Identifier;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public final class FacadeRecipe extends SpecialCraftingRecipe {
public static SpecialRecipeSerializer<FacadeRecipe> SERIALIZER = null;
private final IComparableDefinition anchor;
private final FacadeItem facade;
public FacadeRecipe(Identifier id, FacadeItem facade) {
super(id);
this.facade = facade;
final IDefinitions definitions = Api.instance().definitions();
this.anchor = definitions.parts().cableAnchor();
}
@Override
public boolean matches(@Nonnull final CraftingInventory inv, @Nonnull final World w) {
return !this.getOutput(inv, false).isEmpty();
}
@Nonnull
private ItemStack getOutput(final Inventory inv, final boolean createFacade) {
if (inv.getStack(0).isEmpty() && inv.getStack(2).isEmpty() && inv.getStack(6).isEmpty()
&& inv.getStack(8).isEmpty()) {
if (this.anchor.isSameAs(inv.getStack(1)) && this.anchor.isSameAs(inv.getStack(3))
&& this.anchor.isSameAs(inv.getStack(5)) && this.anchor.isSameAs(inv.getStack(7))) {
final ItemStack facades = this.facade.createFacadeForItem(inv.getStack(4), !createFacade);
if (!facades.isEmpty() && createFacade) {
facades.setCount(4);
}
return facades;
}
}
return ItemStack.EMPTY;
}
@Override
public ItemStack craft(@Nonnull final CraftingInventory inv) {
return this.getOutput(inv, true);
}
@Override
public boolean fits(int i, int i1) {
return false;
}
@Nonnull
@Override
public RecipeSerializer<FacadeRecipe> getSerializer() {
return getSerializer(facade);
}
public static RecipeSerializer<FacadeRecipe> getSerializer(FacadeItem facade) {
if (SERIALIZER == null) {
SERIALIZER = new SpecialRecipeSerializer<>(id -> new FacadeRecipe(id, facade));
}
return SERIALIZER;
}
}
@@ -0,0 +1,118 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.math;
/**
* @author covers1624
*/
public class InterpHelper {
private float[][] posCache = new float[4][2];
private float[] valCache = new float[4];
private float x0;
private float x1;
private float y0;
private float y1;
private float rX;
private float rY;
private int p00;
private int p10;
private int p11;
private int p01;
/**
* Resets the interp helper with the given quad. Does not care what order the
* vertices are in.
*/
public void reset(float dx0, float dy0, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) {
float[] vec0 = this.posCache[0];
float[] vec1 = this.posCache[1];
float[] vec2 = this.posCache[2];
float[] vec3 = this.posCache[3];
vec0[0] = dx0;
vec1[0] = dx1;
vec2[0] = dx2;
vec3[0] = dx3;
vec0[1] = dy0;
vec1[1] = dy1;
vec2[1] = dy2;
vec3[1] = dy3;
}
/**
* Call when you are ready to use the InterpHelper.
*/
public void setup() {
this.p00 = 0;// Bottom Left is always first.
this.x0 = this.posCache[this.p00][0];
this.y0 = this.posCache[this.p00][1];
for (int i = 1; i < 4; i++) {
float x = this.posCache[i][0];
float y = this.posCache[i][1];
if (this.y0 == y) {
this.p10 = i;// Bottom right.
this.x1 = x;
} else if (this.x0 == x) {
this.p01 = i;// Top left.
this.y1 = y;
} else {
// Top right.
this.p11 = i;
}
}
}
/**
* Computes the coefficients for the interpolation.
*
* @param x X interp location.
* @param y Y interp location.
*/
public void locate(float x, float y) {
this.rX = (x - this.x0) / (this.x1 - this.x0);
this.rY = (y - this.y0) / (this.y1 - this.y0);
}
/**
* Interpolates using the already computed coefficients.
*
* @param q0 Value at dx0 dy0
* @param q1 Value at dx1 dy1
* @param q2 Value at dx2 dy2
* @param q3 Value at dx3 dy3
*
* @return The result.
*/
public float interpolate(float q0, float q1, float q2, float q3) {
this.valCache[0] = q0;
this.valCache[1] = q1;
this.valCache[2] = q2;
this.valCache[3] = q3;
float f0 = (this.valCache[this.p00] * (1 - this.rX)) + (this.valCache[this.p10] * this.rX);
float f1 = (this.valCache[this.p01] * (1 - this.rX)) + (this.valCache[this.p11] * this.rX);
return (f0 * (1 - this.rY)) + (f1 * this.rY);
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
/**
* This transformer simply overrides the alpha of the quad.
*
* @author covers1624
*/
public class QuadAlphaOverride implements RenderContext.QuadTransform {
private static final int INV_ALPHA_MASK = 0x00_FF_FF_FF;
private final int alphaOverride;
public QuadAlphaOverride(float alphaOverride) {
this.alphaOverride = (int) (alphaOverride * 255) << 24;
}
@Override
public boolean transform(MutableQuadView quad) {
for (int i = 0; i < 4; i++) {
int color = (quad.spriteColor(i, 0) & INV_ALPHA_MASK) | alphaOverride;
quad.spriteColor(i, 0, color);
}
return true;
}
}
@@ -0,0 +1,107 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
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.Box;
import net.minecraft.util.math.MathHelper;
/**
* This transformer simply clamps the vertices inside the provided box. You
* probably want to Re-Interpolate the UV's, Color, and Lmap, see
* {@link QuadReInterpolator}
*
* @author covers1624
*/
public class QuadClamper implements RenderContext.QuadTransform {
private final Box clampBounds;
private final Vector3f pos = new Vector3f();
public QuadClamper(Box clampBounds) {
this.clampBounds = clampBounds;
}
@Override
public boolean transform(MutableQuadView quad) {
int s = quad.nominalFace().ordinal() >> 1;
clamp(quad, this.clampBounds);
// Check if the quad would be invisible and cull it.
float x1 = quad.posByIndex(0, dx(s));
float x2 = quad.posByIndex(1, dx(s));
float x3 = quad.posByIndex(2, dx(s));
float x4 = quad.posByIndex(3, dx(s));
float y1 = quad.posByIndex(0, dy(s));
float y2 = quad.posByIndex(1, dy(s));
float y3 = quad.posByIndex(2, dy(s));
float y4 = quad.posByIndex(3, dy(s));
// These comparisons are safe as we are comparing clamped values.
boolean flag1 = x1 == x2 && x2 == x3 && x3 == x4;
boolean flag2 = y1 == y2 && y2 == y3 && y3 == y4;
return !flag1 && !flag2;
}
private void clamp(MutableQuadView quad, Box bb) {
for (int i = 0; i < 4; i++) {
quad.copyPos(i, pos);
pos.set(
(float) MathHelper.clamp(pos.getX(), bb.minX, bb.maxX),
(float) MathHelper.clamp(pos.getY(), bb.minY, bb.maxY),
(float) MathHelper.clamp(pos.getZ(), bb.minZ, bb.maxZ)
);
quad.pos(i, pos);
}
}
/**
* Gets the 2d X coord for the given axis.
*
* @param s The axis. side >> 1
* @return The x coord.
*/
private static int dx(int s) {
if (s <= 1) {
return 0;
} else {
return 2;
}
}
/**
* Gets the 2d Y coord for the given axis.
*
* @param s The axis. side >> 1
* @return The y coord.
*/
private static int dy(int s) {
if (s > 0) {
return 1;
} else {
return 2;
}
}
}
@@ -0,0 +1,195 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.AxisDirection;
import net.minecraft.util.math.Vec3i;
import static net.minecraft.util.math.Direction.AxisDirection.NEGATIVE;
import static net.minecraft.util.math.Direction.AxisDirection.POSITIVE;
/**
* This transformer is a little complicated. Basically a Facade / Cover can use
* this to 'kick' the edges in of quads to fix z-Fighting in the corners. Use it
* by specifying the side of the block you are on, the bitmask for where the
* other Facades / Cover's are, the bounding box of the facade, NOT the hole
* piece, and the thickness of your Facade / Cover, this is used as the kick
* amount.
*
* @author covers1624
*/
public class QuadCornerKicker implements RenderContext.QuadTransform {
public static final QuadCornerKicker INSTANCE = new QuadCornerKicker();
// Simple horizonal lookups.
public static int[][] horizonals = new int[][]{
// Around Y axis, NSWE.
{2, 3, 4, 5}, //
{2, 3, 4, 5}, //
// Around Z axis, DUWE.
{0, 1, 4, 5}, //
{0, 1, 4, 5}, //
// Around X axis, DUNS.
{0, 1, 2, 3}, //
{0, 1, 2, 3}};
private int mySide;
private int facadeMask;
private Box box;
private double thickness;
public QuadCornerKicker() {
super();
}
/**
* Set's the side this Facade / Cover is attached to.
*
* @param side The side.
*/
public void setSide(int side) {
this.mySide = side;
}
/**
* Sets the bitmask of Facades / Covers in the blockspace. This is as simple as,
* mask = (1 << side)
*
* @param mask The mask.
*/
public void setFacadeMask(int mask) {
this.facadeMask = mask;
}
/**
* Sets the bounding box of the Facade / Cover, this should be the full box, not
* just a piece of the hole's 'ring'.
*
* @param box The BoundingBox.
*/
public void setBox(Box box) {
this.box = box;
}
/**
* Sets the amount to kick the vertex in by, this is your facades thickness.
*
* @param thickness The thickness.
*/
public void setThickness(double thickness) {
this.thickness = thickness;
}
@Override
public boolean transform(MutableQuadView quad) {
int side = quad.nominalFace().ordinal();
if (side != this.mySide && side != (this.mySide ^ 1)) {
for (int hoz : horizonals[this.mySide]) {
if (side != hoz && side != (hoz ^ 1)) {
if ((this.facadeMask & (1 << hoz)) != 0) {
Corner corner = Corner.fromSides(this.mySide ^ 1, side, hoz);
for (int i = 0; i < 4; i++) {
float x = quad.posByIndex(i, 0);
float y = quad.posByIndex(i, 1);
float z = quad.posByIndex(i, 2);
if (epsComp(x, corner.pX(this.box)) && epsComp(y, corner.pY(this.box))
&& epsComp(z, corner.pZ(this.box))) {
Vec3i vec = Direction.values()[hoz].getVector();
x -= vec.getX() * this.thickness;
y -= vec.getY() * this.thickness;
z -= vec.getZ() * this.thickness;
quad.pos(i, x, y, z);
}
}
}
}
}
}
return true;
}
public enum Corner {
MIN_X_MIN_Y_MIN_Z(NEGATIVE, NEGATIVE, NEGATIVE), MIN_X_MIN_Y_MAX_Z(NEGATIVE, NEGATIVE, POSITIVE),
MIN_X_MAX_Y_MIN_Z(NEGATIVE, POSITIVE, NEGATIVE), MIN_X_MAX_Y_MAX_Z(NEGATIVE, POSITIVE, POSITIVE),
MAX_X_MIN_Y_MIN_Z(POSITIVE, NEGATIVE, NEGATIVE), MAX_X_MIN_Y_MAX_Z(POSITIVE, NEGATIVE, POSITIVE),
MAX_X_MAX_Y_MIN_Z(POSITIVE, POSITIVE, NEGATIVE), MAX_X_MAX_Y_MAX_Z(POSITIVE, POSITIVE, POSITIVE);
private AxisDirection xAxis;
private AxisDirection yAxis;
private AxisDirection zAxis;
private static final int[] sideMask = {0, 2, 0, 1, 0, 4};
Corner(AxisDirection xAxis, AxisDirection yAxis, AxisDirection zAxis) {
this.xAxis = xAxis;
this.yAxis = yAxis;
this.zAxis = zAxis;
}
/**
* Used to find what corner is at the 3 sides. This method assumes you pass in
* the X axis side, Y axis side, and Z axis side, it will NOT complain about an
* invalid side, you will just get garbage data. This method also does not care
* what order the 3 axes are in.
*
* @param sideA Side one.
* @param sideB Side two.
* @param sideC Side three.
* @return The corner at the 3 sides.
*/
public static Corner fromSides(int sideA, int sideB, int sideC) {
// <3 Chicken-Bones.
return values()[sideMask[sideA] | sideMask[sideB] | sideMask[sideC]];
}
public float pX(Box box) {
return (float) (this.xAxis == NEGATIVE ? box.minX : box.maxX);
}
public float pY(Box box) {
return (float) (this.yAxis == NEGATIVE ? box.minY : box.maxY);
}
public float pZ(Box box) {
return (float) (this.zAxis == NEGATIVE ? box.minZ : box.maxZ);
}
}
// Should be small enough.
private final static double EPSILON = 0.00001;
private static boolean epsComp(float a, float b) {
if (a == b) {
return true;
} else {
return Math.abs(a - b) < EPSILON;
}
}
}
@@ -0,0 +1,107 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.AxisDirection;
import static net.minecraft.util.math.Direction.AxisDirection.POSITIVE;
/**
* This transformer strips quads that are on faces. Simply set the bounds for
* the faces, and the strip mask.
*
* @author covers1624
*/
public class QuadFaceStripper implements RenderContext.QuadTransform {
private Box bounds;
private int mask;
QuadFaceStripper() {
super();
}
public QuadFaceStripper(Box bounds, int mask) {
this.bounds = bounds;
this.mask = mask;
}
/**
* The bounds of the faces, used as the .. bounds, if all vertices of a quad lay
* on the bounds, it is up for stripping.
*
* @param bounds The bounds.
*/
public void setBounds(Box bounds) {
this.bounds = bounds;
}
/**
* The mask to strip edges. This is an opt in system, the mask is simple 'mask =
* (1 << side)'.
*
* @param mask The mask.
*/
public void setMask(int mask) {
this.mask = mask;
}
@Override
public boolean transform(MutableQuadView quad) {
if (this.mask == 0) {
return true;// No mask, nothing changes.
}
// If the bit for this quad is set, then check if we should strip.
Direction face = quad.nominalFace();
if ((this.mask & (1 << face.ordinal())) != 0) {
AxisDirection dir = face.getDirection();
switch (face.getAxis()) {
case X: {
float bound = (float) (dir == POSITIVE ? this.bounds.maxX : this.bounds.minX);
float x1 = quad.posByIndex(0, 0);
float x2 = quad.posByIndex(1, 0);
float x3 = quad.posByIndex(2, 0);
float x4 = quad.posByIndex(3, 0);
return x1 != x2 || x2 != x3 || x3 != x4 || x4 != bound;
}
case Y: {
float bound = (float) (dir == POSITIVE ? this.bounds.maxY : this.bounds.minY);
float y1 = quad.posByIndex(0, 1);
float y2 = quad.posByIndex(1, 1);
float y3 = quad.posByIndex(2, 1);
float y4 = quad.posByIndex(3, 1);
return y1 != y2 || y2 != y3 || y3 != y4 || y4 != bound;
}
case Z: {
float bound = (float) (dir == POSITIVE ? this.bounds.maxZ : this.bounds.minZ);
float z1 = quad.posByIndex(0, 2);
float z2 = quad.posByIndex(1, 2);
float z3 = quad.posByIndex(2, 2);
float z4 = quad.posByIndex(3, 2);
return z1 != z2 || z2 != z3 || z3 != z4 || z4 != bound;
}
}
}
return true;
}
}
@@ -0,0 +1,85 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
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.client.util.math.Vector4f;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Matrix4f;
/**
* Created by covers1624 on 2/6/20.
*/
public class QuadMatrixTransformer implements RenderContext.QuadTransform {
private static final Matrix4f identity;
static {
identity = new Matrix4f();
identity.loadIdentity();
}
private final Vector3f storage3 = new Vector3f();
private final Vector4f storage = new Vector4f();
private Matrix4f matrix;
private boolean identityMatrix;
QuadMatrixTransformer() {
super();
}
public QuadMatrixTransformer(Matrix4f matrix) {
this.matrix = matrix;
this.identityMatrix = matrix.equals(identity);
}
public void setMatrix(Matrix4f matrix) {
this.matrix = matrix;
this.identityMatrix = matrix.equals(identity);
}
@Override
public boolean transform(MutableQuadView quad) {
if (identityMatrix) {
return true;
}
for (int i = 0; i < 4; i++) {
quad.copyPos(i, storage3);
storage.set(storage3.getX(), storage3.getY(), storage3.getZ(), 1);
storage.transform(matrix);
quad.pos(i, storage.getX(), storage.getY(), storage.getZ());
if (quad.hasNormal(i)) {
quad.copyNormal(i, storage3);
storage.set(storage3.getX(), storage3.getY(), storage3.getZ(), 0);
storage.transform(matrix);
storage.normalize();
quad.normal(i, storage.getX(), storage.getY(), storage.getZ());
if (i == 0) {
Direction face = Direction.getFacing(storage.getX(), storage.getY(), storage.getZ());
quad.nominalFace(face);
quad.cullFace(face);
}
}
}
return true;
}
}
@@ -0,0 +1,180 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import appeng.thirdparty.codechicken.lib.math.InterpHelper;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
/**
* This transformer Re-Interpolates the Color, UV's and LightMaps. Use this
* after all transformations that translate vertices in the pipeline.
* <p>
* This Transformation can only be used in the BakedPipeline.
*
* @author covers1624
*/
public class QuadReInterpolator implements RenderContext.QuadTransform {
private final InterpHelper interpHelper = new InterpHelper();
private final MutableQuadViewImpl bufferQuad = new MutableQuadViewImpl() {
{
data = new int[EncodingFormat.TOTAL_STRIDE];
}
@Override
public QuadEmitter emit() {
throw new UnsupportedOperationException();
}
};
public QuadReInterpolator() {
super();
}
public void setInputQuad(QuadView quad) {
int s = quad.nominalFace().ordinal() >> 1;
int xIdx = dx(s);
int yIdx = dy(s);
interpHelper.reset( //
quad.posByIndex(0, xIdx), quad.posByIndex(0, yIdx), //
quad.posByIndex(1, xIdx), quad.posByIndex(1, yIdx), //
quad.posByIndex(2, xIdx), quad.posByIndex(2, yIdx), //
quad.posByIndex(3, xIdx), quad.posByIndex(3, yIdx));
quad.copyTo(bufferQuad);
}
@Override
public boolean transform(MutableQuadView quad) {
int s = quad.nominalFace().ordinal() >> 1;
int xIdx = dx(s);
int yIdx = dy(s);
this.interpHelper.setup();
for (int i = 0; i < 4; i++) {
float x = quad.posByIndex(i, xIdx);
float y = quad.posByIndex(i, yIdx);
this.interpHelper.locate(x, y);
interpColorFrom(quad, i);
interpUVFrom(quad, i);
interpLightMapFrom(quad, i);
}
return true;
}
/**
* Interpolates the new color values for this Vertex using the others as a
* reference.
*/
public void interpColorFrom(MutableQuadView quad, int vertexIndex) {
int p1 = bufferQuad.spriteColor(0, 0);
int p2 = bufferQuad.spriteColor(1, 0);
int p3 = bufferQuad.spriteColor(2, 0);
int p4 = bufferQuad.spriteColor(3, 0);
if (p1 == p2 && p2 == p3 && p3 == p4) {
return; // Don't bother for uniformly colored quads
}
// Interpolate each color component separately
int color = 0;
int mask = 0xFF;
for (int i = 0; i < 4; i++) {
float p1c = (float) (p1 & mask);
float p2c = (float) (p2 & mask);
float p3c = (float) (p3 & mask);
float p4c = (float) (p4 & mask);
int interp = (int) interpHelper.interpolate(p1c, p2c, p3c, p4c);
color |= interp & mask;
mask <<= 8;
}
quad.spriteColor(vertexIndex, 0, color);
}
/**
* Interpolates the new UV values for this Vertex using the others as a
* reference.
*/
public void interpUVFrom(MutableQuadView quad, int vertexIndex) {
float p1 = bufferQuad.spriteU(0, 0);
float p2 = bufferQuad.spriteU(1, 0);
float p3 = bufferQuad.spriteU(2, 0);
float p4 = bufferQuad.spriteU(3, 0);
float u = interpHelper.interpolate(p1, p2, p3, p4);
p1 = bufferQuad.spriteV(0, 0);
p2 = bufferQuad.spriteV(1, 0);
p3 = bufferQuad.spriteV(2, 0);
p4 = bufferQuad.spriteV(3, 0);
float v = interpHelper.interpolate(p1, p2, p3, p4);
quad.sprite(vertexIndex, 0, u, v);
}
/**
* Interpolates the new LightMap values for this Vertex using the others as a
* reference.
*
* @return The same Vertex.
*/
public void interpLightMapFrom(MutableQuadView quad, int vertexIndex) {
for (int e = 0; e < 2; e++) {
// FIXME float p1 = others[0].lightmap[e];
// FIXME float p2 = others[1].lightmap[e];
// FIXME float p3 = others[2].lightmap[e];
// FIXME float p4 = others[3].lightmap[e];
// FIXME if (p1 != p2 || p2 != p3 || p3 != p4) {
// FIXME this.lightmap[e] = interpHelper.interpolate(p1, p2, p3, p4);
// FIXME }
}
}
/**
* Gets the 2d X coord for the given axis.
*
* @param s The axis. side >> 1
* @return The x coord.
*/
private static int dx(int s) {
if (s <= 1) {
return 0;
} else {
return 2;
}
}
/**
* Gets the 2d Y coord for the given axis.
*
* @param s The axis. side >> 1
* @return The y coord.
*/
private static int dy(int s) {
if (s > 0) {
return 1;
} else {
return 2;
}
}
}
@@ -0,0 +1,59 @@
/*
* This file is part of CodeChickenLib.
* Copyright (c) 2018, covers1624, All rights reserved.
*
* CodeChickenLib 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 2.1 of the License, or
* (at your option) any later version.
*
* CodeChickenLib 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 CodeChickenLib. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.impl.client.indigo.renderer.helper.ColorHelper;
/**
* This transformer tints quads.. Feed it the output of
* BlockColors.colorMultiplier.
*
* @author covers1624
*/
public class QuadTinter implements RenderContext.QuadTransform {
private int tint;
QuadTinter() {
super();
}
public QuadTinter(int tint) {
this.tint = tint | 0xFF000000;
}
public QuadTinter setTint(int tint) {
this.tint = tint;
return this;
}
@Override
public boolean transform(MutableQuadView quad) {
// Nuke tintIndex.
quad.colorIndex(-1);
for (int i = 0; i < 4; i++) {
int color = quad.spriteColor(i, 0);
color = ColorHelper.multiplyColor(color, tint);
quad.spriteColor(i, 0, color);
}
return true;
}
}
@@ -24,9 +24,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.Optional;
import appeng.util.BlockUpdateFlag;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.block.entity.BlockEntityType;
@@ -251,15 +249,15 @@ public class CraftingBlockEntity extends AENetworkBlockEntity
final LinkedList<BlockPos> places = new LinkedList<>();
final Iterator<CraftingTileEntity> i = this.cluster.getTiles();
final Iterator<CraftingBlockEntity> i = this.cluster.getTiles();
while (i.hasNext()) {
final CraftingTileEntity h = i.next();
final CraftingBlockEntity h = i.next();
if (h == this) {
places.add(pos);
} else {
for (Direction d : Direction.values()) {
BlockPos p = h.pos.offset(d);
if (this.world.isAirBlock(p)) {
if (this.world.isAir(p)) {
places.add(p);
}
}
@@ -50,8 +50,8 @@ import appeng.core.AppEng;
@Environment(EnvType.CLIENT)
public class MolecularAssemblerRenderer extends BlockEntityRenderer<MolecularAssemblerBlockEntity> {
public static final Identifier LIGHTS_MODEL = new Identifier(AppEng.MOD_ID,
"block/molecular_assembler_lights");
public static final ModelIdentifier LIGHTS_MODEL = new ModelIdentifier(AppEng.makeId(
"block/molecular_assembler_lights"), "");
private static final RenderLayer MC_161917_RENDERTYPE_FIX = createRenderType();
@@ -93,7 +93,7 @@ public class MolecularAssemblerRenderer extends BlockEntityRenderer<MolecularAss
// even the fully transparent part)
// https://bugs.mojang.com/browse/MC-161917
MinecraftClient minecraft = MinecraftClient.getInstance();
BakedModel lightsModel = minecraft.getBakedModelManager().getModel(new ModelIdentifier(LIGHTS_MODEL, ""));
BakedModel lightsModel = minecraft.getBakedModelManager().getModel(LIGHTS_MODEL);
VertexConsumer buffer = bufferIn.getBuffer(MC_161917_RENDERTYPE_FIX);
minecraft.getBlockRenderManager().getModelRenderer().render(ms.peek(), buffer, null,
@@ -53,6 +53,7 @@ import appeng.api.util.AEColor;
import appeng.api.util.IConfigManager;
import appeng.container.implementations.MEMonitorableContainer;
import appeng.core.Api;
import appeng.fluids.container.FluidTerminalContainer;
import appeng.fluids.util.AEFluidStack;
import appeng.helpers.IPriorityHost;
import appeng.me.GridAccessException;
@@ -782,8 +783,7 @@ public class ChestBlockEntity extends AENetworkPowerBlockEntity
}
if (this.cellHandler.getChannel() == Api.instance().storage()
.getStorageChannel(IFluidStorageChannel.class)) {
throw new IllegalStateException();
// FIXME FABRIC return FluidTerminalContainer.TYPE;
return FluidTerminalContainer.TYPE;
}
}
return null;
@@ -39,6 +39,9 @@ import net.minecraft.util.math.Direction;
*/
public abstract class InventoryAdaptor implements Iterable<ItemSlot> {
public static InventoryAdaptor getAdaptor(final BlockEntity te, final Direction d) {
if (te == null) {
return null;
}
FixedItemInv inv = ItemAttributes.FIXED_INV.get(te.getWorld(), te.getPos(), SearchOptions.inDirection(d.getOpposite()));
if (inv == ItemAttributes.FIXED_INV.defaultValue) {