Reorganized Imports/Packages

This commit is contained in:
Frank 2022-05-18 23:56:23 +02:00
parent cb9459f176
commit 3ee10482ab
721 changed files with 34873 additions and 33558 deletions

View file

@ -0,0 +1,93 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.inventory.AnvilScreen;
import net.minecraft.client.gui.screens.inventory.ItemCombinerScreen;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.AnvilMenu;
import net.minecraft.world.item.ItemStack;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.vertex.PoseStack;
import org.betterx.bclib.interfaces.AnvilScreenHandlerExtended;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(AnvilScreen.class)
public class AnvilScreenMixin extends ItemCombinerScreen<AnvilMenu> {
@Shadow
private EditBox name;
private final List<AbstractWidget> be_buttons = Lists.newArrayList();
public AnvilScreenMixin(AnvilMenu handler, Inventory playerInventory, Component title, ResourceLocation texture) {
super(handler, playerInventory, title, texture);
}
@Inject(method = "subInit", at = @At("TAIL"))
protected void be_subInit(CallbackInfo info) {
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
be_buttons.clear();
be_buttons.add(new Button(x + 8, y + 45, 15, 20, Component.literal("<"), b -> be_previousRecipe()));
be_buttons.add(new Button(x + 154, y + 45, 15, 20, Component.literal(">"), b -> be_nextRecipe()));
}
@Inject(method = "renderFg", at = @At("TAIL"))
protected void be_renderForeground(PoseStack matrices, int mouseX, int mouseY, float delta, CallbackInfo info) {
be_buttons.forEach(button -> {
button.render(matrices, mouseX, mouseY, delta);
});
}
@Inject(method = "slotChanged", at = @At("HEAD"), cancellable = true)
public void be_onSlotUpdate(AbstractContainerMenu handler, int slotId, ItemStack stack, CallbackInfo info) {
AnvilScreenHandlerExtended anvilHandler = (AnvilScreenHandlerExtended) handler;
if (anvilHandler.be_getCurrentRecipe() != null) {
if (anvilHandler.be_getRecipes().size() > 1) {
be_buttons.forEach(button -> button.visible = true);
} else {
be_buttons.forEach(button -> button.visible = false);
}
name.setValue("");
info.cancel();
} else {
be_buttons.forEach(button -> button.visible = false);
}
}
private void be_nextRecipe() {
((AnvilScreenHandlerExtended) menu).be_nextRecipe();
}
private void be_previousRecipe() {
((AnvilScreenHandlerExtended) menu).be_previousRecipe();
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (minecraft != null) {
for (AbstractWidget elem : be_buttons) {
if (elem.visible && elem.mouseClicked(mouseX, mouseY, button)) {
if (minecraft.gameMode != null) {
int i = be_buttons.indexOf(elem);
minecraft.gameMode.handleInventoryButtonClick(menu.containerId, i);
return true;
}
}
}
}
return super.mouseClicked(mouseX, mouseY, button);
}
}

View file

@ -0,0 +1,30 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import org.betterx.bclib.interfaces.SurvivesOnSpecialGround;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import org.jetbrains.annotations.Nullable;
@Mixin(Block.class)
public class BlockMixin {
@Inject(method = "appendHoverText", at = @At("HEAD"))
void bclib_appendSurvivalBlock(ItemStack itemStack,
@Nullable BlockGetter blockGetter,
List<Component> list,
TooltipFlag tooltipFlag,
CallbackInfo ci) {
if (this instanceof SurvivesOnSpecialGround surv) {
SurvivesOnSpecialGround.appendHoverText(list, surv.getSurvivableBlocksString());
}
}
}

View file

@ -0,0 +1,21 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.RecipeBookCategories;
import net.minecraft.world.item.crafting.Recipe;
import org.betterx.bclib.interfaces.UnknownReceipBookCategory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ClientRecipeBook.class)
public abstract class ClientRecipeBookMixin {
@Inject(method = "getCategory", at = @At("HEAD"), cancellable = true)
private static void be_getGroupForRecipe(Recipe<?> recipe, CallbackInfoReturnable<RecipeBookCategories> info) {
if (recipe instanceof UnknownReceipBookCategory) {
info.setReturnValue(RecipeBookCategories.UNKNOWN);
}
}
}

View file

@ -0,0 +1,24 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
import net.minecraft.client.gui.screens.worldselection.WorldGenSettingsComponent;
import net.minecraft.core.Registry;
import net.minecraft.world.level.DataPackConfig;
import org.betterx.bclib.api.biomes.BiomeAPI;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(CreateWorldScreen.class)
public class CreateWorldScreenMixin {
@Inject(method = "<init>", at = @At("TAIL"))
private void bcl_init(Screen screen,
DataPackConfig dataPackConfig,
WorldGenSettingsComponent worldGenSettingsComponent,
CallbackInfo ci) {
BiomeAPI.initRegistry(worldGenSettingsComponent.registryHolder().registryOrThrow(Registry.BIOME_REGISTRY));
}
}

View file

@ -0,0 +1,68 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.Camera;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.FogRenderer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.material.FogType;
import org.betterx.bclib.client.render.CustomFogRenderer;
import org.betterx.bclib.util.BackgroundInfo;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(FogRenderer.class)
public class FogRendererMixin {
@Shadow
private static float fogRed;
@Shadow
private static float fogGreen;
@Shadow
private static float fogBlue;
@Inject(method = "setupColor", at = @At("RETURN"))
private static void bclib_onRender(Camera camera,
float tickDelta,
ClientLevel world,
int i,
float f,
CallbackInfo info) {
FogType fogType = camera.getFluidInCamera();
if (fogType != FogType.WATER && world.dimension().equals(Level.END)) {
Entity entity = camera.getEntity();
boolean skip = false;
if (entity instanceof LivingEntity) {
MobEffectInstance effect = ((LivingEntity) entity).getEffect(MobEffects.NIGHT_VISION);
skip = effect != null && effect.getDuration() > 0;
}
if (!skip) {
fogRed *= 4;
fogGreen *= 4;
fogBlue *= 4;
}
}
BackgroundInfo.fogColorRed = fogRed;
BackgroundInfo.fogColorGreen = fogGreen;
BackgroundInfo.fogColorBlue = fogBlue;
}
@Inject(method = "setupFog", at = @At("HEAD"), cancellable = true)
private static void bclib_fogDensity(Camera camera,
FogRenderer.FogMode fogMode,
float viewDistance,
boolean thickFog,
float g,
CallbackInfo ci) {
if (CustomFogRenderer.applyFogDensity(camera, viewDistance, thickFog)) {
ci.cancel();
}
}
}

View file

@ -0,0 +1,18 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.Game;
import org.betterx.bclib.api.dataexchange.DataExchangeAPI;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Game.class)
public class GameMixin {
@Inject(method = "onStartGameSession", at = @At("TAIL"))
public void bclib_onStart(CallbackInfo ci) {
DataExchangeAPI.sendOnEnter();
}
}

View file

@ -0,0 +1,36 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.color.item.ItemColors;
import net.minecraft.client.main.GameConfig;
import net.minecraft.core.Registry;
import org.betterx.bclib.interfaces.CustomColorProvider;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Minecraft.class)
public abstract class MinecraftMixin {
@Final
@Shadow
private BlockColors blockColors;
@Final
@Shadow
private ItemColors itemColors;
@Inject(method = "<init>*", at = @At("TAIL"))
private void bclib_onMCInit(GameConfig args, CallbackInfo info) {
Registry.BLOCK.forEach(block -> {
if (block instanceof CustomColorProvider provider) {
blockColors.register(provider.getProvider(), block);
itemColors.register(provider.getItemProvider(), block.asItem());
}
});
}
}

View file

@ -0,0 +1,38 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import org.betterx.bclib.api.ModIntegrationAPI;
import org.betterx.bclib.client.models.CustomModelBakery;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(ModelBakery.class)
public abstract class ModelBakeryMixin {
@Final
@Shadow
private Map<ResourceLocation, UnbakedModel> unbakedCache;
@Inject(method = "<init>*", at = @At("TAIL"))
private void bclib_findEmissiveModels(ResourceManager resourceManager,
BlockColors blockColors,
ProfilerFiller profiler,
int mipmap,
CallbackInfo info) {
//CustomModelBakery.setModelsLoaded(false);
if (ModIntegrationAPI.hasCanvas()) {
CustomModelBakery.loadEmissiveModels(unbakedCache);
}
}
}

View file

@ -0,0 +1,22 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
import org.betterx.bclib.client.BCLibClient;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ModelManager.class)
public class ModelManagerMixin {
@Inject(method = "prepare", at = @At("HEAD"))
private void bclib_loadCustomModels(ResourceManager resourceManager,
ProfilerFiller profilerFiller,
CallbackInfoReturnable<ModelBakery> info) {
BCLibClient.modelBakery.loadCustomModels(resourceManager);
}
}

View file

@ -0,0 +1,55 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.FallbackResourceManager;
import net.minecraft.server.packs.resources.MultiPackResourceManager;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.api.ModIntegrationAPI;
import org.betterx.bclib.client.render.EmissiveTextureInfo;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.io.IOException;
import java.util.Map;
@Mixin(MultiPackResourceManager.class)
public class MultiPackResourceManagerMixin {
@Final
@Shadow
private Map<String, FallbackResourceManager> namespacedManagers;
private final ResourceLocation bclib_alphaEmissionMaterial = BCLib.makeID("materialmaps/block/alpha_emission.json");
@Inject(method = "getResource", at = @At("HEAD"), cancellable = true)
private void bclib_getResource(ResourceLocation resourceLocation,
CallbackInfoReturnable<Resource> info) throws IOException {
if (!ModIntegrationAPI.hasCanvas()) {
return;
}
if (!resourceLocation.getPath().startsWith("materialmaps")) {
return;
}
if (!resourceLocation.getPath().contains("/block/")) {
return;
}
String name = resourceLocation.getPath().replace("materialmaps/block/", "").replace(".json", "");
ResourceLocation blockID = new ResourceLocation(resourceLocation.getNamespace(), name);
if (!EmissiveTextureInfo.isEmissiveBlock(blockID)) {
return;
}
ResourceManager resourceManager = this.namespacedManagers.get(resourceLocation.getNamespace());
if (resourceManager != null && resourceManager.getResource(resourceLocation).isEmpty()) {
info.setReturnValue(resourceManager.getResource(bclib_alphaEmissionMaterial).get());
}
}
}

View file

@ -0,0 +1,77 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.SignEditScreen;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.SignRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import org.betterx.bclib.blocks.BaseSignBlock;
import org.betterx.bclib.client.render.BaseSignBlockEntityRenderer;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(SignEditScreen.class)
public abstract class SignEditScreenMixin extends Screen {
@Shadow
@Final
private SignBlockEntity sign;
@Shadow
private SignRenderer.SignModel signModel;
@Unique
private boolean bclib_renderStick;
@Unique
private boolean bclib_isSign;
protected SignEditScreenMixin(Component component) {
super(component);
}
@Inject(method = "render(Lcom/mojang/blaze3d/vertex/PoseStack;IIF)V", at = @At(
value = "INVOKE",
target = "Lcom/mojang/blaze3d/vertex/PoseStack;pushPose()V",
shift = Shift.BEFORE
), locals = LocalCapture.CAPTURE_FAILSOFT)
private void bclib_checkOffset(PoseStack poseStack,
int i,
int j,
float f,
CallbackInfo info,
float g,
BlockState blockState,
boolean bl,
boolean bl2,
float h) {
bclib_isSign = blockState.getBlock() instanceof BaseSignBlock;
if (bclib_isSign) {
bclib_renderStick = blockState.getValue(BaseSignBlock.FLOOR);
if (bclib_renderStick) {
poseStack.translate(0.0, 0.3125, 0.0);
}
}
}
@ModifyArg(method = "render(Lcom/mojang/blaze3d/vertex/PoseStack;IIF)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/geom/ModelPart;render(Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;II)V"), index = 1)
private VertexConsumer bclib_signRender(VertexConsumer consumer) {
if (bclib_isSign) {
signModel.stick.visible = bclib_renderStick;
Block block = sign.getBlockState().getBlock();
MultiBufferSource.BufferSource bufferSource = this.minecraft.renderBuffers().bufferSource();
return BaseSignBlockEntityRenderer.getConsumer(bufferSource, block);
}
return consumer;
}
}

View file

@ -0,0 +1,111 @@
package org.betterx.bclib.mixin.client;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.fabricmc.fabric.impl.client.texture.FabricSprite;
import net.fabricmc.loader.api.FabricLoader;
import com.mojang.blaze3d.platform.NativeImage;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.client.render.EmissiveTextureInfo;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.io.IOException;
import java.util.Optional;
@Mixin(TextureAtlas.class)
public class TextureAtlasMixin {
private static final int EMISSIVE_ALPHA = 254 << 24;
private boolean bclib_modifyAtlas;
@Inject(method = "<init>*", at = @At("TAIL"))
private void bclib_onAtlasInit(ResourceLocation resourceLocation, CallbackInfo info) {
boolean hasOptifine = FabricLoader.getInstance().isModLoaded("optifabric");
bclib_modifyAtlas = !hasOptifine && resourceLocation.toString().equals("minecraft:textures/atlas/blocks.png");
if (bclib_modifyAtlas) {
EmissiveTextureInfo.clear();
}
}
@Inject(method = "load(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIII)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;", at = @At("HEAD"), cancellable = true)
private void bclib_loadSprite(ResourceManager resourceManager,
TextureAtlasSprite.Info spriteInfo,
int atlasWidth,
int atlasHeight,
int maxLevel,
int posX,
int posY,
CallbackInfoReturnable<TextureAtlasSprite> info) {
if (!bclib_modifyAtlas) {
return;
}
ResourceLocation location = spriteInfo.name();
if (!location.getPath().startsWith("block")) {
return;
}
ResourceLocation emissiveLocation = new ResourceLocation(
location.getNamespace(),
"textures/" + location.getPath() + "_e.png"
);
Optional<Resource> emissiveRes = resourceManager.getResource(emissiveLocation);
if (emissiveRes.isPresent()) {
NativeImage sprite = null;
NativeImage emission = null;
try {
ResourceLocation spriteLocation = new ResourceLocation(
location.getNamespace(),
"textures/" + location.getPath() + ".png"
);
Resource resource = resourceManager.getResource(spriteLocation).orElse(null);
sprite = NativeImage.read(resource.open());
resource = emissiveRes.get();
emission = NativeImage.read(resource.open());
} catch (IOException e) {
BCLib.LOGGER.warning(e.getMessage());
}
if (sprite != null && emission != null) {
int width = Math.min(sprite.getWidth(), emission.getWidth());
int height = Math.min(sprite.getHeight(), emission.getHeight());
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int argb = emission.getPixelRGBA(x, y);
int alpha = (argb >> 24) & 255;
if (alpha > 127) {
int r = (argb >> 16) & 255;
int g = (argb >> 8) & 255;
int b = argb & 255;
if (r > 0 || g > 0 || b > 0) {
argb = (argb & 0x00FFFFFF) | EMISSIVE_ALPHA;
sprite.setPixelRGBA(x, y, argb);
}
}
}
}
TextureAtlas self = (TextureAtlas) (Object) this;
FabricSprite result = new FabricSprite(
self,
spriteInfo,
maxLevel,
atlasWidth,
atlasHeight,
posX,
posY,
sprite
);
EmissiveTextureInfo.addTexture(location);
info.setReturnValue(result);
}
}
}
}

View file

@ -0,0 +1,21 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.level.block.AnvilBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.betterx.bclib.blocks.BaseAnvilBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(AnvilBlock.class)
public class AnvilBlockMixin {
@Inject(method = "damage", at = @At("HEAD"), cancellable = true)
private static void bclib_anvilDamage(BlockState state, CallbackInfoReturnable<BlockState> info) {
if (state.getBlock() instanceof BaseAnvilBlock) {
BaseAnvilBlock anvil = (BaseAnvilBlock) state.getBlock();
info.setReturnValue(anvil.damageAnvilFall(state));
}
}
}

View file

@ -0,0 +1,208 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.*;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.betterx.bclib.blocks.BaseAnvilBlock;
import org.betterx.bclib.blocks.LeveledAnvilBlock;
import org.betterx.bclib.interfaces.AnvilScreenHandlerExtended;
import org.betterx.bclib.recipes.AnvilRecipe;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
@Mixin(AnvilMenu.class)
public abstract class AnvilMenuMixin extends ItemCombinerMenu implements AnvilScreenHandlerExtended {
private List<AnvilRecipe> be_recipes = Collections.emptyList();
private AnvilRecipe be_currentRecipe;
private DataSlot anvilLevel;
@Shadow
private int repairItemCountCost;
@Final
@Shadow
private DataSlot cost;
public AnvilMenuMixin(@Nullable MenuType<?> menuType,
int i,
Inventory inventory,
ContainerLevelAccess containerLevelAccess) {
super(menuType, i, inventory, containerLevelAccess);
}
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/inventory/ContainerLevelAccess;)V", at = @At("TAIL"))
public void be_initAnvilLevel(int syncId, Inventory inventory, ContainerLevelAccess context, CallbackInfo info) {
this.anvilLevel = addDataSlot(DataSlot.standalone());
if (context != ContainerLevelAccess.NULL) {
int level = context.evaluate((world, blockPos) -> {
Block anvilBlock = world.getBlockState(blockPos).getBlock();
if (anvilBlock instanceof LeveledAnvilBlock) {
return ((LeveledAnvilBlock) anvilBlock).getCraftingLevel();
}
return 1;
}, 1);
anvilLevel.set(level);
} else {
anvilLevel.set(1);
}
}
@Shadow
public abstract void createResult();
@Inject(method = "mayPickup", at = @At("HEAD"), cancellable = true)
protected void be_canTakeOutput(Player player, boolean present, CallbackInfoReturnable<Boolean> info) {
if (be_currentRecipe != null) {
info.setReturnValue(be_currentRecipe.checkHammerDurability(inputSlots, player));
}
}
@Inject(method = "onTake", at = @At("HEAD"), cancellable = true)
protected void bclib_onTakeAnvilOutput(Player player, ItemStack stack, CallbackInfo info) {
if (be_currentRecipe != null) {
inputSlots.getItem(0).shrink(be_currentRecipe.getInputCount());
stack = be_currentRecipe.craft(inputSlots, player);
slotsChanged(inputSlots);
access.execute((world, blockPos) -> {
final BlockState anvilState = world.getBlockState(blockPos);
final Block anvilBlock = anvilState.getBlock();
if (anvilBlock instanceof BaseAnvilBlock) {
final BaseAnvilBlock anvil = (BaseAnvilBlock) anvilBlock;
if (!player.getAbilities().instabuild && anvilState.is(BlockTags.ANVIL) && player.getRandom()
.nextDouble() < 0.1) {
BlockState damagedState = anvil.damageAnvilUse(anvilState, player.getRandom());
if (damagedState == null) {
world.removeBlock(blockPos, false);
world.levelEvent(1029, blockPos, 0);
} else {
world.setBlock(blockPos, damagedState, 2);
world.levelEvent(1030, blockPos, 0);
}
} else {
world.levelEvent(1030, blockPos, 0);
}
}
});
info.cancel();
return;
}
this.access.execute((level, blockPos) -> {
BlockState blockState = level.getBlockState(blockPos);
if (blockState.getBlock() instanceof BaseAnvilBlock) {
info.cancel();
if (!player.getAbilities().instabuild) {
player.giveExperienceLevels(-this.cost.get());
}
this.inputSlots.setItem(0, ItemStack.EMPTY);
if (this.repairItemCountCost > 0) {
ItemStack itemStack2 = this.inputSlots.getItem(1);
if (!itemStack2.isEmpty() && itemStack2.getCount() > this.repairItemCountCost) {
itemStack2.shrink(this.repairItemCountCost);
this.inputSlots.setItem(1, itemStack2);
} else {
this.inputSlots.setItem(1, ItemStack.EMPTY);
}
} else {
this.inputSlots.setItem(1, ItemStack.EMPTY);
}
this.cost.set(0);
if (!player.getAbilities().instabuild && blockState.is(BlockTags.ANVIL) && player.getRandom()
.nextFloat() < 0.12F) {
BaseAnvilBlock anvil = (BaseAnvilBlock) blockState.getBlock();
BlockState damaged = anvil.damageAnvilUse(blockState, player.getRandom());
if (damaged == null) {
level.removeBlock(blockPos, false);
level.levelEvent(1029, blockPos, 0);
} else {
level.setBlock(blockPos, damaged, 2);
level.levelEvent(1030, blockPos, 0);
}
} else {
level.levelEvent(1030, blockPos, 0);
}
}
});
}
@Inject(method = "createResult", at = @At("HEAD"), cancellable = true)
public void be_updateOutput(CallbackInfo info) {
RecipeManager recipeManager = this.player.level.getRecipeManager();
be_recipes = recipeManager.getRecipesFor(AnvilRecipe.TYPE, inputSlots, player.level);
if (be_recipes.size() > 0) {
int anvilLevel = this.anvilLevel.get();
be_recipes = be_recipes.stream()
.filter(recipe -> anvilLevel >= recipe.getAnvilLevel())
.collect(Collectors.toList());
if (be_recipes.size() > 0) {
if (be_currentRecipe == null || !be_recipes.contains(be_currentRecipe)) {
be_currentRecipe = be_recipes.get(0);
}
be_updateResult();
info.cancel();
} else {
be_currentRecipe = null;
}
}
}
@Inject(method = "setItemName", at = @At("HEAD"), cancellable = true)
public void be_setNewItemName(String string, CallbackInfo info) {
if (be_currentRecipe != null) {
info.cancel();
}
}
@Override
public boolean clickMenuButton(Player player, int id) {
if (id == 0) {
be_previousRecipe();
return true;
} else if (id == 1) {
be_nextRecipe();
return true;
}
return super.clickMenuButton(player, id);
}
private void be_updateResult() {
if (be_currentRecipe == null) return;
resultSlots.setItem(0, be_currentRecipe.assemble(inputSlots));
broadcastChanges();
}
@Override
public void be_updateCurrentRecipe(AnvilRecipe recipe) {
this.be_currentRecipe = recipe;
be_updateResult();
}
@Override
public AnvilRecipe be_getCurrentRecipe() {
return be_currentRecipe;
}
@Override
public List<AnvilRecipe> be_getRecipes() {
return be_recipes;
}
}

View file

@ -0,0 +1,39 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.HolderSet;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
@Mixin(BiomeGenerationSettings.class)
public interface BiomeGenerationSettingsAccessor {
@Accessor("features")
List<HolderSet<PlacedFeature>> bclib_getFeatures();
@Accessor("features")
@Mutable
void bclib_setFeatures(List<HolderSet<PlacedFeature>> value);
@Accessor("featureSet")
void bclib_setFeatureSet(Supplier<Set<PlacedFeature>> featureSet);
@Accessor("flowerFeatures")
void bclib_setFlowerFeatures(Supplier<List<ConfiguredFeature<?, ?>>> flowerFeatures);
@Accessor("carvers")
Map<GenerationStep.Carving, HolderSet<ConfiguredWorldCarver<?>>> bclib_getCarvers();
@Accessor("carvers")
void bclib_setCarvers(Map<GenerationStep.Carving, HolderSet<ConfiguredWorldCarver<?>>> features);
}

View file

@ -0,0 +1,9 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.level.biome.Biome;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(Biome.class)
public class BiomeMixin {
}

View file

@ -0,0 +1,36 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.BiomeSource.StepFeatureData;
import com.google.common.base.Suppliers;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.interfaces.BiomeSourceAccessor;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
@Mixin(BiomeSource.class)
public abstract class BiomeSourceMixin implements BiomeSourceAccessor {
@Shadow
protected abstract List<StepFeatureData> buildFeaturesPerStep(List<Biome> list, boolean bl);
@Shadow
public abstract Set<Biome> possibleBiomes();
@Mutable
@Shadow
@Final
private Supplier<List<StepFeatureData>> featuresPerStep;
public void bclRebuildFeatures() {
BCLib.LOGGER.info("Rebuilding features in BiomeSource " + this);
featuresPerStep = Suppliers.memoize(() -> buildFeaturesPerStep(this.possibleBiomes().stream().toList(), true));
}
}

View file

@ -0,0 +1,23 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour.BlockStateBase;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.function.Function;
@Mixin(BlockStateBase.class)
public class BlockStateBaseMixin {
@Inject(method = "is(Lnet/minecraft/world/level/block/Block;)Z", at = @At("HEAD"), cancellable = true)
private void bclib_replaceFunction(Block block, CallbackInfoReturnable<Boolean> info) {
Function<BlockStateBase, Boolean> replacement = MethodReplace.getBlockReplace(block);
if (replacement != null) {
info.setReturnValue(replacement.apply(BlockStateBase.class.cast(this)));
}
}
}

View file

@ -0,0 +1,163 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.item.BoneMealItem;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import org.betterx.bclib.api.BonemealAPI;
import org.betterx.bclib.api.biomes.BiomeAPI;
import org.betterx.bclib.util.BlocksHelper;
import org.betterx.bclib.util.MHelper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BoneMealItem.class)
public class BoneMealItemMixin {
private static final MutableBlockPos bclib_BLOCK_POS = new MutableBlockPos();
@Inject(method = "useOn", at = @At("HEAD"), cancellable = true)
private void bclib_onUse(UseOnContext context, CallbackInfoReturnable<InteractionResult> info) {
Level world = context.getLevel();
BlockPos blockPos = context.getClickedPos();
if (!world.isClientSide) {
BlockPos offseted = blockPos.relative(context.getClickedFace());
if (BonemealAPI.isTerrain(world.getBlockState(blockPos).getBlock())) {
boolean consume = false;
if (BonemealAPI.isSpreadableTerrain(world.getBlockState(blockPos).getBlock())) {
BlockState terrain = bclib_getSpreadable(world, blockPos);
if (terrain != null) {
BlocksHelper.setWithoutUpdate(world, blockPos, terrain);
consume = true;
}
} else {
BlockState stateAbove = world.getBlockState(blockPos.above());
if (!stateAbove.getFluidState().isEmpty()) {
if (stateAbove.is(Blocks.WATER)) {
consume = bclib_growWaterGrass(world, blockPos);
}
} else if (stateAbove.isAir()) {
consume = bclib_growLandGrass(world, blockPos);
}
}
if (consume) {
if (!context.getPlayer().isCreative()) {
context.getItemInHand().shrink(1);
}
world.levelEvent(2005, blockPos, 0);
info.setReturnValue(InteractionResult.SUCCESS);
info.cancel();
}
}
}
}
private boolean bclib_growLandGrass(Level world, BlockPos pos) {
int y1 = pos.getY() + 3;
int y2 = pos.getY() - 3;
boolean result = false;
for (int i = 0; i < 64; i++) {
int x = (int) (pos.getX() + world.random.nextGaussian() * 2);
int z = (int) (pos.getZ() + world.random.nextGaussian() * 2);
bclib_BLOCK_POS.setX(x);
bclib_BLOCK_POS.setZ(z);
for (int y = y1; y >= y2; y--) {
bclib_BLOCK_POS.setY(y);
BlockPos down = bclib_BLOCK_POS.below();
if (world.isEmptyBlock(bclib_BLOCK_POS) && !world.isEmptyBlock(down)) {
BlockState grass = bclib_getLandGrassState(world, down);
if (grass != null) {
BlocksHelper.setWithoutUpdate(world, bclib_BLOCK_POS, grass);
result = true;
}
break;
}
}
}
return result;
}
private boolean bclib_growWaterGrass(Level world, BlockPos pos) {
int y1 = pos.getY() + 3;
int y2 = pos.getY() - 3;
boolean result = false;
for (int i = 0; i < 64; i++) {
int x = (int) (pos.getX() + world.random.nextGaussian() * 2);
int z = (int) (pos.getZ() + world.random.nextGaussian() * 2);
bclib_BLOCK_POS.setX(x);
bclib_BLOCK_POS.setZ(z);
for (int y = y1; y >= y2; y--) {
bclib_BLOCK_POS.setY(y);
BlockPos down = bclib_BLOCK_POS.below();
if (BlocksHelper.isFluid(world.getBlockState(bclib_BLOCK_POS)) && !BlocksHelper.isFluid(world.getBlockState(
down))) {
BlockState grass = bclib_getWaterGrassState(world, down);
if (grass != null) {
BlocksHelper.setWithoutUpdate(world, bclib_BLOCK_POS, grass);
result = true;
}
break;
}
}
}
return result;
}
private BlockState bclib_getLandGrassState(Level world, BlockPos pos) {
BlockState state = world.getBlockState(pos);
Block block = state.getBlock();
block = BonemealAPI.getLandGrass(BiomeAPI.getBiomeID(world.getBiome(pos)), block, world.getRandom());
return block == null ? null : block.defaultBlockState();
}
private BlockState bclib_getWaterGrassState(Level world, BlockPos pos) {
BlockState state = world.getBlockState(pos);
Block block = state.getBlock();
block = BonemealAPI.getWaterGrass(BiomeAPI.getBiomeID(world.getBiome(pos)), block, world.getRandom());
return block == null ? null : block.defaultBlockState();
}
private BlockState bclib_getSpreadable(Level world, BlockPos pos) {
Vec3i[] offsets = MHelper.getOffsets(world.getRandom());
BlockState center = world.getBlockState(pos);
for (Vec3i dir : offsets) {
BlockPos p = pos.offset(dir);
BlockState state = world.getBlockState(p);
Block terrain = BonemealAPI.getSpreadable(state.getBlock());
if (center.is(terrain)) {
if (bclib_haveSameProperties(state, center)) {
for (Property property : center.getProperties()) {
state = state.setValue(property, center.getValue(property));
}
}
return state;
}
}
return null;
}
private boolean bclib_haveSameProperties(BlockState state1, BlockState state2) {
Property<?>[] properties1 = state1.getProperties().toArray(new Property[0]);
Property<?>[] properties2 = state2.getProperties().toArray(new Property[0]);
if (properties1.length != properties2.length) {
return false;
}
for (int i = 0; i < properties1.length; i++) {
String name1 = properties1[i].getName();
String name2 = properties2[i].getName();
if (!name1.equals(name2)) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,42 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.Registry;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import org.betterx.bclib.interfaces.ChunkGeneratorAccessor;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ChunkGenerator.class)
public class ChunkGeneratorMixin implements ChunkGeneratorAccessor {
@Shadow
@Final
protected Registry<StructureSet> structureSets;
private int bclib_featureIteratorSeed;
@ModifyArg(method = "applyBiomeDecoration", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/WorldgenRandom;setFeatureSeed(JII)V"))
private long bclib_updateFeatureSeed(long seed) {
return Long.rotateRight(seed, bclib_featureIteratorSeed++);
}
@Inject(method = "applyBiomeDecoration", at = @At("HEAD"))
private void bclib_obBiomeGenerate(WorldGenLevel worldGenLevel,
ChunkAccess chunkAccess,
StructureManager structureFeatureManager,
CallbackInfo ci) {
bclib_featureIteratorSeed = 0;
}
public Registry<StructureSet> bclib_getStructureSetsRegistry() {
return structureSets;
}
}

View file

@ -0,0 +1,15 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.ComposterBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ComposterBlock.class)
public interface ComposterBlockAccessor {
@Invoker
static void callAdd(float levelIncreaseChance, ItemLike item) {
throw new AssertionError("@Invoker dummy body called");
}
}

View file

@ -0,0 +1,32 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ContainerLevelAccess;
import net.minecraft.world.inventory.CraftingMenu;
import net.minecraft.world.level.block.CraftingTableBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.betterx.bclib.api.tag.CommonBlockTags;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(CraftingMenu.class)
public abstract class CraftingMenuMixin {
@Final
@Shadow
private ContainerLevelAccess access;
@Inject(method = "stillValid", at = @At("HEAD"), cancellable = true)
private void bclib_stillValid(Player player, CallbackInfoReturnable<Boolean> info) {
if (access.evaluate((world, pos) -> {
BlockState state = world.getBlockState(pos);
return state.getBlock() instanceof CraftingTableBlock || state.is(CommonBlockTags.WORKBENCHES);
}, true)) {
info.setReturnValue(true);
}
}
}

View file

@ -0,0 +1,16 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.DiggerItem;
import net.minecraft.world.level.block.Block;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(DiggerItem.class)
public interface DiggerItemAccessor {
@Accessor("blocks")
@Mutable
TagKey<Block> bclib_getBlockTag();
}

View file

@ -0,0 +1,62 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.WritableRegistry;
import net.minecraft.world.level.dimension.DimensionType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(DimensionType.class)
public class DimensionTypeMixin {
// @Inject(
// method = "defaultDimensions(Lnet/minecraft/core/RegistryAccess;JZ)Lnet/minecraft/core/Registry;",
// locals = LocalCapture.CAPTURE_FAILHARD,
// at = @At("TAIL")
// )
private static void bclib_updateDimensions(RegistryAccess registryAccess,
long seed,
boolean bl,
CallbackInfoReturnable<Registry> info,
WritableRegistry writableRegistry,
Registry registry,
Registry biomeRegistry,
Registry structureRegistry,
Registry noiseSettingsRegistry,
Registry noiseParamRegistry) {
//This probably moved to WorldPresets.bootstrap();
// int id = writableRegistry.getId(writableRegistry.get(LevelStem.NETHER));
// writableRegistry.registerOrOverride(
// OptionalInt.of(id),
// LevelStem.NETHER,
// new LevelStem(
// registry.getOrCreateHolder(BuiltinDimensionTypes.NETHER),
// new NoiseBasedChunkGenerator(
// structureRegistry,
// noiseParamRegistry,
// new BCLibNetherBiomeSource(biomeRegistry, seed),
// seed,
// noiseSettingsRegistry.getOrCreateHolder(NoiseGeneratorSettings.NETHER))
// ),
// Lifecycle.stable()
// );
//
//
// id = writableRegistry.getId(writableRegistry.get(LevelStem.END));
// writableRegistry.registerOrOverride(
// OptionalInt.of(id),
// LevelStem.END,
// new LevelStem(
// registry.getOrCreateHolder(BuiltinDimensionTypes.END),
// new NoiseBasedChunkGenerator(
// structureRegistry,
// noiseParamRegistry,
// new BCLibEndBiomeSource(biomeRegistry, seed),
// seed,
// noiseSettingsRegistry.getOrCreateHolder(NoiseGeneratorSettings.END))
// ),
// Lifecycle.stable()
// );
}
}

View file

@ -0,0 +1,29 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EnchantmentTableBlock;
import org.betterx.bclib.api.tag.CommonBlockTags;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(EnchantmentTableBlock.class)
public abstract class EnchantingTableBlockMixin extends Block {
public EnchantingTableBlockMixin(Properties settings) {
super(settings);
}
@Inject(method = "isValidBookShelf(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/BlockPos;)Z", at = @At("HEAD"), cancellable = true)
private static void bclib_isBookshelf(Level level,
BlockPos blockPos,
BlockPos blockPos2,
CallbackInfoReturnable<Boolean> info) {
MethodReplace.addBlockReplace(Blocks.BOOKSHELF, state -> state.is(CommonBlockTags.BOOKSHELVES));
}
}

View file

@ -0,0 +1,23 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.function.Function;
@Mixin(ItemStack.class)
public class ItemStackMixin {
@Inject(method = "is(Lnet/minecraft/world/item/Item;)Z", at = @At("HEAD"), cancellable = true)
private void bclib_replaceFunction(Item item, CallbackInfoReturnable<Boolean> info) {
Function<ItemStack, Boolean> replacement = MethodReplace.getItemReplace(item);
if (replacement != null) {
info.setReturnValue(replacement.apply(ItemStack.class.cast(this)));
}
}
}

View file

@ -0,0 +1,35 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.chunk.DataLayer;
import net.minecraft.world.level.lighting.LayerLightSectionStorage;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LayerLightSectionStorage.class)
public class LayerLightSectionStorageMixin {
@Shadow
protected DataLayer getDataLayer(long sectionPos, boolean cached) {
return null;
}
@Inject(method = "getStoredLevel", at = @At(value = "HEAD"), cancellable = true)
private void bclib_lightFix(long blockPos, CallbackInfoReturnable<Integer> info) {
try {
long pos = SectionPos.blockToSection(blockPos);
DataLayer dataLayer = this.getDataLayer(pos, true);
info.setReturnValue(dataLayer.get(
SectionPos.sectionRelative(BlockPos.getX(blockPos)),
SectionPos.sectionRelative(BlockPos.getY(blockPos)),
SectionPos.sectionRelative(BlockPos.getZ(blockPos))
));
} catch (Exception e) {
info.setReturnValue(0);
}
}
}

View file

@ -0,0 +1,61 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.server.Main;
import net.minecraft.server.dedicated.DedicatedServerSettings;
import net.minecraft.world.level.storage.LevelStorageSource;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import org.betterx.bclib.api.LifeCycleAPI;
import org.betterx.bclib.api.datafixer.DataFixerAPI;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
@Mixin(Main.class)
abstract public class MainMixin {
@Inject(method = "main", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/storage/LevelStorageSource;createDefault(Ljava/nio/file/Path;)Lnet/minecraft/world/level/storage/LevelStorageSource;"))
private static void bclib_callServerFix(String[] args, CallbackInfo ci) {
OptionParser parser = new OptionParser();
ArgumentAcceptingOptionSpec<String> optionUniverse = parser.accepts("universe")
.withRequiredArg()
.defaultsTo(".", new String[0]);
ArgumentAcceptingOptionSpec<String> optionWorld = parser.accepts("world").withRequiredArg();
//this is only for compat reasons, we do not need to read thise options in our mixin, but it seems to cause
//errors if they are not defined
parser.accepts("nogui");
parser.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits");
parser.accepts("demo");
parser.accepts("bonusChest");
parser.accepts("forceUpgrade");
parser.accepts("eraseCache");
parser.accepts("safeMode", "Loads level with vanilla datapack only");
parser.accepts("help").forHelp();
parser.accepts("singleplayer").withRequiredArg();
parser.accepts("port").withRequiredArg().ofType(Integer.class).defaultsTo(-1, new Integer[0]);
parser.accepts("serverId").withRequiredArg();
parser.accepts("jfrProfile");
parser.nonOptions();
OptionSet options = parser.parse(args);
Path settingPath = Paths.get("server.properties");
DedicatedServerSettings settings = new DedicatedServerSettings(settingPath);
File file = new File(options.valueOf(optionUniverse));
String levelID = Optional.ofNullable(options.valueOf(optionWorld)).orElse(settings.getProperties().levelName);
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(file.toPath());
DataFixerAPI.fixData(levelStorageSource, levelID, false, (didFix) -> {/* not called when showUI==false */});
LifeCycleAPI._runBeforeLevelLoad();
}
}

View file

@ -0,0 +1,82 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.WorldStem;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.players.GameProfileCache;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess;
import net.minecraft.world.level.storage.WorldData;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.datafixers.DataFixer;
import org.betterx.bclib.api.dataexchange.DataExchangeAPI;
import org.betterx.bclib.recipes.BCLRecipeManager;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.net.Proxy;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@Mixin(MinecraftServer.class)
public class MinecraftServerMixin {
@Shadow
private MinecraftServer.ReloadableResources resources;
@Final
@Shadow
private Map<ResourceKey<Level>, ServerLevel> levels;
@Final
@Shadow
protected WorldData worldData;
@Inject(method = "<init>*", at = @At("TAIL"))
private void bclib_onServerInit(Thread thread,
LevelStorageAccess levelStorageAccess,
PackRepository packRepository,
WorldStem worldStem,
Proxy proxy,
DataFixer dataFixer,
MinecraftSessionService minecraftSessionService,
GameProfileRepository gameProfileRepository,
GameProfileCache gameProfileCache,
ChunkProgressListenerFactory chunkProgressListenerFactory,
CallbackInfo ci) {
DataExchangeAPI.prepareServerside();
}
@Inject(method = "reloadResources", at = @At(value = "RETURN"), cancellable = true)
private void bclib_reloadResources(Collection<String> collection,
CallbackInfoReturnable<CompletableFuture<Void>> info) {
bclib_injectRecipes();
}
@Inject(method = "loadLevel", at = @At(value = "RETURN"), cancellable = true)
private void bclib_loadLevel(CallbackInfo info) {
bclib_injectRecipes();
}
private void bclib_injectRecipes() {
RecipeManagerAccessor accessor = (RecipeManagerAccessor) resources.managers().getRecipeManager();
accessor.bclib_setRecipesByName(BCLRecipeManager.getMapByName(accessor.bclib_getRecipesByName()));
accessor.bclib_setRecipes(BCLRecipeManager.getMap(accessor.bclib_getRecipes()));
}
@Inject(method = "createLevels", at = @At(value = "HEAD"))
private void bcl_createLevel(ChunkProgressListener chunkProgressListener, CallbackInfo ci) {
System.out.println(this.worldData);
}
}

View file

@ -0,0 +1,22 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.util.random.WeightedRandomList;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.biome.MobSpawnSettings.SpawnerData;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(MobSpawnSettings.class)
public interface MobSpawnSettingsAccessor {
@Accessor("spawners")
Map<MobCategory, WeightedRandomList<SpawnerData>> bcl_getSpawners();
@Accessor("spawners")
@Mutable
void bcl_setSpawners(Map<MobCategory, WeightedRandomList<SpawnerData>> spawners);
}

View file

@ -0,0 +1,35 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.MultiPackResourceManager;
import net.minecraft.server.packs.resources.Resource;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Optional;
@Mixin(MultiPackResourceManager.class)
public class MultiPackResourceManagerMixin {
private static final String[] BCLIB_MISSING_RESOURCES = new String[]{
"dimension/the_end.json",
"dimension/the_nether.json",
"dimension_type/the_end.json",
"dimension_type/the_nether.json"
};
@Inject(method = "getResource", at = @At("HEAD"), cancellable = true)
private void bclib_hasResource(ResourceLocation resourceLocation, CallbackInfoReturnable<Optional<Resource>> info) {
if (resourceLocation.getNamespace().equals("minecraft")) {
for (String key : BCLIB_MISSING_RESOURCES) {
if (resourceLocation.getPath().equals(key)) {
info.setReturnValue(Optional.empty());
info.cancel();
return;
}
}
}
}
}

View file

@ -0,0 +1,23 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Climate;
import net.fabricmc.fabric.impl.biome.NetherBiomeData;
import org.betterx.bclib.world.biomes.FabricBiomesData;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = NetherBiomeData.class, remap = false)
public class NetherBiomeDataMixin {
@Inject(method = "addNetherBiome", at = @At(value = "HEAD"))
private static void bclib_addNetherBiome(ResourceKey<Biome> biome,
Climate.ParameterPoint spawnNoisePoint,
CallbackInfo info) {
FabricBiomesData.NETHER_BIOMES.add(biome);
}
}

View file

@ -0,0 +1,70 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.levelgen.*;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.carver.CarvingContext;
import org.betterx.bclib.interfaces.NoiseGeneratorSettingsProvider;
import org.betterx.bclib.interfaces.SurfaceProvider;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.lang.reflect.Constructor;
import java.util.Optional;
@Mixin(NoiseBasedChunkGenerator.class)
public abstract class NoiseBasedChunkGeneratorMixin implements SurfaceProvider, NoiseGeneratorSettingsProvider {
@Final
@Shadow
protected Holder<NoiseGeneratorSettings> settings;
@Final
@Shadow
private Aquifer.FluidPicker globalFluidPicker;
private static final BlockState bclib_air = Blocks.AIR.defaultBlockState();
private static Constructor<?> bclib_constructor;
@Override
public NoiseGeneratorSettings bclib_getNoiseGeneratorSettings() {
return settings.value();
}
@Shadow
protected abstract NoiseChunk createNoiseChunk(ChunkAccess chunkAccess,
StructureManager structureManager,
Blender blender,
RandomState randomState);
@Override
@SuppressWarnings("deprecation")
public BlockState bclib_getSurface(BlockPos pos, Holder<Biome> biome, ServerLevel level) {
ChunkAccess chunkAccess = level.getChunk(pos.getX() >> 4, pos.getZ() >> 4);
StructureManager structureManager = level.structureManager();
NoiseBasedChunkGenerator generator = NoiseBasedChunkGenerator.class.cast(this);
RandomState randomState = level.getChunkSource().randomState();
NoiseChunk noiseChunk = chunkAccess.getOrCreateNoiseChunk(ca -> this.createNoiseChunk(ca,
structureManager,
Blender.empty(),
randomState));
CarvingContext carvingContext = new CarvingContext(generator,
level.registryAccess(),
chunkAccess.getHeightAccessorForGeneration(),
noiseChunk,
randomState,
this.settings.value().surfaceRule());
Optional<BlockState> optional = carvingContext.topMaterial(bpos -> biome, chunkAccess, pos, false);
return optional.isPresent() ? optional.get() : bclib_air;
}
}

View file

@ -0,0 +1,92 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.SurfaceRules;
import net.minecraft.world.level.levelgen.SurfaceRules.RuleSource;
import org.betterx.bclib.api.biomes.BiomeAPI;
import org.betterx.bclib.interfaces.SurfaceRuleProvider;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Mixin(NoiseGeneratorSettings.class)
public class NoiseGeneratorSettingsMixin implements SurfaceRuleProvider {
@Mutable
@Final
@Shadow
private SurfaceRules.RuleSource surfaceRule;
private SurfaceRules.RuleSource bclib_originalSurfaceRule;
private final Set<BiomeSource> bclib_biomeSources = new HashSet<>();
private void bclib_updateCustomRules() {
bclib_setCustomRules(BiomeAPI.getRuleSources(bclib_biomeSources));
}
@Override
public void bclib_addBiomeSource(BiomeSource source) {
bclib_biomeSources.add(source);
bclib_updateCustomRules();
}
@Override
public void bclib_clearBiomeSources() {
bclib_biomeSources.clear();
bclib_clearCustomRules();
}
private void bclib_clearCustomRules() {
if (bclib_originalSurfaceRule != null) {
this.surfaceRule = bclib_originalSurfaceRule;
bclib_originalSurfaceRule = null;
}
}
private void bclib_setCustomRules(List<RuleSource> rules) {
if (rules.size() == 0) {
bclib_clearCustomRules();
return;
}
RuleSource org = bclib_getOriginalSurfaceRule();
if (org instanceof SurfaceRules.SequenceRuleSource sequenceRule) {
List<RuleSource> currentSequence = sequenceRule.sequence();
rules = rules.stream().filter(r -> currentSequence.indexOf(r) < 0).collect(Collectors.toList());
rules.addAll(sequenceRule.sequence());
} else {
rules.add(org);
}
bclib_setSurfaceRule(SurfaceRules.sequence(rules.toArray(new RuleSource[rules.size()])));
}
void bclib_setSurfaceRule(SurfaceRules.RuleSource surfaceRule) {
if (bclib_originalSurfaceRule == null) {
bclib_originalSurfaceRule = this.surfaceRule;
}
this.surfaceRule = surfaceRule;
}
RuleSource bclib_getOriginalSurfaceRule() {
if (bclib_originalSurfaceRule == null) {
return surfaceRule;
}
return bclib_originalSurfaceRule;
}
// @Inject(method = "surfaceRule", at = @At("HEAD"), cancellable = true)
// private void bclib_surfaceRule(CallbackInfoReturnable<SurfaceRules.RuleSource> info) {
// if (bclib_surfaceRule != null) {
// info.setReturnValue(bclib_surfaceRule);
// }
// }
}

View file

@ -0,0 +1,30 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.piston.PistonBaseBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.betterx.bclib.api.tag.CommonBlockTags;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PistonBaseBlock.class)
public class PistonBaseBlockMixin {
@Inject(method = "isPushable", at = @At("HEAD"), cancellable = true)
private static void bclib_isPushable(BlockState blockState,
Level level,
BlockPos blockPos,
Direction direction,
boolean bl,
Direction direction2,
CallbackInfoReturnable<Boolean> cir) {
if (blockState.is(CommonBlockTags.IMMOBILE)) {
cir.setReturnValue(false);
cir.cancel();
}
}
}

View file

@ -0,0 +1,43 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockBehaviour.StatePredicate;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.portal.PortalShape;
import org.betterx.bclib.api.tag.CommonBlockTags;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(PortalShape.class)
public class PortalShapeMixin {
@Redirect(method = "getDistanceUntilEdgeAboveFrame", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;test(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z"))
private boolean be_getDistanceUntilEdgeAboveFrame(StatePredicate statePredicate,
BlockState blockState,
BlockGetter blockGetter,
BlockPos blockPos) {
return be_FRAME(statePredicate, blockState, blockGetter, blockPos);
}
@Redirect(method = "hasTopFrame", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;test(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z"))
private boolean be_hasTopFrame(StatePredicate statePredicate,
BlockState blockState,
BlockGetter blockGetter,
BlockPos blockPos) {
return be_FRAME(statePredicate, blockState, blockGetter, blockPos);
}
@Redirect(method = "getDistanceUntilTop", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;test(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z"))
private boolean be_getDistanceUntilTop(StatePredicate statePredicate,
BlockState blockState,
BlockGetter blockGetter,
BlockPos blockPos) {
return be_FRAME(statePredicate, blockState, blockGetter, blockPos);
}
private static boolean be_FRAME(StatePredicate FRAME, BlockState state, BlockGetter getter, BlockPos pos) {
return state.is(CommonBlockTags.NETHER_PORTAL_FRAME) || FRAME.test(state, getter, pos);
}
}

View file

@ -0,0 +1,16 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionBrewing;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(PotionBrewing.class)
public interface PotionBrewingAccessor {
@Invoker
static void callAddMix(Potion input, Item item, Potion output) {
throw new AssertionError("@Invoker dummy body called");
}
}

View file

@ -0,0 +1,26 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipeType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(RecipeManager.class)
public interface RecipeManagerAccessor {
@Accessor("recipes")
Map<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> bclib_getRecipes();
@Accessor("recipes")
void bclib_setRecipes(Map<RecipeType<?>, Map<ResourceLocation, Recipe<?>>> recipes);
@Accessor("byName")
Map<ResourceLocation, Recipe<?>> bclib_getRecipesByName();
@Accessor("byName")
void bclib_setRecipesByName(Map<ResourceLocation, Recipe<?>> recipes);
}

View file

@ -0,0 +1,34 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.Level;
import org.betterx.bclib.recipes.BCLRecipeManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
import java.util.Optional;
@Mixin(RecipeManager.class)
public abstract class RecipeManagerMixin {
@Shadow
private <C extends Container, T extends Recipe<C>> Map<ResourceLocation, Recipe<C>> byType(RecipeType<T> type) {
return null;
}
@Inject(method = "getRecipeFor", at = @At(value = "HEAD"), cancellable = true)
private <C extends Container, T extends Recipe<C>> void bclib_getRecipeFor(RecipeType<T> type,
C inventory,
Level level,
CallbackInfoReturnable<Optional<T>> info) {
info.setReturnValue(BCLRecipeManager.getSortedRecipe(type, inventory, level, this::byType));
}
}

View file

@ -0,0 +1,86 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource.LevelStorageAccess;
import net.minecraft.world.level.storage.ServerLevelData;
import net.minecraft.world.level.storage.WritableLevelData;
import org.betterx.bclib.api.LifeCycleAPI;
import org.betterx.bclib.api.biomes.BiomeAPI;
import org.betterx.bclib.world.generator.BCLBiomeSource;
import org.betterx.bclib.world.generator.BCLibNetherBiomeSource;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
@Mixin(ServerLevel.class)
public abstract class ServerLevelMixin extends Level {
private static String bclib_lastWorld = null;
protected ServerLevelMixin(WritableLevelData writableLevelData,
ResourceKey<Level> resourceKey,
Holder<DimensionType> holder,
Supplier<ProfilerFiller> supplier,
boolean bl,
boolean bl2,
long l,
int i) {
super(writableLevelData, resourceKey, holder, supplier, bl, bl2, l, i);
}
@Inject(method = "<init>*", at = @At("TAIL"))
private void bclib_onServerWorldInit(MinecraftServer server,
Executor executor,
LevelStorageAccess levelStorageAccess,
ServerLevelData serverLevelData,
ResourceKey resourceKey,
LevelStem levelStem,
ChunkProgressListener chunkProgressListener,
boolean bl,
long l,
List list,
boolean bl2,
CallbackInfo ci) {
ServerLevel level = ServerLevel.class.cast(this);
LifeCycleAPI._runLevelLoad(level,
server,
executor,
levelStorageAccess,
serverLevelData,
resourceKey,
chunkProgressListener,
bl,
l,
list,
bl2);
BiomeAPI.applyModifications(ServerLevel.class.cast(this));
if (level.dimension() == Level.NETHER) {
BCLibNetherBiomeSource.setWorldHeight(level.getChunkSource().getGenerator().getGenDepth());
}
if (levelStem.generator().getBiomeSource() instanceof BCLBiomeSource source) {
source.setSeed(level.getSeed());
}
if (bclib_lastWorld != null && bclib_lastWorld.equals(levelStorageAccess.getLevelId())) {
return;
}
bclib_lastWorld = levelStorageAccess.getLevelId();
}
}

View file

@ -0,0 +1,18 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.world.item.ShovelItem;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(ShovelItem.class)
public interface ShovelItemAccessor {
@Accessor("FLATTENABLES")
static Map<Block, BlockState> bclib_getFlattenables() {
throw new AssertionError("@Accessor dummy body called");
}
}

View file

@ -0,0 +1,17 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.Holder;
import net.minecraft.data.worldgen.Structures;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.levelgen.structure.Structure;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(Structures.class)
public interface StructuresAccessor {
@Invoker
static Holder<Structure> callRegister(ResourceKey<Structure> resourceKey, Structure structure) {
throw new RuntimeException("Unexpected call");
}
}

View file

@ -0,0 +1,48 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.Holder;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.levelgen.NoiseChunk;
import net.minecraft.world.level.levelgen.SurfaceRules;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.function.Supplier;
@Mixin(SurfaceRules.Context.class)
public interface SurfaceRulesContextAccessor {
@Accessor("blockX")
int getBlockX();
@Accessor("blockY")
int getBlockY();
@Accessor("blockZ")
int getBlockZ();
@Accessor("surfaceDepth")
int getSurfaceDepth();
@Accessor("biome")
Supplier<Holder<Biome>> getBiome();
@Accessor("chunk")
ChunkAccess getChunk();
@Accessor("noiseChunk")
NoiseChunk getNoiseChunk();
@Accessor("stoneDepthAbove")
int getStoneDepthAbove();
@Accessor("stoneDepthBelow")
int getStoneDepthBelow();
@Accessor("lastUpdateY")
long getLastUpdateY();
@Accessor("lastUpdateXZ")
long getLastUpdateXZ();
}

View file

@ -0,0 +1,26 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.tags.TagLoader;
import org.betterx.bclib.api.tag.TagAPI;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.Map;
@Mixin(TagLoader.class)
public class TagLoaderMixin {
@Final
@Shadow
private String directory;
@ModifyArg(method = "loadAndBuild", at = @At(value = "INVOKE", target = "Lnet/minecraft/tags/TagLoader;build(Ljava/util/Map;)Ljava/util/Map;"))
public Map<ResourceLocation, Tag.Builder> be_modifyTags(Map<ResourceLocation, Tag.Builder> tagsMap) {
return TagAPI.apply(directory, tagsMap);
}
}

View file

@ -0,0 +1,45 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
import net.fabricmc.fabric.impl.biome.TheEndBiomeData;
import org.betterx.bclib.world.biomes.FabricBiomesData;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = TheEndBiomeData.class, remap = false)
public class TheEndBiomeDataMixin {
@Inject(method = "addEndBiomeReplacement", at = @At(value = "HEAD"))
private static void bclib_addEndBiomeReplacement(ResourceKey<Biome> replaced,
ResourceKey<Biome> variant,
double weight,
CallbackInfo info) {
if (replaced == Biomes.END_BARRENS || replaced == Biomes.SMALL_END_ISLANDS) {
FabricBiomesData.END_VOID_BIOMES.put(variant, (float) weight);
} else {
FabricBiomesData.END_LAND_BIOMES.put(variant, (float) weight);
}
}
@Inject(method = "addEndMidlandsReplacement", at = @At(value = "HEAD"))
private static void bclib_addEndMidlandsReplacement(ResourceKey<Biome> highlands,
ResourceKey<Biome> midlands,
double weight,
CallbackInfo info) {
FabricBiomesData.END_LAND_BIOMES.put(midlands, (float) weight);
}
@Inject(method = "addEndBarrensReplacement", at = @At(value = "HEAD"))
private static void bclib_addEndBarrensReplacement(ResourceKey<Biome> highlands,
ResourceKey<Biome> barrens,
double weight,
CallbackInfo info) {
FabricBiomesData.END_LAND_BIOMES.put(barrens, (float) weight);
FabricBiomesData.END_VOID_BIOMES.put(barrens, (float) weight);
}
}

View file

@ -0,0 +1,15 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.server.dedicated.DedicatedServerProperties;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(DedicatedServerProperties.WorldGenProperties.class)
public class WorldGenPropertiesMixin {
@ModifyArg(method = "create", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/presets/WorldPreset;createWorldGenSettings(JZZ)Lnet/minecraft/world/level/levelgen/WorldGenSettings;"))
public long bcl_create(long seed) {
return seed;
}
}

View file

@ -0,0 +1,27 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(WorldGenRegion.class)
public class WorldGenRegionMixin {
@Final
@Shadow
private ChunkAccess center;
@Inject(method = "ensureCanWrite", at = @At("HEAD"), cancellable = true)
private void be_alterBlockCheck(BlockPos blockPos, CallbackInfoReturnable<Boolean> info) {
int x = blockPos.getX() >> 4;
int z = blockPos.getZ() >> 4;
WorldGenRegion region = (WorldGenRegion) (Object) this;
info.setReturnValue(Math.abs(x - center.getPos().x) < 2 && Math.abs(z - center.getPos().z) < 2);
}
}

View file

@ -0,0 +1,80 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.worldselection.WorldOpenFlows;
import net.minecraft.core.RegistryAccess;
import net.minecraft.server.ReloadableServerResources;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.WorldData;
import org.betterx.bclib.api.LifeCycleAPI;
import org.betterx.bclib.api.biomes.BiomeAPI;
import org.betterx.bclib.api.dataexchange.DataExchangeAPI;
import org.betterx.bclib.api.datafixer.DataFixerAPI;
import org.betterx.bclib.config.Configs;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(WorldOpenFlows.class)
public abstract class WorldOpenFlowsMixin {
@Shadow
@Final
private LevelStorageSource levelSource;
@Shadow
protected abstract void doLoadLevel(Screen screen, String levelID, boolean safeMode, boolean canAskForBackup);
@Inject(method = "loadLevel", cancellable = true, at = @At("HEAD"))
private void bcl_callFixerOnLoad(Screen screen, String levelID, CallbackInfo ci) {
DataExchangeAPI.prepareServerside();
BiomeAPI.prepareNewLevel();
if (DataFixerAPI.fixData(this.levelSource, levelID, true, (appliedFixes) -> {
LifeCycleAPI._runBeforeLevelLoad();
this.doLoadLevel(screen, levelID, false, false);
})) {
//cancel call when fix-screen is presented
ci.cancel();
} else {
LifeCycleAPI._runBeforeLevelLoad();
if (Configs.CLIENT_CONFIG.suppressExperimentalDialog()) {
this.doLoadLevel(screen, levelID, false, false);
//cancel call as we manually start the level load here
ci.cancel();
}
}
}
@Inject(method = "createFreshLevel", at = @At("HEAD"))
public void bcl_createFreshLevel(String levelID,
LevelSettings levelSettings,
RegistryAccess registryAccess,
WorldGenSettings worldGenSettings,
CallbackInfo ci) {
DataExchangeAPI.prepareServerside();
BiomeAPI.prepareNewLevel();
DataFixerAPI.initializeWorldData(this.levelSource, levelID, true);
LifeCycleAPI._runBeforeLevelLoad();
}
@Inject(method = "createLevelFromExistingSettings", at = @At("HEAD"))
public void bcl_createLevelFromExistingSettings(LevelStorageSource.LevelStorageAccess levelStorageAccess,
ReloadableServerResources reloadableServerResources,
RegistryAccess.Frozen frozen,
WorldData worldData,
CallbackInfo ci) {
DataExchangeAPI.prepareServerside();
BiomeAPI.prepareNewLevel();
DataFixerAPI.initializeWorldData(levelStorageAccess, true);
LifeCycleAPI._runBeforeLevelLoad();
}
}

View file

@ -0,0 +1,93 @@
package org.betterx.bclib.mixin.common;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.minecraft.world.level.levelgen.presets.WorldPresets;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.synth.NormalNoise;
import org.betterx.bclib.BCLib;
import org.betterx.bclib.world.generator.BCLibEndBiomeSource;
import org.betterx.bclib.world.generator.BCLibNetherBiomeSource;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.Map;
@Mixin(WorldPresets.Bootstrap.class)
public abstract class WorldPresetsBootstrapMixin {
private static final ResourceKey<WorldPreset> BCL_NORMAL = bcl_register("normal");
@Shadow
@Final
private Registry<WorldPreset> presets;
@Shadow
@Final
private Registry<Biome> biomes;
@Shadow
@Final
private Registry<StructureSet> structureSets;
@Shadow
@Final
private Registry<NormalNoise.NoiseParameters> noises;
@Shadow
@Final
private Holder<DimensionType> netherDimensionType;
@Shadow
@Final
private Holder<NoiseGeneratorSettings> netherNoiseSettings;
@Shadow
@Final
private Holder<DimensionType> endDimensionType;
@Shadow
@Final
private Holder<NoiseGeneratorSettings> endNoiseSettings;
//see WorldPresets.register
private static ResourceKey<WorldPreset> bcl_register(String string) {
return ResourceKey.create(Registry.WORLD_PRESET_REGISTRY, BCLib.makeID(string));
}
@ModifyArg(method = "run", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/world/level/levelgen/presets/WorldPresets$Bootstrap;registerCustomOverworldPreset(Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/level/dimension/LevelStem;)Lnet/minecraft/core/Holder;"))
private LevelStem bcl_getOverworldStem(LevelStem overworldStem) {
BCLibNetherBiomeSource netherSource = new BCLibNetherBiomeSource(this.biomes);
BCLibEndBiomeSource endSource = new BCLibEndBiomeSource(this.biomes);
LevelStem bclNether = new LevelStem(
this.netherDimensionType,
new NoiseBasedChunkGenerator(
this.structureSets,
this.noises,
netherSource,
this.netherNoiseSettings)
);
LevelStem bclEnd = new LevelStem(
this.endDimensionType,
new NoiseBasedChunkGenerator(
this.structureSets,
this.noises,
endSource,
this.endNoiseSettings)
);
WorldPreset preset = new WorldPreset(Map.of(LevelStem.OVERWORLD,
overworldStem,
LevelStem.NETHER,
bclNether,
LevelStem.END,
bclEnd));
BuiltinRegistries.register(this.presets, BCL_NORMAL, preset);
return overworldStem;
}
}

View file

@ -0,0 +1,32 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BeehiveBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import org.betterx.bclib.items.tool.BaseShearsItem;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BeehiveBlock.class)
public class BeehiveBlockMixin {
@Inject(method = "use(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/phys/BlockHitResult;)Lnet/minecraft/world/InteractionResult;", at = @At("HEAD"))
private void bclib_isShears(BlockState blockState,
Level level,
BlockPos blockPos,
Player player,
InteractionHand interactionHand,
BlockHitResult blockHitResult,
CallbackInfoReturnable<InteractionResult> info) {
MethodReplace.addItemReplace(Items.SHEARS, BaseShearsItem::isShear);
}
}

View file

@ -0,0 +1,18 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.DiggingEnchantment;
import org.betterx.bclib.items.tool.BaseShearsItem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(DiggingEnchantment.class)
public class DiggingEnchantmentMixin {
@Inject(method = "canEnchant(Lnet/minecraft/world/item/ItemStack;)Z", at = @At("HEAD"), cancellable = true)
private void bclib_isShears(ItemStack itemStack, CallbackInfoReturnable<Boolean> info) {
if (BaseShearsItem.isShear(itemStack)) info.setReturnValue(true);
}
}

View file

@ -0,0 +1,33 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.betterx.bclib.api.tag.CommonItemTags;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Set;
import org.jetbrains.annotations.Nullable;
@Mixin(ItemPredicate.class)
public abstract class ItemPredicateBuilderMixin {
@Shadow
@Final
private @Nullable Set<Item> items;
@Inject(method = "matches", at = @At("HEAD"), cancellable = true)
void bclib_isShears(ItemStack itemStack, CallbackInfoReturnable<Boolean> info) {
if (this.items != null && this.items.size() == 1 && this.items.contains(Items.SHEARS)) {
if (itemStack.is(CommonItemTags.SHEARS)) {
info.setReturnValue(true);
}
}
}
}

View file

@ -0,0 +1,24 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.animal.MushroomCow;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import org.betterx.bclib.items.tool.BaseShearsItem;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(MushroomCow.class)
public class MushroomCowMixin {
@Inject(method = "mobInteract(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;", at = @At("HEAD"))
private void bclib_isShears(Player player,
InteractionHand interactionHand,
CallbackInfoReturnable<InteractionResult> info) {
MethodReplace.addItemReplace(Items.SHEARS, BaseShearsItem::isShear);
}
}

View file

@ -0,0 +1,32 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.PumpkinBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import org.betterx.bclib.items.tool.BaseShearsItem;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PumpkinBlock.class)
public abstract class PumpkinBlockMixin {
@Inject(method = "use", at = @At("HEAD"))
private void bclib_isShears(BlockState blockState,
Level level,
BlockPos blockPos,
Player player,
InteractionHand interactionHand,
BlockHitResult blockHitResult,
CallbackInfoReturnable<InteractionResult> info) {
MethodReplace.addItemReplace(Items.SHEARS, BaseShearsItem::isShear);
}
}

View file

@ -0,0 +1,24 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.animal.Sheep;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import org.betterx.bclib.items.tool.BaseShearsItem;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Sheep.class)
public class SheepMixin {
@Inject(method = "mobInteract(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;", at = @At("HEAD"))
private void bclib_isShears(Player player,
InteractionHand interactionHand,
CallbackInfoReturnable<InteractionResult> info) {
MethodReplace.addItemReplace(Items.SHEARS, BaseShearsItem::isShear);
}
}

View file

@ -0,0 +1,24 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.animal.SnowGolem;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import org.betterx.bclib.items.tool.BaseShearsItem;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(SnowGolem.class)
public class SnowGolemMixin {
@Inject(method = "mobInteract(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;", at = @At("HEAD"))
private void bclib_isShears(Player player,
InteractionHand interactionHand,
CallbackInfoReturnable<InteractionResult> info) {
MethodReplace.addItemReplace(Items.SHEARS, BaseShearsItem::isShear);
}
}

View file

@ -0,0 +1,27 @@
package org.betterx.bclib.mixin.common.shears;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.TripWireBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.betterx.bclib.items.tool.BaseShearsItem;
import org.betterx.bclib.util.MethodReplace;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TripWireBlock.class)
public class TripWireBlockMixin {
@Inject(method = "playerWillDestroy(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/entity/player/Player;)V", at = @At("HEAD"))
private void bclib_isShears(Level level,
BlockPos blockPos,
BlockState blockState,
Player player,
CallbackInfo info) {
MethodReplace.addItemReplace(Items.SHEARS, BaseShearsItem::isShear);
}
}