Reorganized Imports/Packages
This commit is contained in:
parent
a8beba9196
commit
770a5b4046
854 changed files with 42775 additions and 41811 deletions
|
@ -0,0 +1,12 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.resources.sounds.AbstractSoundInstance;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(AbstractSoundInstance.class)
|
||||
public interface AbstractSoundInstanceAccessor {
|
||||
@Accessor("volume")
|
||||
void setVolume(float volume);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.model.ArmorStandArmorModel;
|
||||
import net.minecraft.client.renderer.entity.ArmorStandRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||
|
||||
import org.betterx.betterend.client.render.ArmoredElytraLayer;
|
||||
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(ArmorStandRenderer.class)
|
||||
public abstract class ArmorStandRendererMixin extends LivingEntityRenderer<ArmorStand, ArmorStandArmorModel> {
|
||||
|
||||
public ArmorStandRendererMixin(EntityRendererProvider.Context context, ArmorStandArmorModel entityModel, float f) {
|
||||
super(context, entityModel, f);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>*", at = @At("TAIL"))
|
||||
public void be_addCustomLayer(EntityRendererProvider.Context context, CallbackInfo ci) {
|
||||
addLayer(new ArmoredElytraLayer<>(this, context.getModelSet()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BiomeColors;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.BlockPos.MutableBlockPos;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import org.betterx.bclib.util.ColorUtil;
|
||||
import org.betterx.bclib.util.MHelper;
|
||||
import org.betterx.betterend.client.ClientOptions;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
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.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
@Mixin(BiomeColors.class)
|
||||
public class BiomeColorsMixin {
|
||||
private static final int POISON_COLOR = ColorUtil.color(92, 160, 78);
|
||||
private static final int STREAM_COLOR = ColorUtil.color(105, 213, 244);
|
||||
private static final Point[] OFFSETS;
|
||||
private static final boolean HAS_SODIUM;
|
||||
|
||||
@Inject(method = "getAverageWaterColor", at = @At("RETURN"), cancellable = true)
|
||||
private static void be_getWaterColor(BlockAndTintGetter world, BlockPos pos, CallbackInfoReturnable<Integer> info) {
|
||||
if (ClientOptions.useSulfurWaterColor()) {
|
||||
BlockAndTintGetter view = HAS_SODIUM ? Minecraft.getInstance().level : world;
|
||||
MutableBlockPos mut = new MutableBlockPos();
|
||||
mut.setY(pos.getY());
|
||||
for (int i = 0; i < OFFSETS.length; i++) {
|
||||
mut.setX(pos.getX() + OFFSETS[i].x);
|
||||
mut.setZ(pos.getZ() + OFFSETS[i].y);
|
||||
if ((view.getBlockState(mut).is(EndBlocks.BRIMSTONE))) {
|
||||
info.setReturnValue(i < 4 ? POISON_COLOR : STREAM_COLOR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
HAS_SODIUM = FabricLoader.getInstance().isModLoaded("sodium");
|
||||
|
||||
int index = 0;
|
||||
OFFSETS = new Point[20];
|
||||
for (int x = -2; x < 3; x++) {
|
||||
for (int z = -2; z < 3; z++) {
|
||||
if ((x != 0 || z != 0) && (Math.abs(x) != 2 || Math.abs(z) != 2)) {
|
||||
OFFSETS[index++] = new Point(x, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
Arrays.sort(OFFSETS, Comparator.comparingInt(pos -> MHelper.sqr(pos.x) + MHelper.sqr(pos.y)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.layers.CapeLayer;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import org.betterx.betterend.item.ArmoredElytra;
|
||||
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(CapeLayer.class)
|
||||
public class CapeLayerMixin {
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"), cancellable = true)
|
||||
public void be_checkCustomElytra(PoseStack poseStack,
|
||||
MultiBufferSource multiBufferSource,
|
||||
int i,
|
||||
AbstractClientPlayer abstractClientPlayer,
|
||||
float f,
|
||||
float g,
|
||||
float h,
|
||||
float j,
|
||||
float k,
|
||||
float l,
|
||||
CallbackInfo info) {
|
||||
ItemStack itemStack = abstractClientPlayer.getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (itemStack.getItem() instanceof ArmoredElytra) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.renderer.DimensionSpecialEffects.EndEffects;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import org.betterx.betterend.integration.Integrations;
|
||||
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(value = EndEffects.class, priority = 10)
|
||||
public class EndEffectsMixin {
|
||||
@Inject(method = "getBrightnessDependentFogColor", at = @At("HEAD"), cancellable = true)
|
||||
private void be_restoreBrightness(Vec3 color, float sunHeight, CallbackInfoReturnable<Vec3> info) {
|
||||
if (Integrations.ENDERSCAPE.modIsInstalled()) {
|
||||
info.setReturnValue(color.scale(0.15000000596046448D));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "isFoggyAt", at = @At("HEAD"), cancellable = true)
|
||||
private void be_restoreFog(int camX, int camY, CallbackInfoReturnable<Boolean> info) {
|
||||
if (Integrations.ENDERSCAPE.modIsInstalled()) {
|
||||
info.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.HumanoidMobRenderer;
|
||||
import net.minecraft.client.renderer.entity.MobRenderer;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
|
||||
import org.betterx.betterend.client.render.ArmoredElytraLayer;
|
||||
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(HumanoidMobRenderer.class)
|
||||
public abstract class HumanoidMobRendererMixin<T extends Mob, M extends HumanoidModel<T>> extends MobRenderer<T, M> {
|
||||
|
||||
public HumanoidMobRendererMixin(EntityRendererProvider.Context context, M entityModel, float f) {
|
||||
super(context, entityModel, f);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>(Lnet/minecraft/client/renderer/entity/EntityRendererProvider$Context;Lnet/minecraft/client/model/HumanoidModel;FFFF)V", at = @At("TAIL"))
|
||||
public void be_addCustomLayer(EntityRendererProvider.Context context,
|
||||
M humanoidModel,
|
||||
float f,
|
||||
float g,
|
||||
float h,
|
||||
float i,
|
||||
CallbackInfo ci) {
|
||||
addLayer(new ArmoredElytraLayer<>(this, context.getModelSet()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
|
||||
import org.betterx.betterend.events.ItemTooltipCallback;
|
||||
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.List;
|
||||
|
||||
@Mixin(ItemStack.class)
|
||||
public class ItemStackMixin {
|
||||
@Inject(method = "getTooltipLines", at = @At("RETURN"))
|
||||
private void be_getTooltip(Player entity,
|
||||
TooltipFlag tooltipContext,
|
||||
CallbackInfoReturnable<List<Component>> info) {
|
||||
ItemTooltipCallback.EVENT.invoker()
|
||||
.getTooltip(entity, ItemStack.class.cast(this), tooltipContext, info.getReturnValue());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.ProfilePublicKey;
|
||||
import net.minecraft.world.item.ElytraItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import org.betterx.betterend.interfaces.FallFlyingItem;
|
||||
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.At.Shift;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public abstract class LocalPlayerMixin extends AbstractClientPlayer {
|
||||
@Final
|
||||
@Shadow
|
||||
public ClientPacketListener connection;
|
||||
|
||||
public LocalPlayerMixin(ClientLevel clientLevel,
|
||||
GameProfile gameProfile,
|
||||
@Nullable ProfilePublicKey profilePublicKey) {
|
||||
super(clientLevel, gameProfile, profilePublicKey);
|
||||
}
|
||||
|
||||
@Inject(method = "aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getItemBySlot(Lnet/minecraft/world/entity/EquipmentSlot;)Lnet/minecraft/world/item/ItemStack;", shift = Shift.AFTER))
|
||||
public void be_aiStep(CallbackInfo info) {
|
||||
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (itemStack.getItem() instanceof FallFlyingItem && ElytraItem.isFlyEnabled(itemStack) && tryToStartFallFlying()) {
|
||||
connection.send(new ServerboundPlayerCommandPacket(
|
||||
LocalPlayer.class.cast(this),
|
||||
ServerboundPlayerCommandPacket.Action.START_FALL_FLYING
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.WinScreen;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.sounds.Music;
|
||||
import net.minecraft.sounds.Musics;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import org.betterx.bclib.util.MHelper;
|
||||
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(Minecraft.class)
|
||||
public class MinecraftClientMixin {
|
||||
@Shadow
|
||||
public LocalPlayer player;
|
||||
|
||||
@Shadow
|
||||
public Screen screen;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
public Gui gui;
|
||||
|
||||
@Shadow
|
||||
public ClientLevel level;
|
||||
|
||||
@Inject(method = "getSituationalMusic", at = @At("HEAD"), cancellable = true)
|
||||
private void be_getEndMusic(CallbackInfoReturnable<Music> info) {
|
||||
if (!(this.screen instanceof WinScreen) && this.player != null) {
|
||||
if (this.player.level.dimension() == Level.END) {
|
||||
if (this.gui.getBossOverlay().shouldPlayMusic() && MHelper.lengthSqr(
|
||||
this.player.getX(),
|
||||
this.player.getZ()
|
||||
) < 250000) {
|
||||
info.setReturnValue(Musics.END_BOSS);
|
||||
} else {
|
||||
Music sound = this.level.getBiomeManager()
|
||||
.getNoiseBiomeAtPosition(this.player.blockPosition())
|
||||
.value()
|
||||
.getBackgroundMusic()
|
||||
.orElse(Musics.END);
|
||||
info.setReturnValue(sound);
|
||||
}
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
|
||||
@Mixin(ModelBakery.class)
|
||||
public abstract class ModelLoaderMixin {
|
||||
@ModifyVariable(method = "loadModel", ordinal = 2, at = @At(value = "INVOKE"))
|
||||
public ResourceLocation be_switchModel(ResourceLocation id) {
|
||||
if (GeneratorOptions.changeChorusPlant() && be_changeModel(id)) {
|
||||
String path = id.getPath().replace("chorus", "custom_chorus");
|
||||
id = BetterEnd.makeID(path);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private boolean be_changeModel(ResourceLocation id) {
|
||||
return id.getNamespace().equals("minecraft")
|
||||
&& id.getPath().startsWith("blockstates/")
|
||||
&& id.getPath().contains("chorus")
|
||||
&& !id.getPath().contains("custom_");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.sounds.AbstractSoundInstance;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.sounds.MusicManager;
|
||||
import net.minecraft.sounds.Music;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
|
||||
import org.betterx.bclib.api.biomes.BiomeAPI;
|
||||
import org.betterx.betterend.client.ClientOptions;
|
||||
import org.betterx.betterend.world.biome.EndBiome;
|
||||
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(MusicManager.class)
|
||||
public abstract class MusicTrackerMixin {
|
||||
@Final
|
||||
@Shadow
|
||||
private Minecraft minecraft;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private RandomSource random;
|
||||
|
||||
@Shadow
|
||||
private SoundInstance currentMusic;
|
||||
|
||||
@Shadow
|
||||
private int nextSongDelay;
|
||||
|
||||
private static float volume = 1;
|
||||
private static float srcVolume = 0;
|
||||
private static long time;
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
|
||||
public void be_onTick(CallbackInfo info) {
|
||||
if (ClientOptions.blendBiomeMusic()) {
|
||||
Music musicSound = minecraft.getSituationalMusic();
|
||||
if (be_checkNullSound(musicSound) && volume > 0 && be_shouldChangeSound(musicSound) && be_isCorrectBiome()) {
|
||||
if (volume > 0) {
|
||||
if (srcVolume < 0) {
|
||||
srcVolume = currentMusic.getVolume();
|
||||
}
|
||||
if (currentMusic instanceof AbstractSoundInstance) {
|
||||
((AbstractSoundInstanceAccessor) currentMusic).setVolume(volume);
|
||||
}
|
||||
minecraft.getSoundManager()
|
||||
.updateSourceVolume(currentMusic.getSource(), currentMusic.getVolume() * volume);
|
||||
long t = System.currentTimeMillis();
|
||||
if (volume == 1 && time == 0) {
|
||||
time = t;
|
||||
}
|
||||
float delta = (t - time) * 0.0005F;
|
||||
time = t;
|
||||
volume -= delta;
|
||||
if (volume < 0) {
|
||||
volume = 0;
|
||||
}
|
||||
}
|
||||
if (volume == 0) {
|
||||
volume = 1;
|
||||
time = 0;
|
||||
srcVolume = -1;
|
||||
this.minecraft.getSoundManager().stop(this.currentMusic);
|
||||
this.nextSongDelay = Mth.nextInt(this.random, 0, musicSound.getMinDelay() / 2);
|
||||
this.currentMusic = null;
|
||||
}
|
||||
if (this.currentMusic == null && this.nextSongDelay-- <= 0) {
|
||||
this.startPlaying(musicSound);
|
||||
}
|
||||
info.cancel();
|
||||
} else {
|
||||
volume = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean be_isCorrectBiome() {
|
||||
if (minecraft.level == null) {
|
||||
return false;
|
||||
}
|
||||
return BiomeAPI.getRenderBiome(minecraft.level.getBiome(minecraft.player.blockPosition())
|
||||
.value()) instanceof EndBiome;
|
||||
}
|
||||
|
||||
private boolean be_shouldChangeSound(Music musicSound) {
|
||||
return currentMusic != null && !musicSound
|
||||
.getEvent()
|
||||
.getLocation()
|
||||
.equals(this.currentMusic.getLocation()) && musicSound.replaceCurrentMusic();
|
||||
}
|
||||
|
||||
private boolean be_checkNullSound(Music musicSound) {
|
||||
return musicSound != null && musicSound.getEvent() != null;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public abstract void startPlaying(Music type);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.betterx.betterend.mixin.client;
|
||||
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
|
||||
import org.betterx.betterend.client.render.ArmoredElytraLayer;
|
||||
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(PlayerRenderer.class)
|
||||
public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
|
||||
|
||||
public PlayerRendererMixin(EntityRendererProvider.Context context,
|
||||
PlayerModel<AbstractClientPlayer> entityModel,
|
||||
float f) {
|
||||
super(context, entityModel, f);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>*", at = @At("TAIL"))
|
||||
public void be_addCustomLayer(EntityRendererProvider.Context context, boolean bl, CallbackInfo ci) {
|
||||
addLayer(new ArmoredElytraLayer<>(this, context.getModelSet()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.item.enchantment.Enchantments;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.betterx.bclib.util.MHelper;
|
||||
import org.betterx.betterend.item.tool.EndHammerItem;
|
||||
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.List;
|
||||
|
||||
@Mixin(BlockBehaviour.class)
|
||||
public abstract class BlockBehaviourMixin {
|
||||
@Inject(method = "getDrops", at = @At("HEAD"), cancellable = true)
|
||||
public void be_getDroppedStacks(BlockState state,
|
||||
LootContext.Builder builder,
|
||||
CallbackInfoReturnable<List<ItemStack>> info) {
|
||||
if (state.is(Blocks.GLOWSTONE)) {
|
||||
ItemStack tool = builder.getParameter(LootContextParams.TOOL);
|
||||
if (tool != null && tool.getItem() instanceof EndHammerItem) {
|
||||
int min = 3;
|
||||
int max = 4;
|
||||
int count = 0;
|
||||
int fortune = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, tool);
|
||||
if (fortune > 0) {
|
||||
fortune /= Enchantments.BLOCK_FORTUNE.getMaxLevel();
|
||||
min = Mth.clamp(min + fortune, min, max);
|
||||
if (min == max) {
|
||||
info.setReturnValue(Lists.newArrayList(new ItemStack(Items.GLOWSTONE_DUST, max)));
|
||||
}
|
||||
}
|
||||
count = MHelper.randRange(min, max, MHelper.RANDOM_SOURCE);
|
||||
info.setReturnValue(Lists.newArrayList(new ItemStack(Items.GLOWSTONE_DUST, count)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.ChorusFlowerBlock;
|
||||
import net.minecraft.world.level.block.ChorusPlantBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
import org.betterx.bclib.api.tag.CommonBlockTags;
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
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;
|
||||
|
||||
@Mixin(value = ChorusFlowerBlock.class, priority = 100)
|
||||
public abstract class ChorusFlowerBlockMixin extends Block {
|
||||
private static final VoxelShape SHAPE_FULL = Block.box(0, 0, 0, 16, 16, 16);
|
||||
private static final VoxelShape SHAPE_HALF = Block.box(0, 0, 0, 16, 4, 16);
|
||||
|
||||
public ChorusFlowerBlockMixin(Properties settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private ChorusPlantBlock plant;
|
||||
|
||||
@Inject(method = "canSurvive", at = @At("HEAD"), cancellable = true)
|
||||
private void be_canSurvive(BlockState state,
|
||||
LevelReader world,
|
||||
BlockPos pos,
|
||||
CallbackInfoReturnable<Boolean> info) {
|
||||
if (world.getBlockState(pos.below()).is(EndBlocks.CHORUS_NYLIUM)) {
|
||||
info.setReturnValue(true);
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "randomTick", at = @At("HEAD"), cancellable = true)
|
||||
private void be_randomTick(BlockState state,
|
||||
ServerLevel world,
|
||||
BlockPos pos,
|
||||
RandomSource random,
|
||||
CallbackInfo info) {
|
||||
if (world.getBlockState(pos.below()).is(CommonBlockTags.END_STONES)) {
|
||||
BlockPos up = pos.above();
|
||||
if (world.isEmptyBlock(up) && up.getY() < 256) {
|
||||
int i = state.getValue(ChorusFlowerBlock.AGE);
|
||||
if (i < 5) {
|
||||
this.placeGrownFlower(world, up, i + 1);
|
||||
BlocksHelper.setWithoutUpdate(world,
|
||||
pos,
|
||||
plant.defaultBlockState()
|
||||
.setValue(ChorusPlantBlock.UP, true)
|
||||
.setValue(ChorusPlantBlock.DOWN, true));
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private void placeGrownFlower(Level world, BlockPos pos, int age) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
|
||||
if (GeneratorOptions.changeChorusPlant()) {
|
||||
return state.getValue(ChorusFlowerBlock.AGE) == 5 ? SHAPE_HALF : SHAPE_FULL;
|
||||
} else {
|
||||
return super.getShape(state, world, pos, context);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "placeDeadFlower", at = @At("HEAD"), cancellable = true)
|
||||
private void be_placeDeadFlower(Level world, BlockPos pos, CallbackInfo info) {
|
||||
BlockState down = world.getBlockState(pos.below());
|
||||
if (down.is(Blocks.CHORUS_PLANT) || down.is(CommonBlockTags.GEN_END_STONES)) {
|
||||
world.setBlock(pos, this.defaultBlockState().setValue(BlockStateProperties.AGE_5, 5), 2);
|
||||
world.levelEvent(1034, pos, 0);
|
||||
}
|
||||
info.cancel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.ChorusPlantBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
|
||||
import org.betterx.bclib.api.tag.CommonBlockTags;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
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(value = ChorusPlantBlock.class, priority = 100)
|
||||
public abstract class ChorusPlantBlockMixin extends Block {
|
||||
public ChorusPlantBlockMixin(Properties settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Inject(method = "getStateForPlacement(Lnet/minecraft/world/item/context/BlockPlaceContext;)Lnet/minecraft/world/level/block/state/BlockState;", at = @At("RETURN"), cancellable = true)
|
||||
private void be_getStateForPlacement(BlockPlaceContext ctx, CallbackInfoReturnable<BlockState> info) {
|
||||
BlockPos pos = ctx.getClickedPos();
|
||||
Level world = ctx.getLevel();
|
||||
BlockState plant = info.getReturnValue();
|
||||
if (ctx.canPlace() && plant.is(Blocks.CHORUS_PLANT) && world.getBlockState(pos.below())
|
||||
.is(CommonBlockTags.END_STONES)) {
|
||||
info.setReturnValue(plant.setValue(BlockStateProperties.DOWN, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "Lnet/minecraft/world/level/block/ChorusPlantBlock;getStateForPlacement" + "(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)" + "Lnet/minecraft/world/level/block/state/BlockState;", at = @At("RETURN"), cancellable = true)
|
||||
private void be_getStateForPlacement(BlockGetter blockGetter,
|
||||
BlockPos blockPos,
|
||||
CallbackInfoReturnable<BlockState> info) {
|
||||
BlockState plant = info.getReturnValue();
|
||||
if (plant.is(Blocks.CHORUS_PLANT) && blockGetter.getBlockState(blockPos.below())
|
||||
.is(CommonBlockTags.END_STONES)) {
|
||||
info.setReturnValue(plant.setValue(BlockStateProperties.DOWN, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "canSurvive", at = @At("HEAD"), cancellable = true)
|
||||
private void be_canSurvive(BlockState state,
|
||||
LevelReader world,
|
||||
BlockPos pos,
|
||||
CallbackInfoReturnable<Boolean> info) {
|
||||
BlockState down = world.getBlockState(pos.below());
|
||||
if (down.is(EndBlocks.CHORUS_NYLIUM) || down.is(Blocks.END_STONE)) {
|
||||
info.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "updateShape", at = @At("RETURN"), cancellable = true)
|
||||
private void be_updateShape(BlockState state,
|
||||
Direction direction,
|
||||
BlockState newState,
|
||||
LevelAccessor world,
|
||||
BlockPos pos,
|
||||
BlockPos posFrom,
|
||||
CallbackInfoReturnable<BlockState> info) {
|
||||
BlockState plant = info.getReturnValue();
|
||||
if (plant.is(Blocks.CHORUS_PLANT) && world.getBlockState(pos.below()).is(CommonBlockTags.END_STONES)) {
|
||||
plant = plant.setValue(BlockStateProperties.DOWN, true);
|
||||
info.setReturnValue(plant);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.ChorusFlowerBlock;
|
||||
import net.minecraft.world.level.block.PipeBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.feature.ChorusPlantFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
import org.betterx.bclib.util.MHelper;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
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(ChorusPlantFeature.class)
|
||||
public class ChorusPlantFeatureMixin {
|
||||
@Inject(method = "place", at = @At("HEAD"), cancellable = true)
|
||||
private void be_place(FeaturePlaceContext<NoneFeatureConfiguration> featureConfig,
|
||||
CallbackInfoReturnable<Boolean> info) {
|
||||
final RandomSource random = featureConfig.random();
|
||||
final BlockPos blockPos = featureConfig.origin();
|
||||
final WorldGenLevel structureWorldAccess = featureConfig.level();
|
||||
if (structureWorldAccess.isEmptyBlock(blockPos) && structureWorldAccess.getBlockState(blockPos.below())
|
||||
.is(EndBlocks.CHORUS_NYLIUM)) {
|
||||
ChorusFlowerBlock.generatePlant(structureWorldAccess, blockPos, random, MHelper.randRange(8, 16, random));
|
||||
BlockState bottom = structureWorldAccess.getBlockState(blockPos);
|
||||
if (bottom.is(Blocks.CHORUS_PLANT)) {
|
||||
BlocksHelper.setWithoutUpdate(
|
||||
structureWorldAccess,
|
||||
blockPos,
|
||||
bottom.setValue(PipeBlock.DOWN, true)
|
||||
);
|
||||
}
|
||||
info.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.betterx.betterend.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 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 be_stillValid(Player player, CallbackInfoReturnable<Boolean> info) {
|
||||
if (access.evaluate((world, pos) -> {
|
||||
return world.getBlockState(pos).getBlock() instanceof CraftingTableBlock;
|
||||
}, true)) {
|
||||
info.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.inventory.*;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentInstance;
|
||||
|
||||
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.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(EnchantmentMenu.class)
|
||||
public abstract class EnchantmentMenuMixin extends AbstractContainerMenu {
|
||||
@Final
|
||||
@Shadow
|
||||
private Container enchantSlots;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private ContainerLevelAccess access;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private RandomSource random;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private DataSlot enchantmentSeed;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public int[] costs;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public int[] enchantClue;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public int[] levelClue;
|
||||
|
||||
protected EnchantmentMenuMixin(MenuType<?> type, int syncId) {
|
||||
super(type, syncId);
|
||||
}
|
||||
|
||||
@Inject(method = "slotsChanged", at = @At("HEAD"), cancellable = true)
|
||||
private void be_slotsChanged(Container inventory, CallbackInfo info) {
|
||||
if (inventory == this.enchantSlots) {
|
||||
ItemStack itemStack = inventory.getItem(0);
|
||||
if (!itemStack.isEmpty() && itemStack.isEnchantable()) {
|
||||
this.access.execute((world, blockPos) -> {
|
||||
int i = 0;
|
||||
|
||||
int j;
|
||||
for (j = -1; j <= 1; ++j) {
|
||||
for (int k = -1; k <= 1; ++k) {
|
||||
if ((j != 0 || k != 0) && world.isEmptyBlock(blockPos.offset(
|
||||
k,
|
||||
0,
|
||||
j
|
||||
)) && world.isEmptyBlock(
|
||||
blockPos.offset(k, 1, j))) {
|
||||
if (world.getBlockState(blockPos.offset(k * 2, 0, j * 2))
|
||||
.is(CommonBlockTags.BOOKSHELVES)) {
|
||||
++i;
|
||||
}
|
||||
|
||||
if (world.getBlockState(blockPos.offset(k * 2, 1, j * 2))
|
||||
.is(CommonBlockTags.BOOKSHELVES)) {
|
||||
++i;
|
||||
}
|
||||
|
||||
if (k != 0 && j != 0) {
|
||||
if (world.getBlockState(blockPos.offset(k * 2, 0, j))
|
||||
.is(CommonBlockTags.BOOKSHELVES)) {
|
||||
++i;
|
||||
}
|
||||
|
||||
if (world.getBlockState(blockPos.offset(k * 2, 1, j))
|
||||
.is(CommonBlockTags.BOOKSHELVES)) {
|
||||
++i;
|
||||
}
|
||||
|
||||
if (world.getBlockState(blockPos.offset(k, 0, j * 2))
|
||||
.is(CommonBlockTags.BOOKSHELVES)) {
|
||||
++i;
|
||||
}
|
||||
|
||||
if (world.getBlockState(blockPos.offset(k, 1, j * 2))
|
||||
.is(CommonBlockTags.BOOKSHELVES)) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
random.setSeed(enchantmentSeed.get());
|
||||
|
||||
for (j = 0; j < 3; ++j) {
|
||||
costs[j] = EnchantmentHelper.getEnchantmentCost(this.random, j, i, itemStack);
|
||||
enchantClue[j] = -1;
|
||||
levelClue[j] = -1;
|
||||
if (costs[j] < j + 1) {
|
||||
costs[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 3; ++j) {
|
||||
if (this.costs[j] > 0) {
|
||||
List<EnchantmentInstance> list = this.getEnchantmentList(itemStack, j, this.costs[j]);
|
||||
if (list != null && !list.isEmpty()) {
|
||||
EnchantmentInstance enchantmentLevelEntry = list.get(this.random.nextInt(
|
||||
list.size()));
|
||||
enchantClue[j] = Registry.ENCHANTMENT.getId(enchantmentLevelEntry.enchantment);
|
||||
levelClue[j] = enchantmentLevelEntry.level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
broadcastChanges();
|
||||
});
|
||||
} else {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
costs[i] = 0;
|
||||
enchantClue[i] = -1;
|
||||
levelClue[i] = -1;
|
||||
}
|
||||
}
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private List<EnchantmentInstance> getEnchantmentList(ItemStack stack, int slot, int level) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.levelgen.WorldgenRandom;
|
||||
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.structures.EndCityStructure;
|
||||
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
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(EndCityStructure.class)
|
||||
public class EndCityFeatureMixin {
|
||||
@Inject(method = "findGenerationPoint", at = @At("HEAD"), cancellable = true)
|
||||
private void be_findGenerationPoint(Structure.GenerationContext context,
|
||||
CallbackInfoReturnable<Optional<Structure.GenerationStub>> info) {
|
||||
final ChunkPos pos = context.chunkPos();
|
||||
WorldgenRandom chunkRandom = new WorldgenRandom(new XoroshiroRandomSource(pos.x, pos.z));
|
||||
|
||||
if (GeneratorOptions.useNewGenerator()) {
|
||||
int chance = GeneratorOptions.getEndCityFailChance();
|
||||
if (chance > 0 && chunkRandom.nextInt(chance) != 0) {
|
||||
info.setReturnValue(Optional.empty());
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.pattern.BlockPattern;
|
||||
import net.minecraft.world.level.dimension.end.DragonRespawnAnimation;
|
||||
import net.minecraft.world.level.dimension.end.EndDragonFight;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
import org.slf4j.Logger;
|
||||
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.List;
|
||||
|
||||
@Mixin(EndDragonFight.class)
|
||||
public class EndDragonFightMixin {
|
||||
@Shadow
|
||||
private DragonRespawnAnimation respawnStage;
|
||||
@Shadow
|
||||
private boolean dragonKilled;
|
||||
@Shadow
|
||||
private BlockPos portalLocation;
|
||||
@Shadow
|
||||
@Final
|
||||
private static Logger LOGGER;
|
||||
@Final
|
||||
@Shadow
|
||||
private ServerLevel level;
|
||||
|
||||
@Shadow
|
||||
private BlockPattern.BlockPatternMatch findExitPortal() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private void spawnExitPortal(boolean bl) {
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private void respawnDragon(List<EndCrystal> list) {
|
||||
}
|
||||
|
||||
@Inject(method = "tryRespawn", at = @At("HEAD"), cancellable = true)
|
||||
private void be_tryRespawnDragon(CallbackInfo info) {
|
||||
if (GeneratorOptions.replacePortal() && GeneratorOptions.hasDragonFights() && this.dragonKilled && this.respawnStage == null) {
|
||||
BlockPos blockPos = portalLocation;
|
||||
if (blockPos == null) {
|
||||
LOGGER.debug("Tried to respawn, but need to find the portal first.");
|
||||
BlockPattern.BlockPatternMatch blockPatternMatch = this.findExitPortal();
|
||||
if (blockPatternMatch == null) {
|
||||
LOGGER.debug("Couldn't find a portal, so we made one.");
|
||||
spawnExitPortal(true);
|
||||
} else {
|
||||
LOGGER.debug("Found the exit portal & temporarily using it.");
|
||||
}
|
||||
}
|
||||
|
||||
List<EndCrystal> crystals = Lists.newArrayList();
|
||||
for (Direction dir : BlocksHelper.HORIZONTAL) {
|
||||
BlockPos central = BlockPos.ZERO.relative(dir, 4);
|
||||
List<EndCrystal> crystalList = level.getEntitiesOfClass(
|
||||
EndCrystal.class,
|
||||
new AABB(central.below(255).south().west(), central.above(255).north().east())
|
||||
);
|
||||
|
||||
int count = crystalList.size();
|
||||
for (int n = 0; n < count; n++) {
|
||||
EndCrystal crystal = crystalList.get(n);
|
||||
if (!level.getBlockState(crystal.blockPosition().below()).is(Blocks.BEDROCK)) {
|
||||
crystalList.remove(n);
|
||||
count--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
if (crystalList.isEmpty()) {
|
||||
info.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
crystals.addAll(crystalList);
|
||||
}
|
||||
|
||||
LOGGER.debug("Found all crystals, respawning dragon.");
|
||||
respawnDragon(crystals);
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.levelgen.Heightmap.Types;
|
||||
import net.minecraft.world.level.levelgen.feature.EndPodiumFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||
|
||||
import org.betterx.bclib.api.WorldDataAPI;
|
||||
import org.betterx.bclib.util.StructureHelper;
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
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.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(EndPodiumFeature.class)
|
||||
public class EndPodiumFeatureMixin {
|
||||
private static BlockPos be_portalPosition;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private boolean active;
|
||||
|
||||
@Inject(method = "place", at = @At("HEAD"), cancellable = true)
|
||||
private void be_place(FeaturePlaceContext<NoneFeatureConfiguration> featurePlaceContext,
|
||||
CallbackInfoReturnable<Boolean> info) {
|
||||
if (!GeneratorOptions.hasPortal()) {
|
||||
info.setReturnValue(false);
|
||||
info.cancel();
|
||||
} else if (GeneratorOptions.replacePortal()) {
|
||||
RandomSource random = featurePlaceContext.random();
|
||||
WorldGenLevel world = featurePlaceContext.level();
|
||||
BlockPos blockPos = be_updatePortalPos(world);
|
||||
StructureTemplate structure = StructureHelper.readStructure(BetterEnd.makeID(active
|
||||
? "portal/end_portal_active"
|
||||
: "portal/end_portal_inactive"));
|
||||
Vec3i size = structure.getSize();
|
||||
blockPos = blockPos.offset(-(size.getX() >> 1), -3, -(size.getZ() >> 1));
|
||||
structure.placeInWorld(world, blockPos, blockPos, new StructurePlaceSettings(), random, 2);
|
||||
info.setReturnValue(true);
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "place", ordinal = 0, at = @At("HEAD"))
|
||||
private FeaturePlaceContext<NoneFeatureConfiguration> be_setPosOnGround(FeaturePlaceContext<NoneFeatureConfiguration> featurePlaceContext) {
|
||||
WorldGenLevel world = featurePlaceContext.level();
|
||||
BlockPos pos = be_updatePortalPos(world);
|
||||
return new FeaturePlaceContext<NoneFeatureConfiguration>(
|
||||
Optional.empty(),
|
||||
world,
|
||||
featurePlaceContext.chunkGenerator(),
|
||||
featurePlaceContext.random(),
|
||||
pos,
|
||||
featurePlaceContext.config()
|
||||
);
|
||||
}
|
||||
|
||||
private BlockPos be_updatePortalPos(WorldGenLevel world) {
|
||||
CompoundTag compound = WorldDataAPI.getRootTag(BetterEnd.MOD_ID).getCompound("portal");
|
||||
be_portalPosition = NbtUtils.readBlockPos(compound);
|
||||
|
||||
if (be_portalPosition.getY() == 0) {
|
||||
/*if (GeneratorOptions.useNewGenerator()) {
|
||||
int y = TerrainGenerator.getHeight(0, 0, world.getLevel().getChunkSource().getGenerator().getBiomeSource());
|
||||
be_portalPosition = new BlockPos(0, y, 0);
|
||||
}
|
||||
else {
|
||||
be_portalPosition = new BlockPos(0, 65, 0);
|
||||
}*/
|
||||
int y = world.getHeight(Types.WORLD_SURFACE, 0, 0);
|
||||
be_portalPosition = new BlockPos(0, y, 0);
|
||||
WorldDataAPI.getRootTag(BetterEnd.MOD_ID).put("portal", NbtUtils.writeBlockPos(be_portalPosition));
|
||||
WorldDataAPI.saveFile(BetterEnd.MOD_ID);
|
||||
}
|
||||
|
||||
return be_portalPosition;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.levelgen.feature.SpikeFeature.EndSpike;
|
||||
|
||||
import org.betterx.bclib.api.WorldDataAPI;
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
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(EndSpike.class)
|
||||
public class EndSpikeMixin {
|
||||
@Final
|
||||
@Shadow
|
||||
private int height;
|
||||
|
||||
@Inject(method = "getHeight", at = @At("HEAD"), cancellable = true)
|
||||
private void be_getSpikeHeight(CallbackInfoReturnable<Integer> info) {
|
||||
if (!GeneratorOptions.isDirectSpikeHeight()) {
|
||||
int x = getCenterX();
|
||||
int z = getCenterZ();
|
||||
String pillarID = String.format("%d_%d", x, z);
|
||||
CompoundTag pillar = WorldDataAPI.getCompoundTag(BetterEnd.MOD_ID, "pillars");
|
||||
int minY = pillar.contains(pillarID) ? pillar.getInt(pillarID) : 65;
|
||||
int maxY = minY + height - 54;
|
||||
info.setReturnValue(maxY);
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public int getCenterX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public int getCenterZ() {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.monster.EnderMan;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
|
||||
import org.betterx.betterend.effects.EndStatusEffects;
|
||||
import org.betterx.betterend.registry.EndEnchantments;
|
||||
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(EnderMan.class)
|
||||
public abstract class EnderManMixin {
|
||||
@Inject(method = "isLookingAtMe", at = @At("HEAD"), cancellable = true)
|
||||
private void be_isLookingAtMe(Player player, CallbackInfoReturnable<Boolean> info) {
|
||||
if (player.isCreative() || player.hasEffect(EndStatusEffects.END_VEIL) || EnchantmentHelper.getItemEnchantmentLevel(
|
||||
EndEnchantments.END_VEIL,
|
||||
player.getItemBySlot(EquipmentSlot.HEAD)
|
||||
) > 0) {
|
||||
info.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.portal.PortalInfo;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import org.betterx.betterend.interfaces.TeleportingEntity;
|
||||
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(Entity.class)
|
||||
public abstract class EntityMixin implements TeleportingEntity {
|
||||
@Shadow
|
||||
private float yRot;
|
||||
@Shadow
|
||||
private float xRot;
|
||||
|
||||
@Shadow
|
||||
public Level level;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
public abstract void unRide();
|
||||
|
||||
@Shadow
|
||||
public abstract Vec3 getDeltaMovement();
|
||||
|
||||
@Shadow
|
||||
public abstract EntityType<?> getType();
|
||||
|
||||
@Shadow
|
||||
protected abstract PortalInfo findDimensionEntryPoint(ServerLevel destination);
|
||||
|
||||
@Shadow
|
||||
protected abstract void removeAfterChangingDimensions();
|
||||
|
||||
@Shadow
|
||||
public abstract boolean isRemoved();
|
||||
|
||||
private BlockPos exitPos;
|
||||
|
||||
@Inject(method = "changeDimension", at = @At("HEAD"), cancellable = true)
|
||||
public void be_changeDimension(ServerLevel destination, CallbackInfoReturnable<Entity> info) {
|
||||
if (!isRemoved() && be_canTeleport() && level instanceof ServerLevel) {
|
||||
unRide();
|
||||
level.getProfiler().push("changeDimension");
|
||||
level.getProfiler().push("reposition");
|
||||
PortalInfo teleportTarget = findDimensionEntryPoint(destination);
|
||||
if (teleportTarget != null) {
|
||||
level.getProfiler().popPush("reloading");
|
||||
Entity entity = getType().create(destination);
|
||||
if (entity != null) {
|
||||
entity.restoreFrom(Entity.class.cast(this));
|
||||
entity.moveTo(
|
||||
teleportTarget.pos.x,
|
||||
teleportTarget.pos.y,
|
||||
teleportTarget.pos.z,
|
||||
teleportTarget.yRot,
|
||||
entity.getXRot()
|
||||
);
|
||||
entity.setDeltaMovement(teleportTarget.speed);
|
||||
destination.addDuringTeleport(entity);
|
||||
}
|
||||
|
||||
this.removeAfterChangingDimensions();
|
||||
level.getProfiler().pop();
|
||||
((ServerLevel) level).resetEmptyTime();
|
||||
destination.resetEmptyTime();
|
||||
level.getProfiler().pop();
|
||||
be_resetExitPos();
|
||||
info.setReturnValue(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "findDimensionEntryPoint", at = @At("HEAD"), cancellable = true)
|
||||
protected void be_findDimensionEntryPoint(ServerLevel destination, CallbackInfoReturnable<PortalInfo> info) {
|
||||
if (be_canTeleport()) {
|
||||
info.setReturnValue(new PortalInfo(
|
||||
new Vec3(exitPos.getX() + 0.5, exitPos.getY(), exitPos.getZ() + 0.5),
|
||||
getDeltaMovement(),
|
||||
yRot,
|
||||
xRot
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void be_setExitPos(BlockPos pos) {
|
||||
this.exitPos = pos.immutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void be_resetExitPos() {
|
||||
this.exitPos = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean be_canTeleport() {
|
||||
return this.exitPos != null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
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(Level.class)
|
||||
public class LevelMixin {
|
||||
|
||||
@Inject(method = "getSharedSpawnPos", at = @At("HEAD"), cancellable = true)
|
||||
private void be_getSharedSpawnPos(CallbackInfoReturnable<BlockPos> info) {
|
||||
if (GeneratorOptions.changeSpawn()) {
|
||||
if (ServerLevel.class.cast(this).dimension() == Level.END) {
|
||||
BlockPos pos = GeneratorOptions.getSpawn();
|
||||
info.setReturnValue(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.tags.EntityTypeTags;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.*;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeMap;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.animal.FlyingAnimal;
|
||||
import net.minecraft.world.item.ElytraItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.item.enchantment.Enchantments;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.interfaces.FallFlyingItem;
|
||||
import org.betterx.betterend.interfaces.MobEffectApplier;
|
||||
import org.betterx.betterend.item.CrystaliteArmor;
|
||||
import org.betterx.betterend.registry.EndAttributes;
|
||||
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.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.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@Mixin(value = LivingEntity.class, priority = 200)
|
||||
public abstract class LivingEntityMixin extends Entity {
|
||||
|
||||
public LivingEntityMixin(EntityType<?> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
protected int fallFlyTicks;
|
||||
|
||||
@Shadow
|
||||
public abstract boolean hasEffect(MobEffect mobEffect);
|
||||
|
||||
@Shadow
|
||||
public abstract ItemStack getItemBySlot(EquipmentSlot equipmentSlot);
|
||||
|
||||
@Shadow
|
||||
public abstract void calculateEntityAnimation(LivingEntity livingEntity, boolean b);
|
||||
|
||||
@Shadow
|
||||
protected abstract SoundEvent getFallDamageSound(int i);
|
||||
|
||||
@Shadow
|
||||
public abstract boolean isFallFlying();
|
||||
|
||||
@Shadow
|
||||
public abstract AttributeMap getAttributes();
|
||||
|
||||
private Entity lastAttacker;
|
||||
|
||||
@Inject(method = "createLivingAttributes", at = @At("RETURN"), cancellable = true)
|
||||
private static void be_addLivingAttributes(CallbackInfoReturnable<AttributeSupplier.Builder> info) {
|
||||
EndAttributes.addLivingEntityAttributes(info.getReturnValue());
|
||||
}
|
||||
|
||||
@Inject(method = "tickEffects", at = @At("HEAD"))
|
||||
protected void be_applyEffects(CallbackInfo info) {
|
||||
if (!level.isClientSide()) {
|
||||
LivingEntity owner = LivingEntity.class.cast(this);
|
||||
if (CrystaliteArmor.hasFullSet(owner)) {
|
||||
CrystaliteArmor.applySetEffect(owner);
|
||||
}
|
||||
getArmorSlots().forEach(itemStack -> {
|
||||
if (itemStack.getItem() instanceof MobEffectApplier) {
|
||||
((MobEffectApplier) itemStack.getItem()).applyEffect(owner);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "canBeAffected", at = @At("HEAD"), cancellable = true)
|
||||
public void be_canBeAffected(MobEffectInstance mobEffectInstance, CallbackInfoReturnable<Boolean> info) {
|
||||
try {
|
||||
if (mobEffectInstance.getEffect() == MobEffects.BLINDNESS && getAttributes().getValue(EndAttributes.BLINDNESS_RESISTANCE) > 0.0) {
|
||||
info.setReturnValue(false);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
BetterEnd.LOGGER.warning("Blindness resistance attribute haven't been registered.");
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "hurt", at = @At("HEAD"))
|
||||
public void be_hurt(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) {
|
||||
this.lastAttacker = source.getEntity();
|
||||
}
|
||||
|
||||
@ModifyArg(method = "hurt", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V"), index = 0)
|
||||
private double be_increaseKnockback(double value, double x, double z) {
|
||||
if (lastAttacker != null && lastAttacker instanceof LivingEntity) {
|
||||
LivingEntity attacker = (LivingEntity) lastAttacker;
|
||||
value += this.be_getKnockback(attacker.getMainHandItem().getItem());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// FlyFallingLib (part of Origin) redirected the call to updateFallFlying,
|
||||
// so we inject our code before the actual call and cancel the execution if the player is still
|
||||
// flying. That means we have to replicate all vanilla code that happens after the call to
|
||||
// updateFallFlying. We do this in vanillaAfterUpdateFallFlying
|
||||
@Inject(method = "aiStep", cancellable = true, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;updateFallFlying()V"))
|
||||
private void be_updateFallFlying_originFix(CallbackInfo info) {
|
||||
//run be_updateFallFlying instead
|
||||
if (!BetterEnd.RUNS_FALL_FLYING_LIB) return;
|
||||
|
||||
if (be_updateFallFlyingCommon()) {
|
||||
vanillaAfterUpdateFallFlying();
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "updateFallFlying", at = @At("HEAD"), cancellable = true)
|
||||
private void be_updateFallFlying(CallbackInfo info) {
|
||||
//run be_updateFallFlying_originFix instead?
|
||||
if (BetterEnd.RUNS_FALL_FLYING_LIB) return;
|
||||
if (be_updateFallFlyingCommon()) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean be_updateFallFlyingCommon() {
|
||||
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (!level.isClientSide && itemStack.getItem() instanceof FallFlyingItem) {
|
||||
boolean isFlying = getSharedFlag(7);
|
||||
if (isFlying && !onGround && !isPassenger() && !hasEffect(MobEffects.LEVITATION)) {
|
||||
if (ElytraItem.isFlyEnabled(itemStack)) {
|
||||
int level = 20 + EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, itemStack) * 5;
|
||||
if ((fallFlyTicks + 1) % level == 0) {
|
||||
itemStack.hurtAndBreak(
|
||||
1,
|
||||
LivingEntity.class.cast(this),
|
||||
livingEntity -> livingEntity.broadcastBreakEvent(EquipmentSlot.CHEST)
|
||||
);
|
||||
}
|
||||
isFlying = true;
|
||||
} else {
|
||||
isFlying = false;
|
||||
}
|
||||
} else {
|
||||
isFlying = false;
|
||||
}
|
||||
setSharedFlag(7, isFlying);
|
||||
return isFlying;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
protected abstract void removeFrost();
|
||||
@Shadow
|
||||
protected abstract void tryAddFrost();
|
||||
@Shadow
|
||||
protected abstract void pushEntities();
|
||||
@Shadow
|
||||
protected abstract void checkAutoSpinAttack(AABB aABB, AABB aABB2);
|
||||
|
||||
@Shadow
|
||||
protected int autoSpinAttackTicks;
|
||||
|
||||
private void vanillaAfterUpdateFallFlying() {
|
||||
LivingEntity self = (LivingEntity) (Object) this;
|
||||
AABB aABB = this.getBoundingBox();
|
||||
self.travel(new Vec3(self.xxa, self.yya, self.zza));
|
||||
this.level.getProfiler().pop();
|
||||
this.level.getProfiler().push("freezing");
|
||||
boolean bl2 = this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES);
|
||||
int o;
|
||||
if (!this.level.isClientSide && !self.isDeadOrDying()) {
|
||||
o = this.getTicksFrozen();
|
||||
if (this.isInPowderSnow && this.canFreeze()) {
|
||||
this.setTicksFrozen(Math.min(this.getTicksRequiredToFreeze(), o + 1));
|
||||
} else {
|
||||
this.setTicksFrozen(Math.max(0, o - 2));
|
||||
}
|
||||
}
|
||||
|
||||
this.removeFrost();
|
||||
this.tryAddFrost();
|
||||
if (!this.level.isClientSide && this.tickCount % 40 == 0 && this.isFullyFrozen() && this.canFreeze()) {
|
||||
o = bl2 ? 5 : 1;
|
||||
this.hurt(DamageSource.FREEZE, (float) o);
|
||||
}
|
||||
|
||||
this.level.getProfiler().pop();
|
||||
this.level.getProfiler().push("push");
|
||||
if (this.autoSpinAttackTicks > 0) {
|
||||
--this.autoSpinAttackTicks;
|
||||
this.checkAutoSpinAttack(aABB, this.getBoundingBox());
|
||||
}
|
||||
|
||||
this.pushEntities();
|
||||
this.level.getProfiler().pop();
|
||||
if (!this.level.isClientSide && self.isSensitiveToWater() && this.isInWaterRainOrBubble()) {
|
||||
this.hurt(DamageSource.DROWN, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Inject(method = "travel", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isFallFlying()Z", shift = Shift.AFTER), cancellable = true)
|
||||
public void be_travel(Vec3 vec3, CallbackInfo info) {
|
||||
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (isFallFlying() && itemStack.getItem() instanceof FallFlyingItem) {
|
||||
Vec3 moveDelta = getDeltaMovement();
|
||||
if (moveDelta.y > -0.5D) {
|
||||
fallDistance = 1.0F;
|
||||
}
|
||||
|
||||
Vec3 lookAngle = getLookAngle();
|
||||
double d = 0.08D;
|
||||
float rotX = getXRot() * 0.017453292F;
|
||||
double k = Math.sqrt(lookAngle.x * lookAngle.x + lookAngle.z * lookAngle.z);
|
||||
double l = moveDelta.horizontalDistance();
|
||||
double lookLen = lookAngle.length();
|
||||
float n = Mth.cos(rotX);
|
||||
n = (float) (n * n * Math.min(1.0D, lookLen / 0.4D));
|
||||
moveDelta = getDeltaMovement().add(0.0D, d * (-1.0D + (double) n * 0.75D), 0.0D);
|
||||
double coef;
|
||||
if (moveDelta.y < 0.0D && k > 0.0D) {
|
||||
coef = moveDelta.y * -0.1D * (double) n;
|
||||
moveDelta = moveDelta.add(lookAngle.x * coef / k, coef, lookAngle.z * coef / k);
|
||||
}
|
||||
|
||||
if (rotX < 0.0F && k > 0.0D) {
|
||||
coef = l * (double) (-Mth.sin(rotX)) * 0.04D;
|
||||
moveDelta = moveDelta.add(-lookAngle.x * coef / k, coef * 3.2D, -lookAngle.z * coef / k);
|
||||
}
|
||||
|
||||
if (k > 0.0D) {
|
||||
moveDelta = moveDelta.add(
|
||||
(lookAngle.x / k * l - moveDelta.x) * 0.1D,
|
||||
0.0D,
|
||||
(lookAngle.z / k * l - moveDelta.z) * 0.1D
|
||||
);
|
||||
}
|
||||
moveDelta = moveDelta.multiply(0.9900000095367432D, 0.9800000190734863D, 0.9900000095367432D);
|
||||
double movementFactor = ((FallFlyingItem) itemStack.getItem()).getMovementFactor();
|
||||
moveDelta = moveDelta.multiply(movementFactor, 1.0D, movementFactor);
|
||||
setDeltaMovement(moveDelta);
|
||||
move(MoverType.SELF, moveDelta);
|
||||
if (!level.isClientSide) {
|
||||
if (horizontalCollision) {
|
||||
coef = moveDelta.horizontalDistance();
|
||||
double r = l - coef;
|
||||
float dmg = (float) (r * 10.0D - 3.0D);
|
||||
if (dmg > 0.0F) {
|
||||
playSound(getFallDamageSound((int) dmg), 1.0F, 1.0F);
|
||||
hurt(DamageSource.FLY_INTO_WALL, dmg);
|
||||
}
|
||||
}
|
||||
if (onGround) {
|
||||
setSharedFlag(7, false);
|
||||
}
|
||||
}
|
||||
|
||||
calculateEntityAnimation(LivingEntity.class.cast(this), this instanceof FlyingAnimal);
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private double be_getKnockback(Item tool) {
|
||||
if (tool == null) return 0.0D;
|
||||
Collection<AttributeModifier> modifiers = tool.getDefaultAttributeModifiers(EquipmentSlot.MAINHAND)
|
||||
.get(Attributes.ATTACK_KNOCKBACK);
|
||||
if (modifiers.size() > 0) {
|
||||
return modifiers.iterator().next().getAmount();
|
||||
}
|
||||
return 0.0D;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.MappedRegistry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
||||
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(MappedRegistry.class)
|
||||
public class MappedRegistryMixin<T> {
|
||||
// TODO Make this a part of BCLib (implement froze/unfroze methods)
|
||||
@Inject(method = "validateWrite", at = @At("HEAD"), cancellable = true)
|
||||
private void be_validateWrite(ResourceKey<T> resourceKey, CallbackInfo info) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.MobSpawnType;
|
||||
import net.minecraft.world.entity.monster.EnderMan;
|
||||
import net.minecraft.world.entity.monster.Monster;
|
||||
import net.minecraft.world.level.ServerLevelAccessor;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
|
||||
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.List;
|
||||
|
||||
@Mixin(Monster.class)
|
||||
public class MonsterMixin {
|
||||
@Inject(method = "checkMonsterSpawnRules", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void be_checkMonsterSpawnRules(EntityType<? extends Monster> type,
|
||||
ServerLevelAccessor serverWorldAccess,
|
||||
MobSpawnType spawnReason,
|
||||
BlockPos pos,
|
||||
RandomSource random,
|
||||
CallbackInfoReturnable<Boolean> info) {
|
||||
boolean canSpawn = info.getReturnValue();
|
||||
if (canSpawn && spawnReason == MobSpawnType.NATURAL && type == EntityType.ENDERMAN) {
|
||||
AABB box = new AABB(pos).inflate(16);
|
||||
List<EnderMan> entities = serverWorldAccess.getEntitiesOfClass(EnderMan.class, box, (entity) -> {
|
||||
return true;
|
||||
});
|
||||
info.setReturnValue(entities.size() < 6);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(NoiseBasedChunkGenerator.class)
|
||||
public interface NoiseBasedChunkGeneratorAccessor {
|
||||
@Accessor("settings")
|
||||
Holder<NoiseGeneratorSettings> be_getSettings();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.world.level.levelgen.NoiseChunk;
|
||||
import net.minecraft.world.level.levelgen.NoiseSettings;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(NoiseChunk.class)
|
||||
public interface NoiseChunkAccessor {
|
||||
@Accessor("noiseSettings")
|
||||
NoiseSettings bnv_getNoiseSettings();
|
||||
|
||||
@Accessor("cellCountXZ")
|
||||
int bnv_getCellCountXZ();
|
||||
|
||||
@Accessor("cellCountY")
|
||||
int bnv_getCellCountY();
|
||||
|
||||
@Accessor("firstCellZ")
|
||||
int bnv_getFirstCellZ();
|
||||
|
||||
@Accessor("cellNoiseMinY")
|
||||
int bnv_getCellNoiseMinY();
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.world.level.levelgen.*;
|
||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||
|
||||
import org.betterx.bclib.BCLib;
|
||||
import org.betterx.betterend.interfaces.BETargetChecker;
|
||||
import org.betterx.betterend.world.generator.TerrainGenerator;
|
||||
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.List;
|
||||
|
||||
@Mixin(NoiseChunk.class)
|
||||
public class NoiseChunkMixin implements BETargetChecker {
|
||||
private boolean be_isEndGenerator;
|
||||
|
||||
@Inject(method = "<init>*", at = @At("TAIL"))
|
||||
private void be_onNoiseChunkInit(int i,
|
||||
RandomState randomState,
|
||||
int j,
|
||||
int k,
|
||||
NoiseSettings noiseSettings,
|
||||
DensityFunctions.BeardifierOrMarker beardifierOrMarker,
|
||||
NoiseGeneratorSettings noiseGeneratorSettings,
|
||||
Aquifer.FluidPicker fluidPicker,
|
||||
Blender blender,
|
||||
CallbackInfo ci) {
|
||||
var o = BETargetChecker.class.cast(noiseGeneratorSettings);
|
||||
if (o != null) be_isEndGenerator = o.be_isTarget();
|
||||
else BCLib.LOGGER.warning(noiseGeneratorSettings + " has unknown implementation.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean be_isTarget() {
|
||||
return be_isEndGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void be_setTarget(boolean target) {
|
||||
be_isEndGenerator = target;
|
||||
}
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private List<NoiseChunk.NoiseInterpolator> interpolators;
|
||||
|
||||
@Inject(method = "fillSlice", at = @At("HEAD"), cancellable = true)
|
||||
private void be_fillSlice(boolean primarySlice, int x, CallbackInfo info) {
|
||||
if (!be_isTarget()) return;
|
||||
|
||||
info.cancel();
|
||||
|
||||
NoiseChunkAccessor accessor = (NoiseChunkAccessor) this;
|
||||
NoiseSettings noiseSettings = accessor.bnv_getNoiseSettings();
|
||||
|
||||
final int sizeY = noiseSettings.getCellHeight();
|
||||
final int sizeXZ = noiseSettings.getCellWidth();
|
||||
final int cellSizeXZ = accessor.bnv_getCellCountXZ() + 1;
|
||||
final int firstCellZ = accessor.bnv_getFirstCellZ();
|
||||
|
||||
x *= sizeXZ;
|
||||
for (int cellXZ = 0; cellXZ < cellSizeXZ; ++cellXZ) {
|
||||
int z = (firstCellZ + cellXZ) * sizeXZ;
|
||||
for (NoiseChunk.NoiseInterpolator noiseInterpolator : this.interpolators) {
|
||||
if (noiseInterpolator instanceof NoiseInterpolatorAccessor interpolator) {
|
||||
final double[] ds = (primarySlice
|
||||
? interpolator.be_getSlice0()
|
||||
: interpolator.be_getSlice1())[cellXZ];
|
||||
TerrainGenerator.fillTerrainDensity(ds, x, z, sizeXZ, sizeY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
|
||||
|
||||
import org.betterx.betterend.interfaces.BETargetChecker;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@Mixin(NoiseGeneratorSettings.class)
|
||||
public class NoiseGeneratorSettingsMixin implements BETargetChecker {
|
||||
private boolean be_isTargetGenerator;
|
||||
|
||||
@Override
|
||||
public boolean be_isTarget() {
|
||||
return be_isTargetGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void be_setTarget(boolean target) {
|
||||
be_isTargetGenerator = target;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.world.level.levelgen.NoiseChunk;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(NoiseChunk.NoiseInterpolator.class)
|
||||
public interface NoiseInterpolatorAccessor {
|
||||
@Accessor("slice0")
|
||||
double[][] be_getSlice0();
|
||||
|
||||
@Accessor("slice1")
|
||||
double[][] be_getSlice1();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.server.PlayerAdvancements;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import org.betterx.betterend.events.PlayerAdvancementsCallback;
|
||||
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.At.Shift;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(PlayerAdvancements.class)
|
||||
public abstract class PlayerAdvancementsMixin {
|
||||
@Shadow
|
||||
private ServerPlayer player;
|
||||
|
||||
@Inject(method = "award", at = @At(value = "INVOKE", target = "Lnet/minecraft/advancements/AdvancementRewards;grant(Lnet/minecraft/server/level/ServerPlayer;)V", shift = Shift.AFTER))
|
||||
public void be_award(Advancement advancement, String criterionName, CallbackInfoReturnable<Boolean> info) {
|
||||
PlayerAdvancementsCallback.PLAYER_ADVANCEMENT_COMPLETE.invoker()
|
||||
.onAdvancementComplete(player,
|
||||
advancement,
|
||||
criterionName
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ElytraItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import org.betterx.bclib.blocks.BlockProperties;
|
||||
import org.betterx.bclib.blocks.BlockProperties.TripleShape;
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
import org.betterx.bclib.util.MHelper;
|
||||
import org.betterx.betterend.interfaces.FallFlyingItem;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
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(value = Player.class, priority = 200)
|
||||
public abstract class PlayerMixin extends LivingEntity {
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
private static Direction[] horizontal;
|
||||
|
||||
@Inject(method = "findRespawnPositionAndUseSpawnBlock", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static void be_findRespawnPositionAndUseSpawnBlock(ServerLevel world,
|
||||
BlockPos pos,
|
||||
float f,
|
||||
boolean bl,
|
||||
boolean bl2,
|
||||
CallbackInfoReturnable<Optional<Vec3>> info) {
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
if (blockState.is(EndBlocks.RESPAWN_OBELISK)) {
|
||||
info.setReturnValue(be_obeliskRespawnPosition(world, pos, blockState));
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tryToStartFallFlying", at = @At("HEAD"), cancellable = true)
|
||||
public void be_tryToStartFlying(CallbackInfoReturnable<Boolean> info) {
|
||||
if (!onGround && !isFallFlying() && !isInWater() && !hasEffect(MobEffects.LEVITATION)) {
|
||||
ItemStack itemStack = getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (itemStack.getItem() instanceof FallFlyingItem && ElytraItem.isFlyEnabled(itemStack)) {
|
||||
setSharedFlag(7, true);
|
||||
info.setReturnValue(true);
|
||||
System.out.println("Started");
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<Vec3> be_obeliskRespawnPosition(ServerLevel world, BlockPos pos, BlockState state) {
|
||||
if (state.getValue(BlockProperties.TRIPLE_SHAPE) == TripleShape.TOP) {
|
||||
pos = pos.below(2);
|
||||
} else if (state.getValue(BlockProperties.TRIPLE_SHAPE) == TripleShape.MIDDLE) {
|
||||
pos = pos.below();
|
||||
}
|
||||
if (horizontal == null) {
|
||||
horizontal = BlocksHelper.makeHorizontal();
|
||||
}
|
||||
MHelper.shuffle(horizontal, world.getRandom());
|
||||
for (Direction dir : horizontal) {
|
||||
BlockPos p = pos.relative(dir);
|
||||
BlockState state2 = world.getBlockState(p);
|
||||
if (!state2.getMaterial().blocksMotion() && state2.getCollisionShape(world, pos).isEmpty()) {
|
||||
return Optional.of(Vec3.atLowerCornerOf(p).add(0.5, 0, 0.5));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
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.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.dimension.BuiltinDimensionTypes;
|
||||
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.storage.LevelStorageSource.LevelStorageAccess;
|
||||
import net.minecraft.world.level.storage.ServerLevelData;
|
||||
import net.minecraft.world.level.storage.WritableLevelData;
|
||||
|
||||
import org.betterx.bclib.api.biomes.BiomeAPI;
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.interfaces.BETargetChecker;
|
||||
import org.betterx.betterend.registry.EndBlocks;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
import org.betterx.betterend.world.generator.TerrainGenerator;
|
||||
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.ModifyArg;
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
private final static List<ResourceKey<DimensionType>> BE_TEST_DIMENSIONS = List.of(BuiltinDimensionTypes.OVERWORLD,
|
||||
BuiltinDimensionTypes.OVERWORLD_CAVES,
|
||||
BuiltinDimensionTypes.NETHER);
|
||||
|
||||
@ModifyArg(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/Holder;is(Lnet/minecraft/resources/ResourceKey;)Z"))
|
||||
ResourceKey<DimensionType> be_dragonFight(ResourceKey<DimensionType> resourceKey) {
|
||||
if (!GeneratorOptions.hasDragonFights()) {
|
||||
//this object would pass the test for the End-Dimension, so make sure we compare against something else to disabled the Dragon-Fight
|
||||
if (this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) return BuiltinDimensionTypes.OVERWORLD;
|
||||
}
|
||||
return resourceKey;
|
||||
}
|
||||
|
||||
@Inject(method = "<init>*", at = @At("TAIL"))
|
||||
private void be_onServerWorldInit(MinecraftServer minecraftServer,
|
||||
Executor executor,
|
||||
LevelStorageAccess levelStorageAccess,
|
||||
ServerLevelData serverLevelData,
|
||||
ResourceKey resourceKey,
|
||||
LevelStem levelStem,
|
||||
ChunkProgressListener chunkProgressListener,
|
||||
boolean bl,
|
||||
long seed,
|
||||
List list,
|
||||
boolean bl2,
|
||||
CallbackInfo ci) {
|
||||
ServerLevel level = ServerLevel.class.cast(this);
|
||||
if (level.dimension() == Level.END) {
|
||||
final ChunkGenerator chunkGenerator = levelStem.generator();
|
||||
if (chunkGenerator instanceof NoiseBasedChunkGenerator) {
|
||||
Holder<NoiseGeneratorSettings> sHolder = ((NoiseBasedChunkGeneratorAccessor) chunkGenerator)
|
||||
.be_getSettings();
|
||||
BETargetChecker.class.cast(sHolder.value()).be_setTarget(true);
|
||||
|
||||
}
|
||||
TerrainGenerator.initNoise(seed,
|
||||
chunkGenerator.getBiomeSource(),
|
||||
level.getChunkSource().randomState().sampler());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Inject(method = "makeObsidianPlatform", at = @At("HEAD"), cancellable = true)
|
||||
private static void be_createObsidianPlatform(ServerLevel serverLevel, CallbackInfo info) {
|
||||
if (!GeneratorOptions.generateObsidianPlatform()) {
|
||||
info.cancel();
|
||||
} else if (GeneratorOptions.changeSpawn()) {
|
||||
BlockPos blockPos = GeneratorOptions.getSpawn();
|
||||
int i = blockPos.getX();
|
||||
int j = blockPos.getY() - 2;
|
||||
int k = blockPos.getZ();
|
||||
BlockPos.betweenClosed(i - 2, j + 1, k - 2, i + 2, j + 3, k + 2).forEach((blockPosx) -> {
|
||||
serverLevel.setBlockAndUpdate(blockPosx, Blocks.AIR.defaultBlockState());
|
||||
});
|
||||
BlockPos.betweenClosed(i - 2, j, k - 2, i + 2, j, k + 2).forEach((blockPosx) -> {
|
||||
serverLevel.setBlockAndUpdate(blockPosx, Blocks.OBSIDIAN.defaultBlockState());
|
||||
});
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyArg(method = "tickChunk", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;setBlockAndUpdate(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)Z"))
|
||||
private BlockState be_modifyTickState(BlockPos pos, BlockState state) {
|
||||
if (state.is(Blocks.ICE)) {
|
||||
ResourceLocation biome = BiomeAPI.getBiomeID(getBiome(pos));
|
||||
if (biome.getNamespace().equals(BetterEnd.MOD_ID)) {
|
||||
state = EndBlocks.EMERALD_ICE.defaultBlockState();
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.server.players.PlayerList;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.player.ProfilePublicKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.BiomeManager;
|
||||
import net.minecraft.world.level.portal.PortalInfo;
|
||||
import net.minecraft.world.level.storage.LevelData;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import org.betterx.betterend.interfaces.TeleportingEntity;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin extends Player implements TeleportingEntity {
|
||||
@Shadow
|
||||
public ServerGamePacketListenerImpl connection;
|
||||
@Final
|
||||
@Shadow
|
||||
public ServerPlayerGameMode gameMode;
|
||||
@Final
|
||||
@Shadow
|
||||
public MinecraftServer server;
|
||||
@Shadow
|
||||
private boolean isChangingDimension;
|
||||
@Shadow
|
||||
private float lastSentHealth;
|
||||
@Shadow
|
||||
private int lastSentFood;
|
||||
@Shadow
|
||||
private int lastSentExp;
|
||||
|
||||
private BlockPos exitPos;
|
||||
private int be_teleportDelay = 0;
|
||||
|
||||
public ServerPlayerMixin(Level level,
|
||||
BlockPos blockPos,
|
||||
float f,
|
||||
GameProfile gameProfile,
|
||||
@Nullable ProfilePublicKey profilePublicKey) {
|
||||
super(level, blockPos, f, gameProfile, profilePublicKey);
|
||||
}
|
||||
|
||||
|
||||
@Inject(method = "createEndPlatform", at = @At("HEAD"), cancellable = true)
|
||||
private void be_createEndSpawnPlatform(ServerLevel world, BlockPos centerPos, CallbackInfo info) {
|
||||
if (!GeneratorOptions.generateObsidianPlatform()) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "findDimensionEntryPoint", at = @At("HEAD"), cancellable = true)
|
||||
protected void be_getTeleportTarget(ServerLevel destination, CallbackInfoReturnable<PortalInfo> info) {
|
||||
if (be_canTeleport()) {
|
||||
info.setReturnValue(new PortalInfo(
|
||||
new Vec3(exitPos.getX() + 0.5, exitPos.getY(), exitPos.getZ() + 0.5),
|
||||
getDeltaMovement(),
|
||||
getYRot(),
|
||||
getXRot()
|
||||
));
|
||||
} else if (GeneratorOptions.changeSpawn() && destination.dimension() == Level.END) {
|
||||
BlockPos spawn = GeneratorOptions.getSpawn();
|
||||
Vec3 pos = new Vec3(spawn.getX() + 0.5, spawn.getY(), spawn.getZ() + 0.5);
|
||||
info.setReturnValue(new PortalInfo(pos, Vec3.ZERO, 90.0F, 0.0F));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "changeDimension", at = @At("HEAD"), cancellable = true)
|
||||
public void be_changeDimension(ServerLevel destination, CallbackInfoReturnable<Entity> info) {
|
||||
if (be_canTeleport() && level instanceof ServerLevel) {
|
||||
isChangingDimension = true;
|
||||
ServerLevel serverWorld = getLevel();
|
||||
LevelData worldProperties = destination.getLevelData();
|
||||
ServerPlayer player = ServerPlayer.class.cast(this);
|
||||
connection.send(new ClientboundRespawnPacket(
|
||||
new Holder.Direct(destination.dimensionType()),
|
||||
destination.dimension(),
|
||||
BiomeManager.obfuscateSeed(destination.getSeed()),
|
||||
gameMode.getGameModeForPlayer(),
|
||||
gameMode.getPreviousGameModeForPlayer(),
|
||||
destination.isDebug(),
|
||||
destination.isFlat(),
|
||||
true
|
||||
));
|
||||
connection.send(new ClientboundChangeDifficultyPacket(
|
||||
worldProperties.getDifficulty(),
|
||||
worldProperties.isDifficultyLocked()
|
||||
));
|
||||
PlayerList playerManager = server.getPlayerList();
|
||||
playerManager.sendPlayerPermissionLevel(player);
|
||||
serverWorld.removePlayerImmediately(player, RemovalReason.CHANGED_DIMENSION);
|
||||
unsetRemoved();
|
||||
PortalInfo teleportTarget = findDimensionEntryPoint(destination);
|
||||
if (teleportTarget != null) {
|
||||
serverWorld.getProfiler().push("moving");
|
||||
serverWorld.getProfiler().pop();
|
||||
serverWorld.getProfiler().push("placing");
|
||||
this.level = destination;
|
||||
destination.addDuringPortalTeleport(player);
|
||||
setRot(teleportTarget.yRot, teleportTarget.xRot);
|
||||
moveTo(teleportTarget.pos.x, teleportTarget.pos.y, teleportTarget.pos.z);
|
||||
serverWorld.getProfiler().pop();
|
||||
triggerDimensionChangeTriggers(serverWorld);
|
||||
gameMode.setLevel(destination);
|
||||
connection.send(new ClientboundPlayerAbilitiesPacket(getAbilities()));
|
||||
playerManager.sendLevelInfo(player, destination);
|
||||
playerManager.sendAllPlayerInfo(player);
|
||||
|
||||
for (MobEffectInstance statusEffectInstance : getActiveEffects()) {
|
||||
connection.send(new ClientboundUpdateMobEffectPacket(getId(), statusEffectInstance));
|
||||
}
|
||||
|
||||
connection.send(new ClientboundLevelEventPacket(1032, BlockPos.ZERO, 0, false));
|
||||
lastSentExp = -1;
|
||||
lastSentHealth = -1.0F;
|
||||
lastSentFood = -1;
|
||||
}
|
||||
be_teleportDelay = 100;
|
||||
be_resetExitPos();
|
||||
info.setReturnValue(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
public void be_decreaseCooldawn(CallbackInfo info) {
|
||||
if (be_teleportDelay > 0) be_teleportDelay--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDimensionChangingDelay() {
|
||||
if (be_teleportDelay > 0) {
|
||||
return be_teleportDelay;
|
||||
}
|
||||
return super.getDimensionChangingDelay();
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public abstract ServerLevel getLevel();
|
||||
|
||||
@Shadow
|
||||
abstract void triggerDimensionChangeTriggers(ServerLevel origin);
|
||||
|
||||
@Shadow
|
||||
@Override
|
||||
protected abstract PortalInfo findDimensionEntryPoint(ServerLevel destination);
|
||||
|
||||
@Override
|
||||
public void be_setExitPos(BlockPos pos) {
|
||||
this.exitPos = pos.immutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void be_resetExitPos() {
|
||||
this.exitPos = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean be_canTeleport() {
|
||||
return this.exitPos != null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.monster.Slime;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import org.betterx.betterend.interfaces.ISlime;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(Slime.class)
|
||||
public abstract class SlimeMixin extends Entity implements ISlime {
|
||||
public SlimeMixin(EntityType<? extends Slime> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public void setSize(int size, boolean heal) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void be_setSlimeSize(int size, boolean heal) {
|
||||
setSize(size, heal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entityRemove(Entity.RemovalReason removalReason) {
|
||||
super.remove(removalReason);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.BlockPos.MutableBlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.boss.enderdragon.EndCrystal;
|
||||
import net.minecraft.world.level.ServerLevelAccessor;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.IronBarsBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.Heightmap.Types;
|
||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||
import net.minecraft.world.level.levelgen.feature.SpikeFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.configurations.SpikeConfiguration;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
||||
|
||||
import org.betterx.bclib.api.WorldDataAPI;
|
||||
import org.betterx.bclib.util.BlocksHelper;
|
||||
import org.betterx.bclib.util.StructureHelper;
|
||||
import org.betterx.betterend.BetterEnd;
|
||||
import org.betterx.betterend.world.generator.GeneratorOptions;
|
||||
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;
|
||||
|
||||
@Mixin(SpikeFeature.class)
|
||||
public class SpikeFeatureMixin {
|
||||
@Inject(method = "place", at = @At("HEAD"), cancellable = true)
|
||||
private void be_place(FeaturePlaceContext<SpikeConfiguration> featurePlaceContext,
|
||||
CallbackInfoReturnable<Boolean> info) {
|
||||
if (!GeneratorOptions.hasPillars()) {
|
||||
info.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "placeSpike", at = @At("HEAD"), cancellable = true)
|
||||
private void be_placeSpike(ServerLevelAccessor world,
|
||||
RandomSource random,
|
||||
SpikeConfiguration config,
|
||||
SpikeFeature.EndSpike spike,
|
||||
CallbackInfo info) {
|
||||
int x = spike.getCenterX();
|
||||
int z = spike.getCenterZ();
|
||||
int radius = spike.getRadius();
|
||||
int minY = 0;
|
||||
|
||||
long lx = x;
|
||||
long lz = z;
|
||||
if (lx * lx + lz * lz < 10000) {
|
||||
String pillarID = String.format("%d_%d", x, z);
|
||||
CompoundTag pillar = WorldDataAPI.getCompoundTag(BetterEnd.MOD_ID, "pillars");
|
||||
boolean haveValue = pillar.contains(pillarID);
|
||||
minY = haveValue
|
||||
? pillar.getInt(pillarID)
|
||||
: world.getChunk(x >> 4, z >> 4).getHeight(Types.WORLD_SURFACE, x & 15, z);
|
||||
if (!haveValue) {
|
||||
pillar.putInt(pillarID, minY);
|
||||
WorldDataAPI.saveFile(BetterEnd.MOD_ID);
|
||||
}
|
||||
} else {
|
||||
minY = world.getChunk(x >> 4, z >> 4).getHeight(Types.WORLD_SURFACE, x & 15, z);
|
||||
}
|
||||
|
||||
GeneratorOptions.setDirectSpikeHeight();
|
||||
int maxY = minY + spike.getHeight() - 64;
|
||||
|
||||
if (GeneratorOptions.replacePillars() && be_radiusInRange(radius)) {
|
||||
radius--;
|
||||
StructureTemplate base = StructureHelper.readStructure(BetterEnd.makeID("pillars/pillar_base_" + radius));
|
||||
StructureTemplate top = StructureHelper.readStructure(BetterEnd.makeID("pillars/pillar_top_" + radius + (
|
||||
spike
|
||||
.isGuarded()
|
||||
? "_cage"
|
||||
: "")));
|
||||
Vec3i side = base.getSize();
|
||||
BlockPos pos1 = new BlockPos(x - (side.getX() >> 1), minY - 3, z - (side.getZ() >> 1));
|
||||
minY = pos1.getY() + side.getY();
|
||||
side = top.getSize();
|
||||
BlockPos pos2 = new BlockPos(x - (side.getX() >> 1), maxY, z - (side.getZ() >> 1));
|
||||
maxY = pos2.getY();
|
||||
|
||||
StructurePlaceSettings data = new StructurePlaceSettings();
|
||||
base.placeInWorld(world, pos1, pos1, data, random, 2);
|
||||
top.placeInWorld(world, pos2, pos2, data, random, 2);
|
||||
|
||||
int r2 = radius * radius + 1;
|
||||
MutableBlockPos mut = new MutableBlockPos();
|
||||
for (int px = -radius; px <= radius; px++) {
|
||||
mut.setX(x + px);
|
||||
int x2 = px * px;
|
||||
for (int pz = -radius; pz <= radius; pz++) {
|
||||
mut.setZ(z + pz);
|
||||
int z2 = pz * pz;
|
||||
if (x2 + z2 <= r2) {
|
||||
for (int py = minY; py < maxY; py++) {
|
||||
mut.setY(py);
|
||||
if (world.getBlockState(mut).getMaterial().isReplaceable()) {
|
||||
if ((px == radius || px == -radius || pz == radius || pz == -radius) && random.nextInt(
|
||||
24) == 0) {
|
||||
BlocksHelper.setWithoutUpdate(world, mut, Blocks.CRYING_OBSIDIAN);
|
||||
} else {
|
||||
BlocksHelper.setWithoutUpdate(world, mut, Blocks.OBSIDIAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
minY -= 15;
|
||||
int r2 = radius * radius + 1;
|
||||
MutableBlockPos mut = new MutableBlockPos();
|
||||
for (int px = -radius; px <= radius; px++) {
|
||||
mut.setX(x + px);
|
||||
int x2 = px * px;
|
||||
for (int pz = -radius; pz <= radius; pz++) {
|
||||
mut.setZ(z + pz);
|
||||
int z2 = pz * pz;
|
||||
if (x2 + z2 <= r2) {
|
||||
for (int py = minY; py < maxY; py++) {
|
||||
mut.setY(py);
|
||||
if (world.getBlockState(mut).getMaterial().isReplaceable()) {
|
||||
BlocksHelper.setWithoutUpdate(world, mut, Blocks.OBSIDIAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mut.setX(x);
|
||||
mut.setZ(z);
|
||||
mut.setY(maxY);
|
||||
BlocksHelper.setWithoutUpdate(world, mut, Blocks.BEDROCK);
|
||||
|
||||
EndCrystal crystal = EntityType.END_CRYSTAL.create(world.getLevel());
|
||||
crystal.setBeamTarget(config.getCrystalBeamTarget());
|
||||
crystal.setInvulnerable(config.isCrystalInvulnerable());
|
||||
crystal.moveTo(x + 0.5D, maxY + 1, z + 0.5D, random.nextFloat() * 360.0F, 0.0F);
|
||||
world.addFreshEntity(crystal);
|
||||
|
||||
if (spike.isGuarded()) {
|
||||
for (int px = -2; px <= 2; ++px) {
|
||||
boolean bl = Mth.abs(px) == 2;
|
||||
for (int pz = -2; pz <= 2; ++pz) {
|
||||
boolean bl2 = Mth.abs(pz) == 2;
|
||||
for (int py = 0; py <= 3; ++py) {
|
||||
boolean bl3 = py == 3;
|
||||
if (bl || bl2 || bl3) {
|
||||
boolean bl4 = px == -2 || px == 2 || bl3;
|
||||
boolean bl5 = pz == -2 || pz == 2 || bl3;
|
||||
BlockState blockState = Blocks.IRON_BARS
|
||||
.defaultBlockState()
|
||||
.setValue(IronBarsBlock.NORTH, bl4 && pz != -2).setValue(
|
||||
IronBarsBlock.SOUTH,
|
||||
bl4 && pz != 2
|
||||
).setValue(
|
||||
IronBarsBlock.WEST,
|
||||
bl5 && px != -2).setValue(
|
||||
IronBarsBlock.EAST,
|
||||
bl5 && px != 2
|
||||
);
|
||||
BlocksHelper.setWithoutUpdate(
|
||||
world,
|
||||
mut.set(spike.getCenterX() + px, maxY + py, spike.getCenterZ() + pz),
|
||||
blockState
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info.cancel();
|
||||
}
|
||||
|
||||
private boolean be_radiusInRange(int radius) {
|
||||
return radius > 1 && radius < 6;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package org.betterx.betterend.mixin.common;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
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) {
|
||||
ChunkPos cPos = center.getPos();
|
||||
int x = blockPos.getX() >> 4;
|
||||
int z = blockPos.getZ() >> 4;
|
||||
WorldGenRegion region = (WorldGenRegion) (Object) this;
|
||||
info.setReturnValue(Math.abs(x - cPos.x) < 2 && Math.abs(z - cPos.z) < 2);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue