Merge branch 'master' into experimental

This commit is contained in:
Aleksey 2021-05-16 12:13:28 +03:00
commit f2e2132bb0
94 changed files with 1078 additions and 270 deletions

View file

@ -8,7 +8,7 @@
loader_version=0.11.3
# Mod Properties
mod_version = 0.9.4-pre
mod_version = 0.9.7-pre
maven_group = ru.betterend
archives_base_name = better-end

0
gradlew vendored Normal file → Executable file
View file

View file

@ -39,6 +39,8 @@ import ru.betterend.world.surface.SurfaceBuilders;
public class BetterEnd implements ModInitializer {
public static final String MOD_ID = "betterend";
public static final Logger LOGGER = Logger.get();
private static boolean hasHydrogen;
@Override
public void onInitialize() {
EndPortals.loadPortals();
@ -70,6 +72,7 @@ public class BetterEnd implements ModInitializer {
if (hasGuideBook()) {
GuideBookItem.register();
}
hasHydrogen = FabricLoader.getInstance().isModLoaded("hydrogen");
FabricLoader.getInstance().getEntrypoints("betterend", BetterEndPlugin.class).forEach(BetterEndPlugin::register);
Configs.saveConfigs();
@ -88,6 +91,10 @@ public class BetterEnd implements ModInitializer {
return FabricLoader.getInstance().isModLoaded("patchouli");
}
public static boolean hasHydrogen() {
return hasHydrogen;
}
public static ResourceLocation makeID(String path) {
return new ResourceLocation(MOD_ID, path);
}

View file

@ -0,0 +1,25 @@
package ru.betterend.blocks;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import ru.betterend.blocks.basis.FeatureSaplingBlock;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndFeatures;
public class LucerniaSaplingBlock extends FeatureSaplingBlock {
public LucerniaSaplingBlock() {
super();
}
@Override
protected Feature<?> getFeature() {
return EndFeatures.LUCERNIA.getFeature();
}
@Override
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
return world.getBlockState(pos.below()).is(EndBlocks.RUTISCUS);
}
}

View file

@ -27,6 +27,7 @@ public class TenaneaFlowersBlock extends VineBlock implements IColorProvider {
@Override
public BlockColor getProvider() {
return (state, world, pos, tintIndex) -> {
if (pos == null) pos = BlockPos.ZERO;
long i = (MHelper.getRandom(pos.getX(), pos.getZ()) & 63) + pos.getY();
double delta = i * 0.1;
int index = MHelper.floor(delta);

View file

@ -15,11 +15,11 @@ public class TenaneaSaplingBlock extends FeatureSaplingBlock {
@Override
protected Feature<?> getFeature() {
return EndFeatures.LUCERNIA.getFeature();
return EndFeatures.TENANEA.getFeature();
}
@Override
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
return world.getBlockState(pos.below()).is(EndBlocks.RUTISCUS);
return world.getBlockState(pos.below()).is(EndBlocks.PINK_MOSS);
}
}

View file

@ -1,6 +1,8 @@
package ru.betterend.blocks.basis;
import java.io.Reader;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
@ -9,29 +11,32 @@ import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
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.BonemealableBlock;
import net.minecraft.world.level.block.SaplingBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import ru.betterend.client.render.ERenderLayer;
import ru.betterend.interfaces.IRenderTypeable;
import ru.betterend.patterns.BlockPatterned;
import ru.betterend.patterns.Patterns;
import ru.betterend.registry.EndTags;
public abstract class FeatureSaplingBlock extends BlockBaseNotFull implements BonemealableBlock, IRenderTypeable {
public abstract class FeatureSaplingBlock extends SaplingBlock implements IRenderTypeable, BlockPatterned {
private static final VoxelShape SHAPE = Block.box(4, 0, 4, 12, 14, 12);
public FeatureSaplingBlock() {
super(FabricBlockSettings.of(Material.PLANT)
super(null, FabricBlockSettings.of(Material.PLANT)
.breakByHand(true)
.collidable(false)
.instabreak()
@ -40,7 +45,7 @@ public abstract class FeatureSaplingBlock extends BlockBaseNotFull implements Bo
}
public FeatureSaplingBlock(int light) {
super(FabricBlockSettings.of(Material.PLANT)
super(null, FabricBlockSettings.of(Material.PLANT)
.breakByHand(true)
.collidable(false)
.luminance(light)
@ -51,6 +56,11 @@ public abstract class FeatureSaplingBlock extends BlockBaseNotFull implements Bo
protected abstract Feature<?> getFeature();
@Override
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
return Collections.singletonList(new ItemStack(this));
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter view, BlockPos pos, CollisionContext ePos) {
return SHAPE;
@ -69,21 +79,21 @@ public abstract class FeatureSaplingBlock extends BlockBaseNotFull implements Bo
return state;
}
@Override
public boolean isValidBonemealTarget(BlockGetter world, BlockPos pos, BlockState state, boolean isClient) {
return true;
}
@Override
public boolean isBonemealSuccess(Level world, Random random, BlockPos pos, BlockState state) {
return random.nextInt(16) == 0;
}
@Override
public void performBonemeal(ServerLevel world, Random random, BlockPos pos, BlockState state) {
public void advanceTree(ServerLevel world, BlockPos pos, BlockState blockState, Random random) {
getFeature().place(world, world.getChunkSource().getGenerator(), random, pos, null);
}
@Override
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
this.tick(state, world, pos, random);
}
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, Random random) {
super.tick(state, world, pos, random);

View file

@ -49,7 +49,7 @@ public class MetalMaterial {
public final Block block;
public final Block tile;
public final Block bars;
public final Block plate;
public final Block pressurePlate;
public final Block door;
public final Block trapdoor;
public final Block anvil;
@ -78,6 +78,7 @@ public class MetalMaterial {
public final Item hoe;
public final Item hammer;
public final Item forgedPlate;
public final Item helmet;
public final Item chestplate;
public final Item leggings;
@ -113,7 +114,7 @@ public class MetalMaterial {
anvil = EndBlocks.registerBlock(name + "_anvil", new EndAnvilBlock(block.defaultMaterialColor(), level));
bars = EndBlocks.registerBlock(name + "_bars", new EndMetalPaneBlock(block));
chain = EndBlocks.registerBlock(name + "_chain", new EndChainBlock(block.defaultMaterialColor()));
plate = EndBlocks.registerBlock(name + "_plate", new EndWoodenPlateBlock(block));
pressurePlate = EndBlocks.registerBlock(name + "_plate", new EndWoodenPlateBlock(block));
chandelier = EndBlocks.registerBlock(name + "_chandelier", new ChandelierBlock(block));
bulb_lantern = EndBlocks.registerBlock(name + "_bulb_lantern", new BulbVineLanternBlock(lanternProperties));
@ -136,6 +137,7 @@ public class MetalMaterial {
hoe = EndItems.registerTool(name + "_hoe", new EndHoeItem(material, -3, 0.0F, itemSettings));
hammer = EndItems.registerTool(name + "_hammer", new EndHammerItem(material, 5.0F, -3.2F, 0.3D, itemSettings));
forgedPlate = EndItems.registerItem(name + "_forged_plate");
helmet = EndItems.registerItem(name + "_helmet", new EndArmorItem(armor, EquipmentSlot.HEAD, itemSettings));
chestplate = EndItems.registerItem(name + "_chestplate", new EndArmorItem(armor, EquipmentSlot.CHEST, itemSettings));
leggings = EndItems.registerItem(name + "_leggings", new EndArmorItem(armor, EquipmentSlot.LEGS, itemSettings));
@ -148,13 +150,14 @@ public class MetalMaterial {
// Basic recipes
GridRecipe.make(name + "_ingot_from_nuggets", ingot).setShape("###", "###", "###").addMaterial('#', nugget).setGroup("end_metal_ingots_nug").build();
GridRecipe.make(name + "_nuggets_from_ingot", nugget).setOutputCount(9).setList("#").addMaterial('#', ingot).setGroup("end_metal_nuggets_ing").build();
GridRecipe.make(name + "_block", block).setShape("###", "###", "###").addMaterial('#', ingot).setGroup("end_metal_blocks").build();
GridRecipe.make(name + "_ingot_from_block", ingot).setOutputCount(9).setList("#").addMaterial('#', block).setGroup("end_metal_ingots").build();
// Block recipes
GridRecipe.make(name + "_tile", tile).setOutputCount(4).setShape("##", "##").addMaterial('#', block).setGroup("end_metal_tiles").build();
GridRecipe.make(name + "_bars", bars).setOutputCount(16).setShape("###", "###").addMaterial('#', ingot).setGroup("end_metal_bars").build();
GridRecipe.make(name + "_plate", plate).setShape("##").addMaterial('#', ingot).setGroup("end_metal_plates").build();
GridRecipe.make(name + "_pressure_plate", pressurePlate).setShape("##").addMaterial('#', ingot).setGroup("end_metal_plates").build();
GridRecipe.make(name + "_door", door).setOutputCount(3).setShape("##", "##", "##").addMaterial('#', ingot).setGroup("end_metal_doors").build();
GridRecipe.make(name + "_trapdoor", trapdoor).setShape("##", "##").addMaterial('#', ingot).setGroup("end_metal_trapdoors").build();
GridRecipe.make(name + "_stairs", stairs).setOutputCount(4).setShape("# ", "## ", "###").addMaterial('#', block, tile).setGroup("end_metal_stairs").build();
@ -182,6 +185,7 @@ public class MetalMaterial {
AnvilRecipe.Builder.create(name + "_axe_head").setInput(ingot).setInputCount(3).setOutput(axeHead).setAnvilLevel(level).setToolLevel(level).setDamage(level).build();
AnvilRecipe.Builder.create(name + "_hoe_head").setInput(ingot).setInputCount(2).setOutput(hoeHead).setAnvilLevel(level).setToolLevel(level).setDamage(level).build();
AnvilRecipe.Builder.create(name + "_sword_blade").setInput(ingot).setOutput(swordBlade).setAnvilLevel(level).setToolLevel(level).setDamage(level).build();
AnvilRecipe.Builder.create(name + "_forged_plate").setInput(ingot).setOutput(forgedPlate).setAnvilLevel(level).setToolLevel(level).setDamage(level).build();
// Tools from parts
SmithingTableRecipe.create(name + "_hammer").setResult(hammer).setBase(block).setAddition(Items.STICK).build();
@ -193,10 +197,10 @@ public class MetalMaterial {
SmithingTableRecipe.create(name + "_shovel").setResult(shovel).setBase(shovelHead).setAddition(Items.STICK).build();
// Armor crafting
GridRecipe.make(name + "_helmet", helmet).setShape("###", "# #").addMaterial('#', ingot).setGroup("end_metal_helmets").build();
GridRecipe.make(name + "_chestplate", chestplate).setShape("# #", "###", "###").addMaterial('#', ingot).setGroup("end_metal_chestplates").build();
GridRecipe.make(name + "_leggings", leggings).setShape("###", "# #", "# #").addMaterial('#', ingot).setGroup("end_metal_leggings").build();
GridRecipe.make(name + "_boots", boots).setShape("# #", "# #").addMaterial('#', ingot).setGroup("end_metal_boots").build();
GridRecipe.make(name + "_helmet", helmet).setShape("###", "# #").addMaterial('#', forgedPlate).setGroup("end_metal_helmets").build();
GridRecipe.make(name + "_chestplate", chestplate).setShape("# #", "###", "###").addMaterial('#', forgedPlate).setGroup("end_metal_chestplates").build();
GridRecipe.make(name + "_leggings", leggings).setShape("###", "# #", "# #").addMaterial('#', forgedPlate).setGroup("end_metal_leggings").build();
GridRecipe.make(name + "_boots", boots).setShape("# #", "# #").addMaterial('#', forgedPlate).setGroup("end_metal_boots").build();
TagHelper.addTag(BlockTags.ANVIL, anvil);
TagHelper.addTag(BlockTags.BEACON_BASE_BLOCKS, block);

View file

@ -7,6 +7,8 @@ import net.minecraft.core.Registry;
import ru.betterend.BetterEnd;
import ru.betterend.client.render.ERenderLayer;
import ru.betterend.interfaces.IRenderTypeable;
import ru.betterend.interfaces.MultiModelItem;
import ru.betterend.item.CrystaliteArmor;
import ru.betterend.registry.EndBlockEntityRenders;
import ru.betterend.registry.EndEntitiesRenders;
import ru.betterend.registry.EndModelProviders;
@ -23,6 +25,8 @@ public class BetterEndClient implements ClientModInitializer {
EndParticles.register();
EndEntitiesRenders.register();
EndModelProviders.register();
MultiModelItem.register();
CrystaliteArmor.registerTooltips();
ClientOptions.init();
if (BetterEnd.isDevEnvironment()) {

View file

@ -16,7 +16,7 @@ public class EndPotions {
public final static Potion LONG_END_VEIL = registerPotion("long_end_veil", EndStatusEffects.END_VEIL, 9600);
public static Potion registerPotion(String name, MobEffect effect, int duration) {
return registerPotion(name, new Potion(name, new MobEffectInstance[]{ new MobEffectInstance(effect, duration) }));
return registerPotion(name, new Potion(name, new MobEffectInstance(effect, duration)));
}
public static Potion registerPotion(String name, Potion potion) {

View file

@ -2,10 +2,15 @@ package ru.betterend.effects;
import net.minecraft.core.Registry;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import ru.betterend.BetterEnd;
import ru.betterend.effects.status.EndVeilEffect;
public class EndStatusEffects {
public final static MobEffectInstance CRYSTALITE_HEALTH_REGEN = new MobEffectInstance(MobEffects.REGENERATION, 40, 0, true, false, true);
public final static MobEffectInstance CRYSTALITE_DIG_SPEED = new MobEffectInstance(MobEffects.DIG_SPEED, 40, 0, true, false, true);
public final static MobEffectInstance CRYSTALITE_MOVE_SPEED = new MobEffectInstance(MobEffects.MOVEMENT_SPEED, 40, 0, true, false, true);
public final static MobEffect END_VEIL = registerEffect("end_veil", new EndVeilEffect());

View file

@ -7,7 +7,6 @@ import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
@ -25,6 +24,7 @@ import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.ai.util.RandomPos;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.animal.FlyingAnimal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.ServerLevelAccessor;
@ -57,8 +57,8 @@ public class DragonflyEntity extends Animal implements FlyingAnimal {
}
@Override
public Entity getLeashHolder() {
return null;
public boolean canBeLeashed(Player player) {
return false;
}
@Override

View file

@ -17,7 +17,6 @@ import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
@ -36,6 +35,7 @@ import net.minecraft.world.entity.ai.util.RandomPos;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.animal.FlyingAnimal;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.Level;
@ -82,8 +82,8 @@ public class SilkMothEntity extends Animal implements FlyingAnimal {
}
@Override
public Entity getLeashHolder() {
return null;
public boolean canBeLeashed(Player player) {
return false;
}
@Override

View file

@ -17,9 +17,38 @@ public class NourishIntegration extends ModIntegration {
Tag.Named<Item> protein = getItemTag("protein");
Tag.Named<Item> sweets = getItemTag("sweets");
TagHelper.addTag(fats, EndItems.END_FISH_RAW, EndItems.END_FISH_COOKED);
TagHelper.addTag(fruit, EndItems.SHADOW_BERRY_RAW, EndItems.SHADOW_BERRY_COOKED, EndItems.BLOSSOM_BERRY, EndItems.SHADOW_BERRY_JELLY, EndItems.SWEET_BERRY_JELLY);
TagHelper.addTag(protein, EndItems.END_FISH_RAW, EndItems.END_FISH_COOKED);
TagHelper.addTag(sweets, EndItems.SHADOW_BERRY_JELLY, EndItems.SWEET_BERRY_JELLY);
TagHelper.addTag(
fats,
EndItems.END_FISH_RAW,
EndItems.END_FISH_COOKED
);
TagHelper.addTag(
fruit,
EndItems.SHADOW_BERRY_RAW,
EndItems.SHADOW_BERRY_COOKED,
EndItems.BLOSSOM_BERRY,
EndItems.SHADOW_BERRY_JELLY,
EndItems.SWEET_BERRY_JELLY,
EndItems.BLOSSOM_BERRY_JELLY,
EndItems.AMBER_ROOT_RAW,
EndItems.CHORUS_MUSHROOM_RAW,
EndItems.CHORUS_MUSHROOM_COOKED,
EndItems.BOLUX_MUSHROOM_COOKED
);
TagHelper.addTag(
protein,
EndItems.END_FISH_RAW,
EndItems.END_FISH_COOKED,
EndItems.CHORUS_MUSHROOM_COOKED,
EndItems.BOLUX_MUSHROOM_COOKED,
EndItems.CAVE_PUMPKIN_PIE
);
TagHelper.addTag(
sweets,
EndItems.SHADOW_BERRY_JELLY,
EndItems.SWEET_BERRY_JELLY,
EndItems.BLOSSOM_BERRY_JELLY,
EndItems.CAVE_PUMPKIN_PIE
);
}
}

View file

@ -1,5 +0,0 @@
package ru.betterend.interfaces;
public interface BreakableItem {
void registerBrokenItem();
}

View file

@ -0,0 +1,7 @@
package ru.betterend.interfaces;
import net.minecraft.world.entity.LivingEntity;
public interface MobEffectApplier {
void applyEffect(LivingEntity owner);
}

View file

@ -0,0 +1,18 @@
package ru.betterend.interfaces;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import ru.betterend.registry.EndItems;
public interface MultiModelItem {
@Environment(EnvType.CLIENT)
void registerModelPredicate();
static void register() {
EndItems.getModItems().forEach(item -> {
if (item instanceof MultiModelItem) {
((MultiModelItem) item).registerModelPredicate();
}
});
}
}

View file

@ -2,18 +2,14 @@ package ru.betterend.item;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.item.*;
import ru.betterend.BetterEnd;
import ru.betterend.interfaces.BreakableItem;
import ru.betterend.patterns.ModelProvider;
import ru.betterend.patterns.Patterns;
import ru.betterend.interfaces.MultiModelItem;
import ru.betterend.registry.EndItems;
import java.util.UUID;

View file

@ -0,0 +1,75 @@
package ru.betterend.item;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Style;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import ru.betterend.effects.EndStatusEffects;
import ru.betterend.item.material.EndArmorMaterial;
import ru.betterend.registry.EndItems;
public class CrystaliteArmor extends EndArmorItem {
protected final static TranslatableComponent CHEST_DESC;
protected final static TranslatableComponent BOOTS_DESC;
public CrystaliteArmor(EquipmentSlot equipmentSlot, Properties settings) {
super(EndArmorMaterial.CRYSTALITE, equipmentSlot, settings);
}
public static boolean hasFullSet(LivingEntity owner) {
for (ItemStack armorStack : owner.getArmorSlots()) {
if (!(armorStack.getItem() instanceof CrystaliteArmor)) {
return false;
}
}
return true;
}
public static void applySetEffect(LivingEntity owner) {
owner.addEffect(new MobEffectInstance(EndStatusEffects.CRYSTALITE_HEALTH_REGEN));
}
@Environment(EnvType.CLIENT)
public static void registerTooltips() {
ItemTooltipCallback.EVENT.register((stack, context, lines) -> {
if (stack.getItem() instanceof CrystaliteArmor) {
boolean hasSet = false;
Player owner = Minecraft.getInstance().player;
if (owner != null) {
hasSet = hasFullSet(owner);
}
TranslatableComponent setDesc = new TranslatableComponent("tooltip.armor.crystalite_set");
setDesc.setStyle(Style.EMPTY.applyFormats(hasSet ? ChatFormatting.BLUE : ChatFormatting.DARK_GRAY, ChatFormatting.ITALIC));
lines.add(TextComponent.EMPTY);
lines.add(setDesc);
if (stack.getItem() == EndItems.CRYSTALITE_CHESTPLATE) {
lines.add(1, TextComponent.EMPTY);
lines.add(2, CHEST_DESC);
} else if (stack.getItem() == EndItems.CRYSTALITE_BOOTS) {
lines.add(1, TextComponent.EMPTY);
lines.add(2, BOOTS_DESC);
}
}
});
}
static {
Style descStyle = Style.EMPTY.applyFormats(ChatFormatting.DARK_AQUA, ChatFormatting.ITALIC);
CHEST_DESC = new TranslatableComponent("tooltip.armor.crystalite_chest");
CHEST_DESC.setStyle(descStyle);
BOOTS_DESC = new TranslatableComponent("tooltip.armor.crystalite_boots");
BOOTS_DESC.setStyle(descStyle);
}
}

View file

@ -0,0 +1,21 @@
package ru.betterend.item;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Rarity;
import ru.betterend.effects.EndStatusEffects;
import ru.betterend.interfaces.MobEffectApplier;
import ru.betterend.registry.EndItems;
public class CrystaliteBoots extends CrystaliteArmor implements MobEffectApplier {
public CrystaliteBoots() {
super(EquipmentSlot.FEET, EndItems.makeItemSettings().rarity(Rarity.RARE));
}
@Override
public void applyEffect(LivingEntity owner) {
owner.addEffect(new MobEffectInstance(EndStatusEffects.CRYSTALITE_MOVE_SPEED));
}
}

View file

@ -0,0 +1,21 @@
package ru.betterend.item;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.Rarity;
import ru.betterend.effects.EndStatusEffects;
import ru.betterend.interfaces.MobEffectApplier;
import ru.betterend.registry.EndItems;
public class CrystaliteChestplate extends CrystaliteArmor implements MobEffectApplier {
public CrystaliteChestplate() {
super(EquipmentSlot.CHEST, EndItems.makeItemSettings().rarity(Rarity.RARE));
}
@Override
public void applyEffect(LivingEntity owner) {
owner.addEffect(new MobEffectInstance(EndStatusEffects.CRYSTALITE_DIG_SPEED));
}
}

View file

@ -0,0 +1,18 @@
package ru.betterend.item;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.item.Rarity;
import ru.betterend.registry.EndAttributes;
import ru.betterend.registry.EndItems;
import java.util.UUID;
public class CrystaliteHelmet extends CrystaliteArmor {
public CrystaliteHelmet() {
super(EquipmentSlot.HEAD, EndItems.makeItemSettings().rarity(Rarity.RARE));
UUID uuid = ARMOR_MODIFIER_UUID_PER_SLOT[EquipmentSlot.HEAD.getIndex()];
addAttributeModifier(EndAttributes.BLINDNESS_RESISTANCE, new AttributeModifier(uuid, "Helmet blindness resistance", 1.0, AttributeModifier.Operation.ADDITION));
}
}

View file

@ -0,0 +1,18 @@
package ru.betterend.item;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.item.Rarity;
import ru.betterend.registry.EndItems;
import java.util.UUID;
public class CrystaliteLeggings extends CrystaliteArmor {
public CrystaliteLeggings() {
super(EquipmentSlot.LEGS, EndItems.makeItemSettings().rarity(Rarity.RARE));
UUID uuid = ARMOR_MODIFIER_UUID_PER_SLOT[EquipmentSlot.LEGS.getIndex()];
addAttributeModifier(Attributes.MAX_HEALTH, new AttributeModifier(uuid, "Armor health boost", 4.0, AttributeModifier.Operation.ADDITION));
}
}

View file

@ -1,25 +1,19 @@
package ru.betterend.item;
import java.util.UUID;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.Item;
import ru.betterend.mixin.common.ArmorItemAccessor;
import ru.betterend.patterns.ModelProvider;
import ru.betterend.patterns.Patterned;
import ru.betterend.patterns.Patterns;
public class EndArmorItem extends ArmorItem implements ModelProvider {
import java.util.UUID;
public class EndArmorItem extends ArmorItem implements Patterned {
protected static final UUID[] ARMOR_MODIFIER_UUID_PER_SLOT = new UUID[] {
UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"),
@ -54,7 +48,7 @@ public class EndArmorItem extends ArmorItem implements ModelProvider {
}
@Override
public String getModelString(String name) {
public String getModelPattern(String name) {
return Patterns.createItemGenerated(name);
}
}

View file

@ -0,0 +1,10 @@
package ru.betterend.item;
import net.minecraft.world.entity.ai.attributes.Attribute;
public class EndAttribute extends Attribute {
public EndAttribute(String description, double value) {
super(description, value);
}
}

View file

@ -1,18 +1,19 @@
package ru.betterend.item;
import net.minecraft.world.item.BucketItem;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.FishBucketItem;
import net.minecraft.world.level.material.Fluids;
import ru.betterend.patterns.ModelProvider;
import ru.betterend.patterns.Patterned;
import ru.betterend.patterns.Patterns;
import ru.betterend.registry.EndItems;
public class EndBucketItem extends BucketItem implements ModelProvider {
public EndBucketItem() {
super(Fluids.WATER, EndItems.makeItemSettings().stacksTo(1));
public class EndBucketItem extends FishBucketItem implements Patterned {
public EndBucketItem(EntityType<?> type) {
super(type, Fluids.WATER, EndItems.makeItemSettings().stacksTo(1));
}
@Override
public String getModelString(String name) {
public String getModelPattern(String name) {
return Patterns.createJson(Patterns.ITEM_GENERATED, name);
}
}

View file

@ -0,0 +1,26 @@
package ru.betterend.mixin.client;
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 net.minecraft.client.model.ArmorStandArmorModel;
import net.minecraft.client.renderer.entity.ArmorStandRenderer;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.world.entity.decoration.ArmorStand;
import ru.betterend.client.render.ArmoredElytraLayer;
@Mixin(ArmorStandRenderer.class)
public abstract class ArmorStandRendererMixin extends LivingEntityRenderer<ArmorStand, ArmorStandArmorModel> {
public ArmorStandRendererMixin(EntityRenderDispatcher entityRenderDispatcher, ArmorStandArmorModel entityModel, float f) {
super(entityRenderDispatcher, entityModel, f);
}
@Inject(method = "<init>*", at = @At("TAIL"))
public void be_addCustomLayer(EntityRenderDispatcher entityRenderDispatcher, CallbackInfo info) {
addLayer(new ArmoredElytraLayer<>(this));
}
}

View file

@ -0,0 +1,26 @@
package ru.betterend.mixin.client;
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 net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.HumanoidMobRenderer;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.world.entity.Mob;
import ru.betterend.client.render.ArmoredElytraLayer;
@Mixin(HumanoidMobRenderer.class)
public abstract class HumanoidMobRendererMixin<T extends Mob, M extends HumanoidModel<T>> extends MobRenderer<T, M> {
public HumanoidMobRendererMixin(EntityRenderDispatcher entityRenderDispatcher, M entityModel, float f) {
super(entityRenderDispatcher, entityModel, f);
}
@Inject(method = "<init>*", at = @At("TAIL"))
public void be_addCustomLayer(EntityRenderDispatcher entityRenderDispatcher, M humanoidModel, float f, float g, float h, float i, CallbackInfo info) {
addLayer(new ArmoredElytraLayer<>(this));
}
}

View file

@ -21,6 +21,6 @@ public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractC
@Inject(method = "<init>(Lnet/minecraft/client/renderer/entity/EntityRenderDispatcher;Z)V", at = @At("TAIL"))
public void be_addCustomLayer(EntityRenderDispatcher entityRenderDispatcher, boolean bl, CallbackInfo info) {
addLayer(new ArmoredElytraLayer<>(PlayerRenderer.class.cast(this)));
addLayer(new ArmoredElytraLayer<>(this));
}
}

View file

@ -1,24 +0,0 @@
package ru.betterend.mixin.common;
import java.util.UUID;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import com.google.common.collect.Multimap;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.item.ArmorItem;
@Mixin(ArmorItem.class)
public interface ArmorItemAccessor {
@Accessor("ARMOR_MODIFIER_UUID_PER_SLOT")
UUID[] be_getModifiers();
@Accessor("defaultModifiers")
Multimap<Attribute, AttributeModifier> be_getDefaultModifiers();
@Accessor("defaultModifiers")
void be_setDefaultModifiers(Multimap<Attribute, AttributeModifier> attributeModifiers);
}

View file

@ -1,13 +1,17 @@
package ru.betterend.mixin.common;
import java.lang.reflect.Field;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.core.BlockPos;
import net.minecraft.util.BitStorage;
import net.minecraft.util.Mth;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
import ru.betterend.BetterEnd;
import ru.betterend.interfaces.IBiomeArray;
@Mixin(ChunkBiomeContainer.class)
@ -34,6 +38,42 @@ public class ChunkBiomeContainerMixin implements IBiomeArray {
int biomeY = pos.getY() >> 2;
int biomeZ = pos.getZ() >> 2;
int index = be_getArrayIndex(biomeX, biomeY, biomeZ);
if (BetterEnd.hasHydrogen()) {
try {
ChunkBiomeContainer self = (ChunkBiomeContainer) (Object) this;
BitStorage storage = be_getHydrogenStorage(self);
Biome[] palette = be_getHydrogenPalette(self);
int paletteIndex = be_getHydrogenPaletteIndex(biome, palette);
if (paletteIndex == -1) {
Biome[] newPalette = new Biome[palette.length + 1];
System.arraycopy(palette, 0, newPalette, 0, palette.length);
paletteIndex = palette.length;
palette = newPalette;
palette[paletteIndex] = biome;
be_setHydrogenPalette(self, palette);
}
try {
storage.set(index, paletteIndex);
}
catch (Exception e) {
int size = storage.getSize();
int bits = Mth.ceillog2(palette.length);
BitStorage newStorage = new BitStorage(bits, size);
for (int i = 0; i < size; i++) {
newStorage.set(i, storage.get(i));
}
storage = newStorage;
storage.set(index, paletteIndex);
be_setHydrogenStorage(self, storage);
}
}
catch (Exception e) {
BetterEnd.LOGGER.warning(e.getLocalizedMessage());
}
return;
}
biomes[index] = biome;
}
@ -43,4 +83,37 @@ public class ChunkBiomeContainerMixin implements IBiomeArray {
int k = biomeZ & HORIZONTAL_MASK;
return j << WIDTH_BITS + WIDTH_BITS | k << WIDTH_BITS | i;
}
private Field be_getField(String name) throws Exception {
Field field = ChunkBiomeContainer.class.getDeclaredField(name);
field.setAccessible(true);
return field;
}
private BitStorage be_getHydrogenStorage(ChunkBiomeContainer container) throws Exception {
return (BitStorage) be_getField("intArray").get(container);
}
private Biome[] be_getHydrogenPalette(ChunkBiomeContainer container) throws Exception {
return (Biome[]) be_getField("palette").get(container);
}
private int be_getHydrogenPaletteIndex(Biome biome, Biome[] palette) {
int index = -1;
for (int i = 0; i < palette.length; i++) {
if (palette[i] == biome) {
index = i;
break;
}
}
return index;
}
private void be_setHydrogenPalette(ChunkBiomeContainer container, Biome[] palette) throws Exception {
be_getField("palette").set(container, palette);
}
private void be_setHydrogenStorage(ChunkBiomeContainer container, BitStorage storage) throws Exception {
be_getField("intArray").set(container, storage);
}
}

View file

@ -0,0 +1,100 @@
package ru.betterend.mixin.common;
import java.util.List;
import org.apache.logging.log4j.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 com.google.common.collect.Lists;
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 ru.betterend.util.BlocksHelper;
import ru.betterend.world.generator.GeneratorOptions;
@Mixin(EndDragonFight.class)
public class EndDragonFightMixin {
@Shadow
private DragonRespawnAnimation respawnStage;
@Shadow
private boolean dragonKilled;
@Shadow
private BlockPos portalLocation;
@Final
@Shadow
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.");
}
blockPos = portalLocation;
}
List<EndCrystal> crystals = Lists.newArrayList();
BlockPos center = GeneratorOptions.getPortalPos().above(5);
for (Direction dir : BlocksHelper.HORIZONTAL) {
BlockPos central = center.relative(dir, 4);
List<EndCrystal> crystalList = level.getEntitiesOfClass(EndCrystal.class, new AABB(central.below(10).south().west(), central.above(10).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();
}
}
}

View file

@ -14,6 +14,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.feature.EndPodiumFeature;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
@ -40,7 +41,7 @@ public class EndPodiumFeatureMixin {
blockPos = be_updatePos(blockPos, world);
StructureTemplate structure = StructureHelper.readStructure(BetterEnd.makeID(active ? "portal/end_portal_active" : "portal/end_portal_inactive"));
BlockPos size = structure.getSize();
blockPos = blockPos.offset(-(size.getX() >> 1), -3, -(size.getZ() >> 1));
blockPos = blockPos.offset(-(size.getX() >> 1), -1, -(size.getZ() >> 1));
structure.placeInWorldChunk(world, blockPos, new StructurePlaceSettings(), random);
info.setReturnValue(true);
info.cancel();
@ -56,7 +57,7 @@ public class EndPodiumFeatureMixin {
if (GeneratorOptions.useNewGenerator()) {
BlockPos pos = GeneratorOptions.getPortalPos();
if (pos.equals(BlockPos.ZERO)) {
int y = world.getChunk(blockPos).getHeight(Types.WORLD_SURFACE, blockPos.getX(), blockPos.getZ());
int y = world.getChunk(0, 0, ChunkStatus.FULL).getHeight(Types.WORLD_SURFACE, blockPos.getX(), blockPos.getZ());
if (y < 1) {
y = 65;
}

View file

@ -0,0 +1,43 @@
package ru.betterend.mixin.common;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.levelgen.feature.SpikeFeature.EndSpike;
import ru.betterend.util.WorldDataUtil;
import ru.betterend.world.generator.GeneratorOptions;
@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 = WorldDataUtil.getCompoundTag("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;
}
}

View file

@ -1,7 +1,22 @@
package ru.betterend.mixin.common;
import java.util.Collection;
import net.minecraft.sounds.SoundEvent;
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.level.Level;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -10,26 +25,12 @@ 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 net.minecraft.sounds.SoundEvent;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
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.level.Level;
import net.minecraft.world.phys.Vec3;
import ru.betterend.interfaces.MobEffectApplier;
import ru.betterend.item.ArmoredElytra;
import ru.betterend.item.CrystaliteArmor;
import ru.betterend.registry.EndAttributes;
import java.util.Collection;
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin extends Entity {
@ -56,8 +57,38 @@ public abstract class LivingEntityMixin extends Entity {
@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) {
if (mobEffectInstance.getEffect() == MobEffects.BLINDNESS && getAttributes().getValue(EndAttributes.BLINDNESS_RESISTANCE) > 0.0) {
info.setReturnValue(false);
}
}
@Inject(method = "hurt", at = @At("HEAD"))
public void be_hurt(DamageSource source, float amount, CallbackInfoReturnable<Boolean> info) {
this.lastAttacker = source.getEntity();
@ -80,9 +111,8 @@ public abstract class LivingEntityMixin extends Entity {
if (isFlying && !onGround && !isPassenger() && !hasEffect(MobEffects.LEVITATION)) {
if (ElytraItem.isFlyEnabled(itemStack)) {
if ((fallFlyTicks + 1) % 20 == 0) {
itemStack.hurtAndBreak(1, LivingEntity.class.cast(this), (livingEntity) -> {
livingEntity.broadcastBreakEvent(EquipmentSlot.CHEST);
});
itemStack.hurtAndBreak(1, LivingEntity.class.cast(this),
livingEntity -> livingEntity.broadcastBreakEvent(EquipmentSlot.CHEST));
}
isFlying = true;
} else {

View file

@ -4,10 +4,12 @@ import java.io.File;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executor;
import java.util.function.Supplier;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@ -17,35 +19,47 @@ import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
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.CustomSpawner;
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.DimensionType;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.ServerLevelData;
import net.minecraft.world.level.storage.WritableLevelData;
import ru.betterend.BetterEnd;
import ru.betterend.registry.EndBiomes;
import ru.betterend.registry.EndBlocks;
import ru.betterend.util.DataFixerUtil;
import ru.betterend.util.WorldDataUtil;
import ru.betterend.world.generator.GeneratorOptions;
@Mixin(ServerLevel.class)
public class ServerLevelMixin {
private static final int DEV_VERSION = be_getVersionInt("63.63.63");
private static final int FIX_VERSION = DEV_VERSION;
private static String lastWorld = null;
public abstract class ServerLevelMixin extends Level {
private static final int BE_DEV_VERSION = be_getVersionInt("63.63.63");
private static final int BE_FIX_VERSION = BE_DEV_VERSION;
private static String be_lastWorld = null;
protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey<Level> resourceKey, DimensionType dimensionType, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l) {
super(writableLevelData, resourceKey, dimensionType, supplier, bl, bl2, l);
}
@Inject(method = "<init>*", at = @At("TAIL"))
private void be_onServerWorldInit(MinecraftServer server, Executor workerExecutor, LevelStorageSource.LevelStorageAccess session, ServerLevelData properties, ResourceKey<Level> registryKey, DimensionType dimensionType, ChunkProgressListener worldGenerationProgressListener, ChunkGenerator chunkGenerator, boolean debugWorld, long l, List<CustomSpawner> list, boolean bl, CallbackInfo info) {
if (lastWorld != null && lastWorld.equals(session.getLevelId())) {
if (be_lastWorld != null && be_lastWorld.equals(session.getLevelId())) {
return;
}
lastWorld = session.getLevelId();
be_lastWorld = session.getLevelId();
ServerLevel world = ServerLevel.class.cast(this);
EndBiomes.onWorldLoad(world.getSeed());
File dir = session.getDimensionPath(world.dimension());
if (!new File(dir, "level.dat").exists()) {
dir = dir.getParentFile();
@ -53,7 +67,7 @@ public class ServerLevelMixin {
File data = new File(dir, "data/betterend_data.nbt");
ModMetadata meta = FabricLoader.getInstance().getModContainer(BetterEnd.MOD_ID).get().getMetadata();
int version = BetterEnd.isDevEnvironment() ? DEV_VERSION : be_getVersionInt(meta.getVersion().toString());
int version = BetterEnd.isDevEnvironment() ? BE_DEV_VERSION : be_getVersionInt(meta.getVersion().toString());
WorldDataUtil.load(data);
CompoundTag root = WorldDataUtil.getRootTag();
@ -61,7 +75,7 @@ public class ServerLevelMixin {
GeneratorOptions.setPortalPos(NbtUtils.readBlockPos(root.getCompound("portal")));
if (dataVersion < version) {
if (version < FIX_VERSION) {
if (version < BE_FIX_VERSION) {
DataFixerUtil.fixData(data.getParentFile());
}
root.putString("version", be_getVersionString(version));
@ -79,6 +93,23 @@ public class ServerLevelMixin {
}
}
@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 = EndBiomes.getBiomeID(getBiome(pos));
if (biome.getNamespace().equals(BetterEnd.MOD_ID)) {
state = EndBlocks.EMERALD_ICE.defaultBlockState();
}
}
return state;
}
private static int be_getVersionInt(String version) {
if (version.isEmpty()) {
return 0;

View file

@ -63,6 +63,7 @@ public class SpikeFeatureMixin {
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)) {

View file

@ -63,5 +63,12 @@ public class AnvilRecipes {
.setToolLevel(4)
.setDamage(6)
.build();
AnvilRecipe.Builder.create("aeternium_forged_plate")
.setInput(EndItems.AETERNIUM_INGOT)
.setOutput(EndItems.AETERNIUM_FORGED_PLATE)
.setAnvilLevel(anvilLevel)
.setToolLevel(4)
.setDamage(6)
.build();
}
}

View file

@ -101,19 +101,27 @@ public class CraftingRecipes {
GridRecipe.make("petal_white_dye", Items.WHITE_DYE).setList("#").addMaterial('#', EndItems.HYDRALUX_PETAL).build();
GridRecipe.make("sweet_berry_jelly", EndItems.SWEET_BERRY_JELLY)
.setList("JWSB")
.addMaterial('J', EndItems.GELATINE)
.addMaterial('W', PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER))
.addMaterial('S', Items.SUGAR).addMaterial('B', Items.SWEET_BERRIES)
.build();
.setList("JWSB")
.addMaterial('J', EndItems.GELATINE)
.addMaterial('W', PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER))
.addMaterial('S', Items.SUGAR).addMaterial('B', Items.SWEET_BERRIES)
.build();
GridRecipe.make("shadow_berry_jelly", EndItems.SHADOW_BERRY_JELLY)
.setList("JWSB")
.addMaterial('J', EndItems.GELATINE)
.addMaterial('W', PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER))
.addMaterial('S', Items.SUGAR)
.addMaterial('B', EndItems.SHADOW_BERRY_COOKED)
.build();
.setList("JWSB")
.addMaterial('J', EndItems.GELATINE)
.addMaterial('W', PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER))
.addMaterial('S', Items.SUGAR)
.addMaterial('B', EndItems.SHADOW_BERRY_COOKED)
.build();
GridRecipe.make("shadow_berry_jelly", EndItems.BLOSSOM_BERRY_JELLY)
.setList("JWSB")
.addMaterial('J', EndItems.GELATINE)
.addMaterial('W', PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER))
.addMaterial('S', Items.SUGAR)
.addMaterial('B', EndItems.BLOSSOM_BERRY)
.build();
GridRecipe.make("sulphur_gunpowder", Items.GUNPOWDER).setList("SCB").addMaterial('S', EndItems.CRYSTALLINE_SULPHUR).addMaterial('C', Items.COAL, Items.CHARCOAL).addMaterial('B', Items.BONE_MEAL).build();
@ -188,11 +196,12 @@ public class CraftingRecipes {
registerHammer("diamond", Items.DIAMOND, EndItems.DIAMOND_HAMMER);
GridRecipe.make("charcoal_block", EndBlocks.CHARCOAL_BLOCK).setShape("###", "###", "###").addMaterial('#', Items.CHARCOAL).build();
GridRecipe.make("charcoal_from_block", Items.CHARCOAL).setOutputCount(9).setList("#").addMaterial('#', EndBlocks.CHARCOAL_BLOCK).build();
GridRecipe.make("end_stone_furnace", EndBlocks.END_STONE_FURNACE).setShape("###", "# #", "###").addMaterial('#', Blocks.END_STONE).build();
GridRecipe.make("filalux_lantern", EndBlocks.FILALUX_LANTERN).setShape("###", "###", "###").addMaterial('#', EndBlocks.FILALUX).build();
GridRecipe.make("silk_moth_hive", EndBlocks.SILK_MOTH_HIVE).setShape("#L#", "LML", "#L#").addMaterial('#', EndBlocks.TENANEA.planks).addMaterial('L', EndBlocks.TENANEA_LEAVES).addMaterial('M', EndItems.SILK_MOTH_MATRIX).build();
GridRecipe.make("cave_pumpkin_pie", EndItems.CAVE_PUMPKIN_PIE).setShape(" B ", "BPB", " B ").addMaterial('P', EndBlocks.CAVE_PUMPKIN).addMaterial('B', EndItems.BLOSSOM_BERRY, EndItems.SHADOW_BERRY_RAW).build();
GridRecipe.make("cave_pumpkin_pie", EndItems.CAVE_PUMPKIN_PIE).setShape("SBS", "BPB", "SBS").addMaterial('P', EndBlocks.CAVE_PUMPKIN).addMaterial('B', EndItems.BLOSSOM_BERRY, EndItems.SHADOW_BERRY_RAW).addMaterial('S', Items.SUGAR).build();
GridRecipe.make("cave_pumpkin_seeds", EndBlocks.CAVE_PUMPKIN_SEED).setOutputCount(4).setList("#").addMaterial('#', EndBlocks.CAVE_PUMPKIN).build();
GridRecipe.make("neon_cactus_block", EndBlocks.NEON_CACTUS_BLOCK).setShape("##", "##").addMaterial('#', EndBlocks.NEON_CACTUS).build();
@ -202,7 +211,7 @@ public class CraftingRecipes {
GridRecipe.make("tag_smith_table", Blocks.SMITHING_TABLE).setShape("II", "##", "##").addMaterial('#', ItemTags.PLANKS).addMaterial('I', EndTags.IRON_INGOTS).build();
GridRecipe.make("tag_cauldron", Blocks.CAULDRON).setShape("I I", "I I", "III").addMaterial('I', EndTags.IRON_INGOTS).build();
GridRecipe.make("tag_hopper", Blocks.HOPPER).setShape("I I", "ICI", " I ").addMaterial('I', EndTags.IRON_INGOTS).addMaterial('C', EndTags.ITEM_CHEST).build();
GridRecipe.make("tag_piston", Blocks.PISTON).setShape("WWW", "CIC", "CDC").addMaterial('I', EndTags.IRON_INGOTS).addMaterial('D', Items.REDSTONE).addMaterial('C', Items.COBBLESTONE).build();
GridRecipe.make("tag_piston", Blocks.PISTON).setShape("WWW", "CIC", "CDC").addMaterial('I', EndTags.IRON_INGOTS).addMaterial('D', Items.REDSTONE).addMaterial('C', Items.COBBLESTONE).addMaterial('W', ItemTags.PLANKS).build();
GridRecipe.make("tag_rail", Blocks.RAIL).setShape("I I", "ISI", "I I").addMaterial('I', EndTags.IRON_INGOTS).addMaterial('S', Items.STICK).build();
GridRecipe.make("tag_stonecutter", Blocks.STONECUTTER).setShape(" I ", "SSS").addMaterial('I', EndTags.IRON_INGOTS).addMaterial('S', Items.STONE).build();
@ -210,6 +219,8 @@ public class CraftingRecipes {
GridRecipe.make("tag_compass", Items.COMPASS).setShape(" I ", "IDI", " I ").addMaterial('I', EndTags.IRON_INGOTS).addMaterial('D', Items.REDSTONE).build();
GridRecipe.make("tag_minecart", Items.MINECART).setShape("I I", "III").addMaterial('I', EndTags.IRON_INGOTS).build();
GridRecipe.make("tag_shield", Items.SHIELD).setShape("WIW", "WWW", " W ").addMaterial('I', EndTags.IRON_INGOTS).addMaterial('W', ItemTags.PLANKS).build();
GridRecipe.make("sugar_from_root", Items.SUGAR).setList("###").addMaterial('#', EndItems.AMBER_ROOT_RAW).build();
}
private static void registerLantern(String name, Block lantern, Block slab) {

View file

@ -54,22 +54,22 @@ public class SmithingRecipes {
SmithingTableRecipe.create("aeternium_helmet")
.setResult(EndItems.AETERNIUM_HELMET)
.setBase(EndBlocks.TERMINITE.helmet)
.setAddition(EndItems.AETERNIUM_INGOT)
.setAddition(EndItems.AETERNIUM_FORGED_PLATE)
.build();
SmithingTableRecipe.create("aeternium_chestplate")
.setResult(EndItems.AETERNIUM_CHESTPLATE)
.setBase(EndBlocks.TERMINITE.chestplate)
.setAddition(EndItems.AETERNIUM_INGOT)
.setAddition(EndItems.AETERNIUM_FORGED_PLATE)
.build();
SmithingTableRecipe.create("aeternium_leggings")
.setResult(EndItems.AETERNIUM_LEGGINGS)
.setBase(EndBlocks.TERMINITE.leggings)
.setAddition(EndItems.AETERNIUM_INGOT)
.setAddition(EndItems.AETERNIUM_FORGED_PLATE)
.build();
SmithingTableRecipe.create("aeternium_boots")
.setResult(EndItems.AETERNIUM_BOOTS)
.setBase(EndBlocks.TERMINITE.boots)
.setAddition(EndItems.AETERNIUM_INGOT)
.setAddition(EndItems.AETERNIUM_FORGED_PLATE)
.build();
SmithingTableRecipe.create("thallasium_anvil_updrade")
@ -80,7 +80,7 @@ public class SmithingRecipes {
SmithingTableRecipe.create("terminite_anvil_updrade")
.setResult(EndBlocks.AETERNIUM_ANVIL)
.setBase(EndBlocks.TERMINITE.anvil)
.setAddition(EndBlocks.AETERNIUM_BLOCK)
.setAddition(EndItems.AETERNIUM_INGOT)
.build();
SmithingTableRecipe.create("armored_elytra")

View file

@ -0,0 +1,21 @@
package ru.betterend.registry;
import net.minecraft.core.Registry;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import ru.betterend.BetterEnd;
import ru.betterend.item.EndAttribute;
public class EndAttributes {
public final static Attribute BLINDNESS_RESISTANCE = registerAttribute("generic.blindness_resistance", 0.0, true);
public static Attribute registerAttribute(String name, double value, boolean syncable) {
return Registry.register(Registry.ATTRIBUTE, BetterEnd.makeID(name), new EndAttribute("attribute.name." + name, value).setSyncable(syncable));
}
public static AttributeSupplier.Builder addLivingEntityAttributes(AttributeSupplier.Builder builder) {
return builder.add(EndAttributes.BLINDNESS_RESISTANCE);
}
}

View file

@ -5,7 +5,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import com.google.common.collect.Lists;
@ -58,8 +57,10 @@ import ru.betterend.world.biome.land.PaintedMountainsBiome;
import ru.betterend.world.biome.land.ShadowForestBiome;
import ru.betterend.world.biome.land.SulphurSpringsBiome;
import ru.betterend.world.biome.land.UmbrellaJungleBiome;
import ru.betterend.world.generator.BiomeMap;
import ru.betterend.world.generator.BiomePicker;
import ru.betterend.world.generator.BiomeType;
import ru.betterend.world.generator.GeneratorOptions;
public class EndBiomes {
private static final HashMap<ResourceLocation, EndBiome> ID_MAP = Maps.newHashMap();
@ -74,6 +75,7 @@ public class EndBiomes {
private static final JsonObject EMPTY_JSON = new JsonObject();
private static Registry<Biome> biomeRegistry;
private static BiomeMap caveBiomeMap;
// Vanilla Land
public static final EndBiome END = registerBiome(Biomes.THE_END, BiomeType.LAND, 1F);
@ -118,6 +120,12 @@ public class EndBiomes {
CAVE_BIOMES.rebuild();
}
public static void onWorldLoad(long seed) {
if (caveBiomeMap == null || caveBiomeMap.getSeed() != seed) {
caveBiomeMap = new BiomeMap(seed, GeneratorOptions.getBiomeSizeCaves(), CAVE_BIOMES);
}
}
public static void mutateRegistry(Registry<Biome> biomeRegistry) {
EndBiomes.biomeRegistry = biomeRegistry;
@ -222,7 +230,7 @@ public class EndBiomes {
* @param server - {@link MinecraftServer}
*/
public static void initRegistry(MinecraftServer server) {
if (biomeRegistry == null) {
if (biomeRegistry == null || biomeRegistry == BuiltinRegistries.BIOME) {
biomeRegistry = server.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
}
}
@ -439,8 +447,8 @@ public class EndBiomes {
return biome;
}
public static EndCaveBiome getCaveBiome(Random random) {
return (EndCaveBiome) CAVE_BIOMES.getBiome(random);
public static EndCaveBiome getCaveBiome(int x, int z) {
return (EndCaveBiome) caveBiomeMap.getBiome(x, z);
}
public static boolean hasBiome(ResourceLocation biomeID) {

View file

@ -148,7 +148,7 @@ public class EndBlocks {
public static final Block JELLYSHROOM_CAP_PURPLE = registerBlock("jellyshroom_cap_purple", new JellyshroomCapBlock(217, 142, 255, 164, 0, 255));
public static final WoodenMaterial JELLYSHROOM = new WoodenMaterial("jellyshroom", MaterialColor.COLOR_PURPLE, MaterialColor.COLOR_LIGHT_BLUE);
public static final Block LUCERNIA_SAPLING = registerBlock("lucernia_sapling", new TenaneaSaplingBlock());
public static final Block LUCERNIA_SAPLING = registerBlock("lucernia_sapling", new LucerniaSaplingBlock());
public static final Block LUCERNIA_LEAVES = registerBlock("lucernia_leaves", new EndLeavesBlock(LUCERNIA_SAPLING, MaterialColor.COLOR_ORANGE));
public static final Block LUCERNIA_OUTER_LEAVES = registerBlock("lucernia_outer_leaves", new FurBlock(LUCERNIA_SAPLING, 32));
public static final WoodenMaterial LUCERNIA = new WoodenMaterial("lucernia", MaterialColor.COLOR_ORANGE, MaterialColor.COLOR_ORANGE);

View file

@ -257,7 +257,7 @@ public class EndFeatures {
addFeature(ENDER_ORE, features);
addFeature(CRASHED_SHIP, features);
if (EndBiomes.getBiome(id).hasCaves()) {
if (EndBiomes.getBiome(id).hasCaves() && !EndBiomes.VOID_BIOMES.containsImmutable(id)) {
addFeature(ROUND_CAVE, features);
addFeature(TUNEL_CAVE, features);
}

View file

@ -4,6 +4,7 @@ import java.util.List;
import com.google.common.collect.Lists;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.core.BlockSource;
import net.minecraft.core.Direction;
@ -21,7 +22,6 @@ import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.food.Foods;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Item.Properties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.Rarity;
@ -33,9 +33,7 @@ import net.minecraft.world.item.Tiers;
import net.minecraft.world.level.block.DispenserBlock;
import ru.betterend.BetterEnd;
import ru.betterend.config.Configs;
import ru.betterend.interfaces.BreakableItem;
import ru.betterend.item.*;
import ru.betterend.item.ModelProviderItem;
import ru.betterend.item.material.EndArmorMaterial;
import ru.betterend.item.material.EndToolMaterial;
import ru.betterend.item.tool.EndAxeItem;
@ -55,6 +53,7 @@ public class EndItems {
public final static Item ENDER_DUST = registerItem("ender_dust");
public final static Item ENDER_SHARD = registerItem("ender_shard");
public final static Item AETERNIUM_INGOT = registerItem("aeternium_ingot");
public final static Item AETERNIUM_FORGED_PLATE = registerItem("aeternium_forged_plate");
public final static Item END_LILY_LEAF = registerItem("end_lily_leaf");
public final static Item END_LILY_LEAF_DRIED = registerItem("end_lily_leaf_dried");
public final static Item CRYSTAL_SHARDS = registerItem("crystal_shards");
@ -73,18 +72,21 @@ public class EndItems {
public final static Item SILK_MOTH_MATRIX = registerItem("silk_moth_matrix");
// Music Discs
public final static Item MUSIC_DISC_STRANGE_AND_ALIEN = registerDisc("music_disc_strange_and_alien", 0, EndSounds.STRANGE_AND_ALIEN);
public final static Item MUSIC_DISC_STRANGE_AND_ALIEN = registerDisc("music_disc_strange_and_alien", 0, EndSounds.RECORD_STRANGE_AND_ALIEN);
public final static Item MUSIC_DISC_GRASPING_AT_STARS = registerDisc("music_disc_grasping_at_stars", 0, EndSounds.RECORD_GRASPING_AT_STARS);
public final static Item MUSIC_DISC_ENDSEEKER = registerDisc("music_disc_endseeker", 0, EndSounds.RECORD_ENDSEEKER);
public final static Item MUSIC_DISC_EO_DRACONA = registerDisc("music_disc_eo_dracona", 0, EndSounds.RECORD_EO_DRACONA);
// Armor //
public static final Item AETERNIUM_HELMET = registerItem("aeternium_helmet", new EndArmorItem(EndArmorMaterial.AETERNIUM, EquipmentSlot.HEAD, makeItemSettings().fireResistant()));
public static final Item AETERNIUM_CHESTPLATE = registerItem("aeternium_chestplate", new EndArmorItem(EndArmorMaterial.AETERNIUM, EquipmentSlot.CHEST, makeItemSettings().fireResistant()));
public static final Item AETERNIUM_LEGGINGS = registerItem("aeternium_leggings", new EndArmorItem(EndArmorMaterial.AETERNIUM, EquipmentSlot.LEGS, makeItemSettings().fireResistant()));
public static final Item AETERNIUM_BOOTS = registerItem("aeternium_boots", new EndArmorItem(EndArmorMaterial.AETERNIUM, EquipmentSlot.FEET, makeItemSettings().fireResistant()));
public static final Item CRYSTALITE_HELMET = registerItem("crystalite_helmet", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.HEAD, makeItemSettings().rarity(Rarity.UNCOMMON)));
public static final Item CRYSTALITE_CHESTPLATE = registerItem("crystalite_chestplate", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.CHEST, makeItemSettings().rarity(Rarity.UNCOMMON)));
public static final Item CRYSTALITE_LEGGINGS = registerItem("crystalite_leggings", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.LEGS, makeItemSettings().rarity(Rarity.UNCOMMON)));
public static final Item CRYSTALITE_BOOTS = registerItem("crystalite_boots", new EndArmorItem(EndArmorMaterial.CRYSTALITE, EquipmentSlot.FEET, makeItemSettings().rarity(Rarity.UNCOMMON)));
public static final Item ARMORED_ELYTRA = registerItem("elytra_armored", new ArmoredElytra("elytra_armored", AETERNIUM_INGOT, 700, 0.96D, true));
public static final Item CRYSTALITE_HELMET = registerItem("crystalite_helmet", new CrystaliteHelmet());
public static final Item CRYSTALITE_CHESTPLATE = registerItem("crystalite_chestplate", new CrystaliteChestplate());
public static final Item CRYSTALITE_LEGGINGS = registerItem("crystalite_leggings", new CrystaliteLeggings());
public static final Item CRYSTALITE_BOOTS = registerItem("crystalite_boots", new CrystaliteBoots());
public static final Item ARMORED_ELYTRA = registerItem("elytra_armored", new ArmoredElytra("elytra_armored", EndArmorMaterial.AETERNIUM, Items.PHANTOM_MEMBRANE, 900, 0.96D, true));
// Tools //
public static final TieredItem AETERNIUM_SHOVEL = registerTool("aeternium_shovel", new EndShovelItem(EndToolMaterial.AETERNIUM, 1.5F, -3.0F, makeItemSettings().fireResistant()));
@ -114,10 +116,11 @@ public class EndItems {
public final static Item SHADOW_BERRY_COOKED = registerFood("shadow_berry_cooked", 6, 0.7F);
public final static Item END_FISH_RAW = registerFood("end_fish_raw", Foods.SALMON);
public final static Item END_FISH_COOKED = registerFood("end_fish_cooked", Foods.COOKED_SALMON);
public final static Item BUCKET_END_FISH = registerItem("bucket_end_fish", new EndBucketItem());
public final static Item BUCKET_CUBOZOA = registerItem("bucket_cubozoa", new EndBucketItem());
public final static Item SWEET_BERRY_JELLY = registerFood("sweet_berry_jelly", 6, 0.75F);
public final static Item SHADOW_BERRY_JELLY = registerFood("shadow_berry_jelly", 7, 0.75F, new MobEffectInstance(MobEffects.NIGHT_VISION, 400));
public final static Item BUCKET_END_FISH = registerItem("bucket_end_fish", new EndBucketItem(EndEntities.END_FISH));
public final static Item BUCKET_CUBOZOA = registerItem("bucket_cubozoa", new EndBucketItem(EndEntities.CUBOZOA));
public final static Item SWEET_BERRY_JELLY = registerFood("sweet_berry_jelly", 8, 0.7F);
public final static Item SHADOW_BERRY_JELLY = registerFood("shadow_berry_jelly", 6, 0.8F, new MobEffectInstance(MobEffects.NIGHT_VISION, 400));
public final static Item BLOSSOM_BERRY_JELLY = registerFood("blossom_berry_jelly", 8, 0.7F);
public final static Item BLOSSOM_BERRY = registerFood("blossom_berry", Foods.APPLE);
public final static Item AMBER_ROOT_RAW = registerFood("amber_root_raw", 2, 0.8F);
public final static Item CHORUS_MUSHROOM_RAW = registerFood("chorus_mushroom_raw", 3, 0.5F);
@ -129,11 +132,11 @@ public class EndItems {
public final static Item UMBRELLA_CLUSTER_JUICE = registerDrink("umbrella_cluster_juice", 5, 0.7F);
public static Item registerDisc(String name, int power, SoundEvent sound) {
return registerItem(BetterEnd.makeID(name), new ModelProviderDiscItem(power, sound, makeItemSettings()));
return registerItem(BetterEnd.makeID(name), new PatternedDiscItem(power, sound, makeItemSettings()));
}
public static Item registerItem(String name) {
return registerItem(BetterEnd.makeID(name), new ModelProviderItem(makeItemSettings()));
return registerItem(BetterEnd.makeID(name), new PatternedItem(makeItemSettings()));
}
public static Item registerItem(String name, Item item) {
@ -148,9 +151,6 @@ public class EndItems {
return item;
}
registerItem(id, item, MOD_ITEMS);
if (item instanceof BreakableItem) {
((BreakableItem) item).registerBrokenItem();
}
return item;
}
@ -222,7 +222,7 @@ public class EndItems {
}
public static Item registerFood(String name, FoodProperties foodComponent) {
return registerItem(name, new ModelProviderItem(makeItemSettings().food(foodComponent)));
return registerItem(name, new PatternedItem(makeItemSettings().food(foodComponent)));
}
public static Item registerDrink(String name) {
@ -238,12 +238,14 @@ public class EndItems {
return registerDrink(name, builder.build());
}
public static Properties makeItemSettings() {
return new Item.Properties().tab(CreativeTabs.TAB_ITEMS);
public static FabricItemSettings makeItemSettings() {
FabricItemSettings properties = new FabricItemSettings();
return (FabricItemSettings) properties.tab(CreativeTabs.TAB_ITEMS);
}
public static Properties makeBlockItemSettings() {
return new Item.Properties().tab(CreativeTabs.TAB_BLOCKS);
public static FabricItemSettings makeBlockItemSettings() {
FabricItemSettings properties = new FabricItemSettings();
return (FabricItemSettings) properties.tab(CreativeTabs.TAB_BLOCKS);
}
public static void register() {}

View file

@ -10,6 +10,7 @@ public class EndSounds {
public static final SoundEvent MUSIC_WATER = register("music", "water");
public static final SoundEvent MUSIC_DARK = register("music", "dark");
public static final SoundEvent MUSIC_OPENSPACE = register("music", "openspace");
public static final SoundEvent MUSIC_CAVES = register("music", "caves");
// Ambient
public static final SoundEvent AMBIENT_FOGGY_MUSHROOMLAND = register("ambient", "foggy_mushroomland");
@ -21,6 +22,7 @@ public class EndSounds {
public static final SoundEvent AMBIENT_SULPHUR_SPRINGS = register("ambient", "sulphur_springs");
public static final SoundEvent AMBIENT_UMBRELLA_JUNGLE = register("ambient", "umbrella_jungle");
public static final SoundEvent AMBIENT_GLOWING_GRASSLANDS = register("ambient", "glowing_grasslands");
public static final SoundEvent AMBIENT_CAVES = register("ambient", "caves");
// Entity
public static final SoundEvent ENTITY_DRAGONFLY = register("entity", "dragonfly");
@ -29,7 +31,10 @@ public class EndSounds {
public static final SoundEvent ENTITY_SHADOW_WALKER_DEATH = register("entity", "shadow_walker_death");
// Records
public static final SoundEvent STRANGE_AND_ALIEN = register("record", "strange_and_alien");
public static final SoundEvent RECORD_STRANGE_AND_ALIEN = register("record", "strange_and_alien");
public static final SoundEvent RECORD_GRASPING_AT_STARS = register("record", "grasping_at_stars");
public static final SoundEvent RECORD_ENDSEEKER = register("record", "endseeker");
public static final SoundEvent RECORD_EO_DRACONA = register("record", "eo_dracona");
public static void register() {}

View file

@ -151,7 +151,7 @@ public class EndTags {
TagHelper.addTag(EndTags.DRAGON_IMMUNE, EndBlocks.ENDER_ORE, EndBlocks.ETERNAL_PEDESTAL, EndBlocks.FLAVOLITE_RUNED_ETERNAL, EndBlocks.FLAVOLITE_RUNED);
TagHelper.addTag(EndTags.IRON_INGOTS, Items.IRON_INGOT);
TagHelper.addTag(EndTags.IRON_INGOTS, EndBlocks.TERMINITE.ingot);
TagHelper.addTag(EndTags.IRON_INGOTS, EndBlocks.THALLASIUM.ingot);
}
public static void addSurfaceBlock(Block block) {

View file

@ -19,7 +19,15 @@ public class LootTableUtil {
builder.setRolls(RandomValueBounds.between(0, 5));
builder.withCondition(LootItemRandomChanceCondition.randomChance(0.5f).build());
builder.withEntry(LootItem.lootTableItem(Items.GHAST_TEAR).build());
supplier.withPool(builder);
builder = FabricLootPoolBuilder.builder();
builder.setRolls(RandomValueBounds.between(0, 5));
builder.withCondition(LootItemRandomChanceCondition.randomChance(0.1f).build());
builder.withEntry(LootItem.lootTableItem(EndItems.MUSIC_DISC_STRANGE_AND_ALIEN).build());
builder.withEntry(LootItem.lootTableItem(EndItems.MUSIC_DISC_GRASPING_AT_STARS).build());
builder.withEntry(LootItem.lootTableItem(EndItems.MUSIC_DISC_ENDSEEKER).build());
builder.withEntry(LootItem.lootTableItem(EndItems.MUSIC_DISC_EO_DRACONA).build());
supplier.withPool(builder);
}
});

View file

@ -68,6 +68,7 @@ public class BiomeDefinition {
private float genChance = 1F;
private boolean hasCaves = true;
private boolean isCaveBiome = false;
private float temperature = 1F;
private ConfiguredSurfaceBuilder<?> surface;
@ -118,6 +119,11 @@ public class BiomeDefinition {
return this;
}
public BiomeDefinition setTemperature(float temperature) {
this.temperature = temperature;
return this;
}
public BiomeDefinition addMobSpawn(EntityType<?> type, int weight, int minGroupSize, int maxGroupSize) {
ResourceLocation eID = Registry.ENTITY_TYPE.getKey(type);
if (eID != Registry.ENTITY_TYPE.getDefaultKey()) {
@ -263,7 +269,7 @@ public class BiomeDefinition {
.biomeCategory(isCaveBiome ? BiomeCategory.NONE : BiomeCategory.THEEND)
.depth(depth)
.scale(0.2F)
.temperature(2.0F)
.temperature(temperature)
.downfall(0.0F)
.specialEffects(effects.build())
.mobSpawnSettings(spawnSettings.build())

View file

@ -11,9 +11,11 @@ public class BiomeIceStarfield extends EndBiome {
public BiomeIceStarfield() {
super(new BiomeDefinition("ice_starfield")
.setFogColor(224, 245, 254)
.setTemperature(0F)
.setFogDensity(2.2F)
.setFoliageColor(193, 244, 244)
.setGenChance(0.25F)
.setCaves(false)
.setParticles(EndParticles.SNOWFLAKE, 0.002F)
.addStructureFeature(EndStructures.GIANT_ICE_STAR)
.addFeature(EndFeatures.ICE_STAR)

View file

@ -2,7 +2,6 @@ package ru.betterend.world.biome.cave;
import ru.betterend.registry.EndFeatures;
import ru.betterend.registry.EndParticles;
import ru.betterend.registry.EndSounds;
import ru.betterend.world.biome.BiomeDefinition;
public class EmptyAuroraCaveBiome extends EndCaveBiome {
@ -12,7 +11,6 @@ public class EmptyAuroraCaveBiome extends EndCaveBiome {
.setFogDensity(2.0F)
.setPlantsColor(108, 25, 46)
.setWaterAndFogColor(186, 77, 237)
.setMusic(EndSounds.MUSIC_FOREST)
.setParticles(EndParticles.GLOWING_SPHERE, 0.001F));
this.addFloorFeature(EndFeatures.BIG_AURORA_CRYSTAL, 1);

View file

@ -1,15 +1,11 @@
package ru.betterend.world.biome.cave;
import ru.betterend.registry.EndFeatures;
import ru.betterend.registry.EndSounds;
import ru.betterend.world.biome.BiomeDefinition;
public class EmptyEndCaveBiome extends EndCaveBiome {
public EmptyEndCaveBiome() {
super(new BiomeDefinition("empty_end_cave")
.setFogDensity(2.0F)
.setMusic(EndSounds.MUSIC_FOREST));
super(new BiomeDefinition("empty_end_cave").setFogDensity(2.0F));
this.addFloorFeature(EndFeatures.END_STONE_STALAGMITE, 1);
this.addCeilFeature(EndFeatures.END_STONE_STALACTITE, 1);
}

View file

@ -2,7 +2,6 @@ package ru.betterend.world.biome.cave;
import ru.betterend.registry.EndFeatures;
import ru.betterend.registry.EndParticles;
import ru.betterend.registry.EndSounds;
import ru.betterend.world.biome.BiomeDefinition;
public class EmptySmaragdantCaveBiome extends EndCaveBiome {
@ -12,7 +11,6 @@ public class EmptySmaragdantCaveBiome extends EndCaveBiome {
.setFogDensity(2.0F)
.setPlantsColor(0, 131, 145)
.setWaterAndFogColor(31, 167, 212)
.setMusic(EndSounds.MUSIC_FOREST)
.setParticles(EndParticles.SMARAGDANT, 0.001F));
this.addFloorFeature(EndFeatures.SMARAGDANT_CRYSTAL, 1);

View file

@ -7,6 +7,7 @@ import net.minecraft.world.entity.ai.behavior.WeightedList;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.Feature;
import ru.betterend.registry.EndBiomes;
import ru.betterend.registry.EndSounds;
import ru.betterend.world.biome.BiomeDefinition;
import ru.betterend.world.biome.EndBiome;
import ru.betterend.world.features.EndFeature;
@ -26,6 +27,8 @@ public class EndCaveBiome extends EndBiome {
new CaveChunkPopulatorFeature(() -> (EndCaveBiome) EndBiomes.getBiome(definition.getID()))
);
definition.addFeature(feature).setCaveBiome();
definition.setMusic(EndSounds.MUSIC_CAVES);
definition.setLoop(EndSounds.AMBIENT_CAVES);
return definition;
}

View file

@ -5,7 +5,6 @@ import net.minecraft.util.Mth;
import net.minecraft.world.level.block.state.BlockState;
import ru.betterend.noise.OpenSimplexNoise;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndSounds;
import ru.betterend.world.biome.BiomeDefinition;
public class JadeCaveBiome extends EndCaveBiome {
@ -18,7 +17,6 @@ public class JadeCaveBiome extends EndCaveBiome {
.setFogColor(118, 150, 112)
.setFogDensity(2.0F)
.setWaterAndFogColor(95, 223, 255)
.setMusic(EndSounds.MUSIC_FOREST)
);
JADE[0] = EndBlocks.VIRID_JADESTONE.stone.defaultBlockState();
JADE[1] = EndBlocks.AZURE_JADESTONE.stone.defaultBlockState();

View file

@ -7,7 +7,6 @@ import ru.betterend.blocks.BlockProperties.TripleShape;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndFeatures;
import ru.betterend.registry.EndParticles;
import ru.betterend.registry.EndSounds;
import ru.betterend.world.biome.BiomeDefinition;
public class LushAuroraCaveBiome extends EndCaveBiome {
@ -17,7 +16,6 @@ public class LushAuroraCaveBiome extends EndCaveBiome {
.setFogDensity(2.0F)
.setPlantsColor(108, 25, 46)
.setWaterAndFogColor(186, 77, 237)
.setMusic(EndSounds.MUSIC_FOREST)
.setParticles(EndParticles.GLOWING_SPHERE, 0.001F)
.setSurface(EndBlocks.CAVE_MOSS));

View file

@ -3,7 +3,6 @@ package ru.betterend.world.biome.cave;
import ru.betterend.registry.EndBlocks;
import ru.betterend.registry.EndFeatures;
import ru.betterend.registry.EndParticles;
import ru.betterend.registry.EndSounds;
import ru.betterend.world.biome.BiomeDefinition;
public class LushSmaragdantCaveBiome extends EndCaveBiome {
@ -13,7 +12,6 @@ public class LushSmaragdantCaveBiome extends EndCaveBiome {
.setFogDensity(2.0F)
.setPlantsColor(0, 131, 145)
.setWaterAndFogColor(31, 167, 212)
.setMusic(EndSounds.MUSIC_FOREST)
.setParticles(EndParticles.SMARAGDANT, 0.001F)
.setSurface(EndBlocks.CAVE_MOSS));

View file

@ -13,7 +13,6 @@ public class PaintedMountainsBiome extends EndBiome {
super(new BiomeDefinition("painted_mountains")
.setFogColor(226, 239, 168)
.setFogDensity(2)
.setCaves(false)
.setWaterAndFogColor(192, 180, 131)
.setMusic(EndSounds.MUSIC_OPENSPACE)
.setLoop(EndSounds.AMBIENT_DUST_WASTELANDS)

View file

@ -26,18 +26,15 @@ import ru.betterend.world.features.DefaultFeature;
public class ObsidianPillarBasementFeature extends DefaultFeature {
@Override
public boolean place(WorldGenLevel world, ChunkGenerator chunkGenerator, Random random, BlockPos pos,
NoneFeatureConfiguration config) {
pos = getPosOnSurface(world,
new BlockPos(pos.getX() + random.nextInt(16), pos.getY(), pos.getZ() + random.nextInt(16)));
public boolean place(WorldGenLevel world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, NoneFeatureConfiguration config) {
pos = getPosOnSurface(world, new BlockPos(pos.getX() + random.nextInt(16), pos.getY(), pos.getZ() + random.nextInt(16)));
if (!world.getBlockState(pos.below(5)).is(EndTags.GEN_TERRAIN)) {
return false;
}
float height = MHelper.randRange(10F, 35F, random);
float radius = MHelper.randRange(2F, 5F, random);
SDF pillar = new SDFCappedCone().setRadius1(radius).setRadius2(radius).setHeight(height * 0.5F)
.setBlock(Blocks.OBSIDIAN);
SDF pillar = new SDFCappedCone().setRadius1(radius).setRadius2(radius).setHeight(height * 0.5F).setBlock(Blocks.OBSIDIAN);
pillar = new SDFTranslate().setTranslate(0, height * 0.5F - 3, 0).setSource(pillar);
SDF cut = new SDFFlatland().setBlock(Blocks.OBSIDIAN);
OpenSimplexNoise noise = new OpenSimplexNoise(random.nextLong());
@ -52,7 +49,6 @@ public class ObsidianPillarBasementFeature extends DefaultFeature {
vec = MHelper.randomHorizontal(random);
angle = random.nextFloat() * 0.2F;
pillar = new SDFRotation().setRotation(vec, angle).setSource(pillar);
BlockState mossy = EndBlocks.MOSSY_OBSIDIAN.defaultBlockState();
pillar.addPostProcess((info) -> {
if (info.getStateUp().isAir() && random.nextFloat() > 0.1F) {
@ -60,8 +56,7 @@ public class ObsidianPillarBasementFeature extends DefaultFeature {
}
return info.getState();
}).setReplaceFunction((state) -> {
return state.getMaterial().isReplaceable() || state.is(EndTags.GEN_TERRAIN)
|| state.getMaterial().equals(Material.PLANT);
return state.getMaterial().isReplaceable() || state.is(EndTags.GEN_TERRAIN) || state.getMaterial().equals(Material.PLANT);
}).fillRecursive(world, pos);
return true;

View file

@ -51,7 +51,7 @@ public abstract class EndCaveFeature extends DefaultFeature {
return false;
}
EndCaveBiome biome = EndBiomes.getCaveBiome(random);
EndCaveBiome biome = EndBiomes.getCaveBiome(pos.getX(), pos.getZ());
Set<BlockPos> caveBlocks = generate(world, center, radius, random);
if (!caveBlocks.isEmpty()) {
if (biome != null) {
@ -88,7 +88,9 @@ public abstract class EndCaveFeature extends DefaultFeature {
protected void placeFloor(WorldGenLevel world, EndCaveBiome biome, Set<BlockPos> floorPositions, Random random, BlockState surfaceBlock) {
float density = biome.getFloorDensity();
floorPositions.forEach((pos) -> {
BlocksHelper.setWithoutUpdate(world, pos, surfaceBlock);
if (!surfaceBlock.is(Blocks.END_STONE)) {
BlocksHelper.setWithoutUpdate(world, pos, surfaceBlock);
}
if (density > 0 && random.nextFloat() <= density) {
Feature<?> feature = biome.getFloorFeature(random);
if (feature != null) {

View file

@ -1,16 +1,21 @@
package ru.betterend.world.features.terrain.caves;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.level.WorldGenLevel;
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.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
import ru.betterend.noise.OpenSimplexNoise;
@ -20,12 +25,14 @@ import ru.betterend.util.BlocksHelper;
import ru.betterend.world.biome.cave.EndCaveBiome;
public class TunelCaveFeature extends EndCaveFeature {
private static final OpenSimplexNoise BIOME_NOISE_X = new OpenSimplexNoise("biome_noise_x".hashCode());
private static final OpenSimplexNoise BIOME_NOISE_Z = new OpenSimplexNoise("biome_noise_z".hashCode());
private Set<BlockPos> generate(WorldGenLevel world, BlockPos center, Random random) {
int x1 = (center.getX() >> 4) << 4;
int z1 = (center.getZ() >> 4) << 4;
int cx = center.getX() >> 4;
int cz = center.getZ() >> 4;
if ((long) cx * (long) cx + (long) cz + (long) cz < 256) {
return Sets.newHashSet();
}
int x1 = cx << 4;
int z1 = cz << 4;
int x2 = x1 + 16;
int z2 = z1 + 16;
int y2 = world.getHeight();
@ -43,12 +50,19 @@ public class TunelCaveFeature extends EndCaveFeature {
for (int y = 0; y < y2; y++) {
pos.setY(y);
float val = Mth.abs((float) noiseH.eval(x * 0.02, y * 0.01, z * 0.02));
float vert = Mth.sin((y + (float) noiseV.eval(x * 0.01, z * 0.01) * 20) * 0.1F) * 0.9F;//Mth.abs(y - 50 + (float) noiseV.eval(x * 0.01, z * 0.01) * 20) * 0.1F;
float vert = Mth.sin((y + (float) noiseV.eval(x * 0.01, z * 0.01) * 20) * 0.1F) * 0.9F;
float dist = (float) noiseD.eval(x * 0.1, y * 0.1, z * 0.1) * 0.12F;
vert *= vert;
if (val + vert + dist < 0.15 && world.getBlockState(pos).is(EndTags.GEN_TERRAIN)) {
if (val + vert + dist < 0.15 && world.getBlockState(pos).is(EndTags.GEN_TERRAIN) && noWaterNear(world, pos)) {
BlocksHelper.setWithoutUpdate(world, pos, AIR);
positions.add(pos.immutable());
int height = world.getHeight(Types.WORLD_SURFACE_WG, pos.getX(), pos.getZ());
if (height < pos.getY() + 4) {
while (pos.getY() < height && noWaterNear(world, pos)) {
pos.setY(pos.getY() + 1);
BlocksHelper.setWithoutUpdate(world, pos, AIR);
}
}
}
}
}
@ -56,6 +70,23 @@ public class TunelCaveFeature extends EndCaveFeature {
return positions;
}
private boolean noWaterNear(WorldGenLevel world, BlockPos pos) {
BlockPos above1 = pos.above();
BlockPos above2 = pos.above(2);
if (!world.getFluidState(above1).isEmpty() || !world.getFluidState(above2).isEmpty()) {
return false;
}
for (Direction dir: BlocksHelper.HORIZONTAL) {
if (!world.getFluidState(above1.relative(dir)).isEmpty()) {
return false;
}
if (!world.getFluidState(above2.relative(dir)).isEmpty()) {
return false;
}
}
return true;
}
@Override
public boolean place(WorldGenLevel world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, NoneFeatureConfiguration config) {
if (pos.getX() * pos.getX() + pos.getZ() * pos.getZ() <= 2500) {
@ -66,49 +97,62 @@ public class TunelCaveFeature extends EndCaveFeature {
return false;
}
EndCaveBiome biome = EndBiomes.getCaveBiome(random);
Set<BlockPos> preCaveBlocks = generate(world, pos, random);
Set<BlockPos> caveBlocks = mutateBlocks(preCaveBlocks);
if (!caveBlocks.isEmpty()) {
if (biome != null) {
setBiomes(world, biome, caveBlocks);
Set<BlockPos> floorPositions = Sets.newHashSet();
Set<BlockPos> ceilPositions = Sets.newHashSet();
MutableBlockPos mut = new MutableBlockPos();
caveBlocks.forEach((bpos) -> {
mut.set(bpos);
if (world.getBlockState(mut).getMaterial().isReplaceable()) {
mut.setY(bpos.getY() - 1);
if (world.getBlockState(mut).is(EndTags.GEN_TERRAIN)) {
floorPositions.add(mut.immutable());
}
mut.setY(bpos.getY() + 1);
if (world.getBlockState(mut).is(EndTags.GEN_TERRAIN)) {
ceilPositions.add(mut.immutable());
}
}
});
BlockState surfaceBlock = biome.getBiome().getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial();
placeFloor(world, biome, floorPositions, random, surfaceBlock);
placeCeil(world, biome, ceilPositions, random);
placeWalls(world, biome, caveBlocks, random);
}
fixBlocks(world, preCaveBlocks);
Set<BlockPos> caveBlocks = generate(world, pos, random);
if (caveBlocks.isEmpty()) {
return false;
}
return true;
}
private Set<BlockPos> mutateBlocks(Set<BlockPos> caveBlocks) {
Set<BlockPos> result = Sets.newHashSet();
caveBlocks.forEach(pos -> {
int dx = pos.getX() + (int) (BIOME_NOISE_X.eval(pos.getX() * 0.2, pos.getZ() * 0.2) * 5);
int dz = pos.getZ() + (int) (BIOME_NOISE_Z.eval(pos.getX() * 0.2, pos.getZ() * 0.2) * 5);
if ((dx >> 4) == (pos.getX() >> 4) && (dz >> 4) == (pos.getZ() >> 4)) {
result.add(pos);
Map<EndCaveBiome, Set<BlockPos>> floorSets = Maps.newHashMap();
Map<EndCaveBiome, Set<BlockPos>> ceilSets = Maps.newHashMap();
MutableBlockPos mut = new MutableBlockPos();
Set<BlockPos> remove = Sets.newHashSet();
caveBlocks.forEach((bpos) -> {
mut.set(bpos);
EndCaveBiome bio = EndBiomes.getCaveBiome(bpos.getX(), bpos.getZ());
int height = world.getHeight(Types.WORLD_SURFACE, bpos.getX(), bpos.getZ());
if (mut.getY() >= height) {
remove.add(bpos);
}
else if (world.getBlockState(mut).getMaterial().isReplaceable()) {
mut.setY(bpos.getY() - 1);
if (world.getBlockState(mut).is(EndTags.GEN_TERRAIN)) {
Set<BlockPos> floorPositions = floorSets.get(bio);
if (floorPositions == null) {
floorPositions = Sets.newHashSet();
floorSets.put(bio, floorPositions);
}
floorPositions.add(mut.immutable());
}
mut.setY(bpos.getY() + 1);
if (world.getBlockState(mut).is(EndTags.GEN_TERRAIN)) {
Set<BlockPos> ceilPositions = ceilSets.get(bio);
if (ceilPositions == null) {
ceilPositions = Sets.newHashSet();
ceilSets.put(bio, ceilPositions);
}
ceilPositions.add(mut.immutable());
}
setBiome(world, bpos, bio);
}
});
return result;
caveBlocks.removeAll(remove);
if (caveBlocks.isEmpty()) {
return true;
}
floorSets.forEach((biome, floorPositions) -> {
BlockState surfaceBlock = biome.getBiome().getGenerationSettings().getSurfaceBuilderConfig().getTopMaterial();
placeFloor(world, biome, floorPositions, random, surfaceBlock);
});
ceilSets.forEach((biome, ceilPositions) -> {
placeCeil(world, biome, ceilPositions, random);
});
EndCaveBiome biome = EndBiomes.getCaveBiome(pos.getX(), pos.getZ());
placeWalls(world, biome, caveBlocks, random);
fixBlocks(world, caveBlocks);
return true;
}
@Override
@ -120,7 +164,9 @@ public class TunelCaveFeature extends EndCaveFeature {
protected void placeFloor(WorldGenLevel world, EndCaveBiome biome, Set<BlockPos> floorPositions, Random random, BlockState surfaceBlock) {
float density = biome.getFloorDensity() * 0.2F;
floorPositions.forEach((pos) -> {
BlocksHelper.setWithoutUpdate(world, pos, surfaceBlock);
if (!surfaceBlock.is(Blocks.END_STONE)) {
BlocksHelper.setWithoutUpdate(world, pos, surfaceBlock);
}
if (density > 0 && random.nextFloat() <= density) {
Feature<?> feature = biome.getFloorFeature(random);
if (feature != null) {

View file

@ -95,6 +95,9 @@ public class BetterEndBiomeSource extends BiomeSource {
endBiome = mapLand.getBiome(biomeX << 2, biomeZ << 2);
}
else {
if (!GeneratorOptions.noRingVoid() && dist <= 65536L) {
return barrens;
}
endBiome = mapVoid.getBiome(biomeX << 2, biomeZ << 2);
}
}

View file

@ -20,6 +20,7 @@ public class BiomeMap {
private final OpenSimplexNoise noiseX;
private final OpenSimplexNoise noiseZ;
private final BiomePicker picker;
private final long seed;
public BiomeMap(long seed, int size, BiomePicker picker) {
maps.clear();
@ -30,6 +31,11 @@ public class BiomeMap {
depth = (int) Math.ceil(Math.log(size) / Math.log(2)) - 2;
this.size = 1 << depth;
this.picker = picker;
this.seed = seed;
}
public long getSeed() {
return seed;
}
public void clearCache() {

View file

@ -7,6 +7,7 @@ import ru.betterend.config.Configs;
public class GeneratorOptions {
private static int biomeSizeLand;
private static int biomeSizeVoid;
private static int biomeSizeCaves;
private static boolean hasPortal;
private static boolean hasPillars;
private static boolean hasDragonFights;
@ -28,10 +29,12 @@ public class GeneratorOptions {
private static boolean replacePillars;
private static long islandDistBlock;
private static int islandDistChunk;
private static boolean directSpikeHeight;
public static void init() {
biomeSizeLand = Configs.GENERATOR_CONFIG.getInt("biomeMap", "biomeSizeLand", 256);
biomeSizeVoid = Configs.GENERATOR_CONFIG.getInt("biomeMap", "biomeSizeVoid", 256);
biomeSizeCaves = Configs.GENERATOR_CONFIG.getInt("biomeMap", "biomeSizeCaves", 32);
hasPortal = Configs.GENERATOR_CONFIG.getBoolean("portal", "hasPortal", true);
hasPillars = Configs.GENERATOR_CONFIG.getBoolean("spikes", "hasSpikes", true);
hasDragonFights = Configs.GENERATOR_CONFIG.getBooleanRoot("hasDragonFights", true);
@ -67,6 +70,10 @@ public class GeneratorOptions {
return Mth.clamp(biomeSizeVoid, 1, 8192);
}
public static int getBiomeSizeCaves() {
return Mth.clamp(biomeSizeCaves, 1, 8192);
}
public static boolean hasPortal() {
return hasPortal;
}
@ -142,4 +149,14 @@ public class GeneratorOptions {
public static int getIslandDistChunk() {
return islandDistChunk;
}
public static void setDirectSpikeHeight() {
directSpikeHeight = true;
}
public static boolean isDirectSpikeHeight() {
boolean height = directSpikeHeight;
directSpikeHeight = false;
return height;
}
}

View file

@ -26,25 +26,25 @@ public class EternalPortalStructure extends FeatureBaseStructure {
private static final StructureTemplate STRUCTURE = StructureHelper.readStructure(STRUCTURE_ID);
@Override
protected boolean shouldStartAt(ChunkGenerator chunkGenerator, BiomeSource biomeSource, long worldSeed, WorldgenRandom chunkRandom, int chunkX, int chunkZ, Biome biome, ChunkPos chunkPos, NoneFeatureConfiguration featureConfig) {
long x = chunkPos.x;
long z = chunkPos.z;
if (x * x + z * z < 10000) {
protected boolean isFeatureChunk(ChunkGenerator chunkGenerator, BiomeSource biomeSource, long worldSeed, WorldgenRandom chunkRandom, int chunkX, int chunkZ, Biome biome, ChunkPos chunkPos, NoneFeatureConfiguration featureConfig) {
long x = (long) chunkPos.x * (long) chunkPos.x;
long z = (long) chunkPos.z * (long) chunkPos.z;
if (x + z < 1024L) {
return false;
}
if (chunkGenerator.getBaseHeight((chunkX << 4) | 8, (chunkZ << 4) | 8, Heightmap.Types.WORLD_SURFACE_WG) < 10) {
return false;
}
return super.shouldStartAt(chunkGenerator, biomeSource, worldSeed, chunkRandom, chunkX, chunkZ, biome, chunkPos, featureConfig);
return super.isFeatureChunk(chunkGenerator, biomeSource, worldSeed, chunkRandom, chunkX, chunkZ, biome, chunkPos, featureConfig);
}
@Override
public StructureFeature.StructureStartFactory<NoneFeatureConfiguration> getStartFactory() {
return SDFStructureStart::new;
return PortalStructureStart::new;
}
public static class SDFStructureStart extends StructureStart<NoneFeatureConfiguration> {
public SDFStructureStart(StructureFeature<NoneFeatureConfiguration> feature, int chunkX, int chunkZ, BoundingBox box, int references, long seed) {
public static class PortalStructureStart extends StructureStart<NoneFeatureConfiguration> {
public PortalStructureStart(StructureFeature<NoneFeatureConfiguration> feature, int chunkX, int chunkZ, BoundingBox box, int references, long seed) {
super(feature, chunkX, chunkZ, box, references, seed);
}

View file

@ -21,7 +21,8 @@ public abstract class FeatureBaseStructure extends StructureFeature<NoneFeatureC
super(NoneFeatureConfiguration.CODEC);
}
protected boolean shouldStartAt(ChunkGenerator chunkGenerator, BiomeSource biomeSource, long worldSeed, WorldgenRandom chunkRandom, int chunkX, int chunkZ, Biome biome, ChunkPos chunkPos, NoneFeatureConfiguration featureConfig) {
@Override
protected boolean isFeatureChunk(ChunkGenerator chunkGenerator, BiomeSource biomeSource, long worldSeed, WorldgenRandom chunkRandom, int chunkX, int chunkZ, Biome biome, ChunkPos chunkPos, NoneFeatureConfiguration featureConfig) {
return getGenerationHeight(chunkX, chunkZ, chunkGenerator) >= 20;
}

View file

@ -48,7 +48,7 @@ public class NBTPiece extends BasePiece {
@Override
protected void addAdditionalSaveData(CompoundTag tag) {
tag.putString("id", structureID.toString());
tag.putString("structureID", structureID.toString());
tag.putInt("rotation", rotation.ordinal());
tag.putInt("mirror", mirror.ordinal());
tag.putInt("erosion", erosion);
@ -58,7 +58,7 @@ public class NBTPiece extends BasePiece {
@Override
protected void fromNbt(CompoundTag tag) {
structureID = new ResourceLocation(tag.getString("id"));
structureID = new ResourceLocation(tag.getString("structureID"));
rotation = Rotation.values()[tag.getInt("rotation")];
mirror = Mirror.values()[tag.getInt("mirror")];
erosion = tag.getInt("erosion");

View file

@ -506,7 +506,7 @@
"block.betterend.vent_bubble_column": "Vent Bubble Column",
"block.betterend.respawn_obelisk": "Respawn Obelisk",
"message.betterend.set_spawn": "\u00A7b\u00A7lYour spawn point is set here",
"message.betterend.fail_spawn": "\u00A7c\u00A7lYour need to hold 6 Amber Gems to set your spawn point",
"message.betterend.fail_spawn": "\u00A7c\u00A7lYou need to hold 6 Amber Gems to set your spawn point",
"block.betterend.dragon_tree_composter": "Dragon Tree Composter",
"block.betterend.end_lotus_composter": "End Lotus Composter",
@ -821,6 +821,12 @@
"item.betterend.music_disc_strange_and_alien": "§bMusic Disc§r",
"item.betterend.music_disc_strange_and_alien.desc": "§5Firel§r - §fStrange And Alien§r",
"item.betterend.music_disc_grasping_at_stars": "§bMusic Disc§r",
"item.betterend.music_disc_grasping_at_stars.desc": "§5Firel§r - §fGrasping At Stars§r",
"item.betterend.music_disc_endseeker": "§bMusic Disc§r",
"item.betterend.music_disc_endseeker.desc": "§5Firel§r - §fEndseeker§r",
"item.betterend.music_disc_eo_dracona": "§bMusic Disc§r",
"item.betterend.music_disc_eo_dracona.desc": "§5Firel§r - §fEo Dracona§r",
"block.betterend.hydralux_petal_block_amber": "Amber Petal Block",
"block.betterend.hydralux_petal_block_beige": "Beige Petal Block",
@ -855,5 +861,15 @@
"block.betterend.neon_cactus_block": "Neon Cactus Block",
"block.betterend.neon_cactus_slab": "Neon Cactus Slab",
"block.betterend.neon_cactus_stairs": "Neon Cactus Stairs",
"biome.betterend.jade_cave": "Jade Cave"
"biome.betterend.jade_cave": "Jade Cave",
"item.betterend.blossom_berry_jelly": "Blossom Berry Jelly",
"item.betterend.aeternium_forged_plate": "Aeternium Forged Plate",
"item.betterend.terminite_forged_plate": "Terminite Forged Plate",
"item.betterend.thallasium_forged_plate": "Thallasium Forged Plate",
"attribute.name.generic.blindness_resistance": "Blindness Resistance",
"tooltip.armor.crystalite_set": "Set bonus: Regeneration I",
"tooltip.armor.crystalite_chest": "Effect: Dig Speed I",
"tooltip.armor.crystalite_boots": "Effect: Swiftness I"
}

View file

@ -840,6 +840,9 @@
"item.betterend.cave_pumpkin_pie": "Пирог из пещерной тыквы",
"item.betterend.music_disc_strange_and_alien": "§bПластинка§r",
"item.betterend.music_disc_grasping_at_stars": "§bПластинка§r",
"item.betterend.music_disc_endseeker": "§bПластинка§r",
"item.betterend.music_disc_eo_dracona": "§bПластинка§r",
"block.betterend.hydralux_petal_block_amber": "Янтарный блок лепестков",
"block.betterend.hydralux_petal_block_beige": "Бежевый блок лепестков",
@ -874,5 +877,15 @@
"block.betterend.neon_cactus_block": "Блок неонового кактуса",
"block.betterend.neon_cactus_slab": "Плита из неонового кактуса",
"block.betterend.neon_cactus_stairs": "Ступени из неонового кактуса",
"biome.betterend.jade_cave": "Нефритовая пещера"
"biome.betterend.jade_cave": "Нефритовая пещера",
"item.betterend.blossom_berry_jelly": "Желе из цветущей ягоды",
"item.betterend.aeternium_forged_plate": "Этериевая кованная пластина",
"item.betterend.terminite_forged_plate": "Терминитовая кованная пластина",
"item.betterend.thallasium_forged_plate": "Талласиевая кованная пластина",
"attribute.name.generic.blindness_resistance": "Сопротивление ослеплению",
"tooltip.armor.crystalite_set": "Бонус сета: Регенерация I",
"tooltip.armor.crystalite_chest": "Эффект: Ускорение I",
"tooltip.armor.crystalite_boots": "Эффект: Стремительность I"
}

View file

@ -0,0 +1,14 @@
{
"parent": "item/generated",
"textures": {
"layer0": "betterend:item/elytra_armored"
},
"overrides": [
{
"predicate": {
"broken": 1
},
"model": "betterend:item/elytra_armored_broken"
}
]
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "betterend:item/elytra_armored_broken"
}
}

View file

@ -99,6 +99,31 @@
}
]
},
"betterend.music.caves": {
"category": "music",
"sounds": [
{
"name": "betterend:music/godmode-future_rennaisance",
"volume": 0.1,
"stream": false
},
{
"name": "betterend:music/futuremono-moonrise",
"volume": 0.1,
"stream": false
},
{
"name": "betterend:music/emmit_fenn-wander",
"volume": 0.1,
"stream": false
},
{
"name": "betterend:music/corbyn_kites-orbit",
"volume": 0.1,
"stream": false
}
]
},
"betterend.ambient.foggy_mushroomland": {
"category": "ambient",
@ -184,6 +209,16 @@
}
]
},
"betterend.ambient.caves": {
"category": "ambient",
"sounds": [
{
"name": "betterend:ambient/caves",
"volume": 0.5,
"stream": false
}
]
},
"betterend.entity.dragonfly": {
"category": "entity",
@ -242,5 +277,32 @@
"stream": false
}
]
},
"betterend.record.grasping_at_stars": {
"category": "record",
"sounds": [
{
"name": "betterend:records/firel-grasping_at_stars",
"stream": false
}
]
},
"betterend.record.endseeker": {
"category": "record",
"sounds": [
{
"name": "betterend:records/firel-endseeker",
"stream": false
}
]
},
"betterend.record.eo_dracona": {
"category": "record",
"sounds": [
{
"name": "betterend:records/firel-eo_dracona",
"stream": false
}
]
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

After

Width:  |  Height:  |  Size: 690 B

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 453 B

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

After

Width:  |  Height:  |  Size: 209 B

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

View file

@ -8,6 +8,8 @@
"ClientPlayNetworkHandlerMixin",
"NamespaceResourceManagerMixin",
"EnchantingTableBlockMixin",
"HumanoidMobRendererMixin",
"ArmorStandRendererMixin",
"BackgroundRendererMixin",
"ClientRecipeBookMixin",
"ModelVariantMapMixin",

View file

@ -18,10 +18,10 @@
"RecipeManagerAccessor",
"EnchantmentMenuMixin",
"MinecraftServerMixin",
"EndDragonFightMixin",
"BlockBehaviourMixin",
"DimensionTypeMixin",
"RecipeManagerMixin",
"ArmorItemAccessor",
"BoneMealItemMixin",
"CraftingMenuMixin",
"LivingEntityMixin",
@ -33,6 +33,7 @@
"AnvilMenuMixin",
"TagLoaderMixin",
"EnderManMixin",
"EndSpikeMixin",
"MonsterMixin",
"EntityMixin",
"PlayerMixin",

View file

@ -43,9 +43,9 @@
],
"depends": {
"fabricloader": ">=0.10.0",
"fabric": ">=0.29.0",
"minecraft": ">=1.16.3"
"fabricloader": ">=0.11.0",
"fabric": ">=0.32.0",
"minecraft": ">=1.16.4"
},
"suggests": {
"byg": ">=1.1.3",