diff --git a/src/main/generated/assets/voltexdesertupdate/blockstates/quicksand_block.json b/src/main/generated/assets/voltexdesertupdate/blockstates/quicksand_block.json new file mode 100644 index 0000000..2553abc --- /dev/null +++ b/src/main/generated/assets/voltexdesertupdate/blockstates/quicksand_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "voltexdesertupdate:block/quicksand_block" + } + } +} \ No newline at end of file diff --git a/src/main/generated/assets/voltexdesertupdate/models/block/quicksand_block.json b/src/main/generated/assets/voltexdesertupdate/models/block/quicksand_block.json new file mode 100644 index 0000000..a98dc2f --- /dev/null +++ b/src/main/generated/assets/voltexdesertupdate/models/block/quicksand_block.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "voltexdesertupdate:block/quicksand_block" + } +} \ No newline at end of file diff --git a/src/main/generated/assets/voltexdesertupdate/models/item/quicksand_block.json b/src/main/generated/assets/voltexdesertupdate/models/item/quicksand_block.json new file mode 100644 index 0000000..3ab44db --- /dev/null +++ b/src/main/generated/assets/voltexdesertupdate/models/item/quicksand_block.json @@ -0,0 +1,3 @@ +{ + "parent": "voltexdesertupdate:block/quicksand_block" +} \ No newline at end of file diff --git a/src/main/java/net/voltexstudios/VoltexDesertUpdate.java b/src/main/java/net/voltexstudios/VoltexDesertUpdate.java index d0dc7de..8c7aa2b 100644 --- a/src/main/java/net/voltexstudios/VoltexDesertUpdate.java +++ b/src/main/java/net/voltexstudios/VoltexDesertUpdate.java @@ -3,8 +3,12 @@ package net.voltexstudios; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; +import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; +import net.minecraft.block.FireBlock; +import net.voltexstudios.blocks.ModBlocks; import net.voltexstudios.entity.ModEntities; import net.voltexstudios.entity.custom.VultureEntity; +import net.voltexstudios.item.ModItemGroups; import net.voltexstudios.item.ModItems; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,12 +21,18 @@ public class VoltexDesertUpdate implements ModInitializer { @Override public void onInitialize() { - LOGGER.info("Hello Fabric world!"); + ModItemGroups.registerItemGroups(); ModItems.registerModItems(); + ModBlocks.registerModBlocks(); ModEntities.registerModEntities(); - FabricDefaultAttributeRegistry.register(ModEntities.VULTURE_ENTITY, VultureEntity.createAttributes()); + FabricDefaultAttributeRegistry.register(ModEntities.VULTURE_ENTITY, VultureEntity.createVultureAttributes()); + + FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.PALM_LOG, 5, 5); + FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.PALM_WOOD, 5, 5); + FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.PALM_PLANKS, 5, 20); + FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.PALM_LEAVES, 30, 60); } } \ No newline at end of file diff --git a/src/main/java/net/voltexstudios/VoltexDesertUpdateClient.java b/src/main/java/net/voltexstudios/VoltexDesertUpdateClient.java index c4d05d0..1aadabd 100644 --- a/src/main/java/net/voltexstudios/VoltexDesertUpdateClient.java +++ b/src/main/java/net/voltexstudios/VoltexDesertUpdateClient.java @@ -1,8 +1,11 @@ package net.voltexstudios; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry; import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; +import net.minecraft.client.render.RenderLayer; +import net.voltexstudios.blocks.ModBlocks; import net.voltexstudios.entity.ModEntities; import net.voltexstudios.entity.client.VultureModel; import net.voltexstudios.entity.client.VultureRenderer; @@ -13,6 +16,8 @@ public class VoltexDesertUpdateClient implements ClientModInitializer { public void onInitializeClient() { VoltexDesertUpdate.LOGGER.info("Initializing Desert Update Client"); + BlockRenderLayerMap.INSTANCE.putBlock(ModBlocks.PALM_SAPLING, RenderLayer.getCutout()); + EntityModelLayerRegistry.registerModelLayer(VultureModel.VULTURE, VultureModel::getTexturedModelData); EntityRendererRegistry.register(ModEntities.VULTURE_ENTITY, VultureRenderer::new); } diff --git a/src/main/java/net/voltexstudios/VoltexDesertUpdateDataGenerator.java b/src/main/java/net/voltexstudios/VoltexDesertUpdateDataGenerator.java index 39bb10a..f665ade 100644 --- a/src/main/java/net/voltexstudios/VoltexDesertUpdateDataGenerator.java +++ b/src/main/java/net/voltexstudios/VoltexDesertUpdateDataGenerator.java @@ -2,10 +2,32 @@ package net.voltexstudios; import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; +import net.minecraft.registry.RegistryBuilder; +import net.minecraft.registry.RegistryKeys; +import net.voltexstudios.datagen.ModBlockTagProvider; +import net.voltexstudios.datagen.ModItemTagProvider; +import net.voltexstudios.datagen.ModLootTableProvider; +import net.voltexstudios.datagen.ModModelProvider; +import net.voltexstudios.world.ModConfiguredFeatures; +import net.voltexstudios.world.ModPlacedFeatures; public class VoltexDesertUpdateDataGenerator implements DataGeneratorEntrypoint { + @Override public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { + FabricDataGenerator.Pack pack = fabricDataGenerator.createPack(); + + pack.addProvider(ModBlockTagProvider::new); + pack.addProvider(ModItemTagProvider::new); + pack.addProvider(ModLootTableProvider::new); + pack.addProvider(ModModelProvider::new); + } + + @Override + public void buildRegistry(RegistryBuilder registryBuilder) { + registryBuilder.addRegistry(RegistryKeys.CONFIGURED_FEATURE, ModConfiguredFeatures::bootstrap); + registryBuilder.addRegistry(RegistryKeys.PLACED_FEATURE, ModPlacedFeatures::bootstrap); + } } diff --git a/src/main/java/net/voltexstudios/blocks/ModBlocks.java b/src/main/java/net/voltexstudios/blocks/ModBlocks.java new file mode 100644 index 0000000..cf454cf --- /dev/null +++ b/src/main/java/net/voltexstudios/blocks/ModBlocks.java @@ -0,0 +1,60 @@ +package net.voltexstudios.blocks; + +import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; +import net.minecraft.block.*; +import net.minecraft.block.piston.PistonBehavior; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroups; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.sound.BlockSoundGroup; +import net.minecraft.util.Identifier; +import net.voltexstudios.VoltexDesertUpdate; +import net.voltexstudios.blocks.custom.QuicksandBlock; +import net.voltexstudios.world.tree.ModSaplingGenerators; + +public class ModBlocks { + + public static final Block QUICKSAND_BLOCK = registerBlock("quicksand_block", + new QuicksandBlock(AbstractBlock.Settings.copy(Blocks.POWDER_SNOW))); + + public static final Block PALM_LOG = registerBlock("palm_log", + new PillarBlock(AbstractBlock.Settings.copy(Blocks.OAK_LOG))); + public static final Block PALM_WOOD = registerBlock("palm_wood", + new PillarBlock(AbstractBlock.Settings.copy(Blocks.OAK_WOOD))); + public static final Block PALM_PLANKS = registerBlock("palm_planks", + new Block(AbstractBlock.Settings.copy(Blocks.OAK_PLANKS))); + public static final Block PALM_LEAVES = registerBlock("palm_leaves", + new LeavesBlock(AbstractBlock.Settings.copy(Blocks.OAK_LEAVES))); + public static final Block PALM_SAPLING = registerBlock("palm_sapling", + new SaplingBlock(ModSaplingGenerators.PALM, AbstractBlock.Settings.create() + .mapColor(MapColor.PALE_YELLOW) + .noCollision() + .ticksRandomly() + .breakInstantly() + .sounds(BlockSoundGroup.SAND) + .pistonBehavior(PistonBehavior.DESTROY))); + + private static Block registerBlockWithoutBlockItem(String name, Block block) { + return Registry.register(Registries.BLOCK, Identifier.of(VoltexDesertUpdate.MOD_ID, name), block); + } + + private static Block registerBlock(String name, Block block) { + registerBlockItem(name, block); + return Registry.register(Registries.BLOCK, Identifier.of(VoltexDesertUpdate.MOD_ID, name), block); + } + + private static void registerBlockItem(String name, Block block) { + Registry.register(Registries.ITEM, Identifier.of(VoltexDesertUpdate.MOD_ID, name), + new BlockItem(block, new Item.Settings())); + } + + public static void registerModBlocks() { + VoltexDesertUpdate.LOGGER.info("Registering Mod Blocks for " + VoltexDesertUpdate.MOD_ID); + + ItemGroupEvents.modifyEntriesEvent(ItemGroups.BUILDING_BLOCKS).register(entries -> { + + }); + } +} diff --git a/src/main/java/net/voltexstudios/blocks/custom/QuicksandBlock.java b/src/main/java/net/voltexstudios/blocks/custom/QuicksandBlock.java new file mode 100644 index 0000000..3a2db52 --- /dev/null +++ b/src/main/java/net/voltexstudios/blocks/custom/QuicksandBlock.java @@ -0,0 +1,129 @@ +package net.voltexstudios.blocks.custom; + +import com.mojang.serialization.MapCodec; +import net.minecraft.block.*; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.FallingBlockEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.pathing.NavigationType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.particle.DustParticleEffect; +import net.minecraft.registry.tag.EntityTypeTags; +import net.minecraft.sound.SoundEvent; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.random.Random; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.*; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class QuicksandBlock extends Block implements FluidDrainable { + + private static final float DAMAGE = 0.25f; + + public static final MapCodec CODEC = createCodec(PowderSnowBlock::new); + + private static final VoxelShape FALLING_SHAPE = VoxelShapes.cuboid(0.0, 0.0, 0.0, 1.0, 0.8999999761581421, 1.0); + + public QuicksandBlock(Settings settings) { + super(settings); + } + + @Override + protected MapCodec getCodec() { + return CODEC; + } + + protected boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) { + return stateFrom.isOf(this) || super.isSideInvisible(state, stateFrom, direction); + } + + protected VoxelShape getCullingShape(BlockState state, BlockView world, BlockPos pos) { + return VoxelShapes.empty(); + } + + protected void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) { + if (!(entity instanceof LivingEntity) || entity.getBlockStateAtPos().isOf(this)) { + entity.slowMovement(state, new Vec3d(0.8999999761581421, 1.5, 0.8999999761581421)); + + entity.damage(world.getDamageSources().inWall(), DAMAGE); + + if (world.isClient) { + Random random = world.getRandom(); + boolean bl = entity.lastRenderX != entity.getX() || entity.lastRenderZ != entity.getZ(); + if (bl && random.nextBoolean()) { + world.addParticle(new DustParticleEffect(new Vec3d(1.0, 1.0, 1.0).toVector3f(), 1.0F), entity.getX(), pos.getY() + 1, entity.getZ(), (double)(MathHelper.nextBetween(random, -1.0F, 1.0F) * 0.083333336F), 0.05000000074505806, (double)(MathHelper.nextBetween(random, -1.0F, 1.0F) * 0.083333336F)); + } + } + } + } + + public void onLandedUpon(World world, BlockState state, BlockPos pos, Entity entity, float fallDistance) { + if (!((double)fallDistance < 4.0) && entity instanceof LivingEntity livingEntity) { + LivingEntity.FallSounds fallSounds = livingEntity.getFallSounds(); + SoundEvent soundEvent = (double)fallDistance < 7.0 ? fallSounds.small() : fallSounds.big(); + entity.playSound(soundEvent, 1.0F, 1.0F); + } + } + + protected VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + if (context instanceof EntityShapeContext entityShapeContext) { + Entity entity = entityShapeContext.getEntity(); + if (entity != null) { + if (entity.fallDistance > 2.5F) { + return FALLING_SHAPE; + } + + boolean bl = entity instanceof FallingBlockEntity; + if (bl || canWalkOnQuicksand(entity) && context.isAbove(VoxelShapes.fullCube(), pos, false) && !context.isDescending()) { + return super.getCollisionShape(state, world, pos, context); + } + } + } + + return VoxelShapes.empty(); + } + + protected VoxelShape getCameraCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return VoxelShapes.empty(); + } + + public static boolean canWalkOnQuicksand(Entity entity) { + if (entity.getType().isIn(EntityTypeTags.POWDER_SNOW_WALKABLE_MOBS)) { + return true; + } else { + return entity instanceof LivingEntity && ((LivingEntity) entity).getEquippedStack(EquipmentSlot.FEET).isOf(Items.LEATHER_BOOTS); + } + } + + public ItemStack tryDrainFluid(@Nullable PlayerEntity player, WorldAccess world, BlockPos pos, BlockState state) { + world.setBlockState(pos, Blocks.AIR.getDefaultState(), Block.NOTIFY_ALL_AND_REDRAW); + if (!world.isClient()) { + world.syncWorldEvent(WorldEvents.BLOCK_BROKEN, pos, Block.getRawIdFromState(state)); + } + + return new ItemStack(Items.POWDER_SNOW_BUCKET); + } + + public Optional getBucketFillSound() { + return Optional.of(SoundEvents.ITEM_BUCKET_FILL_POWDER_SNOW); + } + + protected boolean canPathfindThrough(BlockState state, NavigationType type) { + return true; + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return VoxelShapes.empty(); // Optional: also prevents outline rendering + } +} diff --git a/src/main/java/net/voltexstudios/datagen/ModBlockTagProvider.java b/src/main/java/net/voltexstudios/datagen/ModBlockTagProvider.java new file mode 100644 index 0000000..8b9f88c --- /dev/null +++ b/src/main/java/net/voltexstudios/datagen/ModBlockTagProvider.java @@ -0,0 +1,23 @@ +package net.voltexstudios.datagen; + +import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.tag.BlockTags; +import net.voltexstudios.blocks.ModBlocks; + +import java.util.concurrent.CompletableFuture; + +public class ModBlockTagProvider extends FabricTagProvider.BlockTagProvider { + + public ModBlockTagProvider(FabricDataOutput output, CompletableFuture registriesFuture) { + super(output, registriesFuture); + } + + @Override + protected void configure(RegistryWrapper.WrapperLookup wrapperLookup) { + getOrCreateTagBuilder(BlockTags.LOGS_THAT_BURN) + .add(ModBlocks.PALM_LOG) + .add(ModBlocks.PALM_WOOD); + } +} diff --git a/src/main/java/net/voltexstudios/datagen/ModItemTagProvider.java b/src/main/java/net/voltexstudios/datagen/ModItemTagProvider.java new file mode 100644 index 0000000..dc5ca48 --- /dev/null +++ b/src/main/java/net/voltexstudios/datagen/ModItemTagProvider.java @@ -0,0 +1,26 @@ +package net.voltexstudios.datagen; + +import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.registry.tag.ItemTags; +import net.voltexstudios.blocks.ModBlocks; + +import java.util.concurrent.CompletableFuture; + +public class ModItemTagProvider extends FabricTagProvider.ItemTagProvider { + + public ModItemTagProvider(FabricDataOutput output, CompletableFuture completableFuture) { + super(output, completableFuture); + } + + @Override + protected void configure(RegistryWrapper.WrapperLookup wrapperLookup) { + getOrCreateTagBuilder(ItemTags.LOGS_THAT_BURN) + .add(ModBlocks.PALM_WOOD.asItem()) + .add(ModBlocks.PALM_LOG.asItem()); + + getOrCreateTagBuilder(ItemTags.PLANKS) + .add(ModBlocks.PALM_PLANKS.asItem()); + } +} diff --git a/src/main/java/net/voltexstudios/datagen/ModLootTableProvider.java b/src/main/java/net/voltexstudios/datagen/ModLootTableProvider.java new file mode 100644 index 0000000..595b96d --- /dev/null +++ b/src/main/java/net/voltexstudios/datagen/ModLootTableProvider.java @@ -0,0 +1,24 @@ +package net.voltexstudios.datagen; + +import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider; +import net.minecraft.registry.RegistryWrapper; +import net.voltexstudios.blocks.ModBlocks; + +import java.util.concurrent.CompletableFuture; + +public class ModLootTableProvider extends FabricBlockLootTableProvider { + + public ModLootTableProvider(FabricDataOutput dataOutput, CompletableFuture registryLookup) { + super(dataOutput, registryLookup); + } + + @Override + public void generate() { + addDrop(ModBlocks.PALM_LOG); + addDrop(ModBlocks.PALM_WOOD); + addDrop(ModBlocks.PALM_PLANKS); + addDrop(ModBlocks.PALM_SAPLING); + addDrop(ModBlocks.PALM_LEAVES, leavesDrops(ModBlocks.PALM_LEAVES, ModBlocks.PALM_SAPLING, 0.0625F)); + } +} diff --git a/src/main/java/net/voltexstudios/datagen/ModModelProvider.java b/src/main/java/net/voltexstudios/datagen/ModModelProvider.java new file mode 100644 index 0000000..4df4b2b --- /dev/null +++ b/src/main/java/net/voltexstudios/datagen/ModModelProvider.java @@ -0,0 +1,31 @@ +package net.voltexstudios.datagen; + +import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider; +import net.minecraft.data.client.BlockStateModelGenerator; +import net.minecraft.data.client.ItemModelGenerator; +import net.minecraft.data.client.Models; +import net.minecraft.data.client.TexturedModel; +import net.voltexstudios.blocks.ModBlocks; + +public class ModModelProvider extends FabricModelProvider { + + public ModModelProvider(FabricDataOutput output) { + super(output); + } + + @Override + public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) { + blockStateModelGenerator.registerLog(ModBlocks.PALM_LOG).log(ModBlocks.PALM_LOG).wood(ModBlocks.PALM_WOOD); + + blockStateModelGenerator.registerSimpleCubeAll(ModBlocks.QUICKSAND_BLOCK); + blockStateModelGenerator.registerSimpleCubeAll(ModBlocks.PALM_PLANKS); + blockStateModelGenerator.registerSingleton(ModBlocks.PALM_LEAVES, TexturedModel.LEAVES); + blockStateModelGenerator.registerTintableCrossBlockState(ModBlocks.PALM_SAPLING, BlockStateModelGenerator.TintType.NOT_TINTED); + } + + @Override + public void generateItemModels(ItemModelGenerator itemModelGenerator) { + itemModelGenerator.register(ModBlocks.PALM_SAPLING.asItem(), Models.GENERATED); + } +} diff --git a/src/main/java/net/voltexstudios/entity/custom/VultureEntity.java b/src/main/java/net/voltexstudios/entity/custom/VultureEntity.java index 4f9e2b4..bccae83 100644 --- a/src/main/java/net/voltexstudios/entity/custom/VultureEntity.java +++ b/src/main/java/net/voltexstudios/entity/custom/VultureEntity.java @@ -1,74 +1,201 @@ package net.voltexstudios.entity.custom; -import net.minecraft.entity.AnimationState; import net.minecraft.entity.EntityType; -import net.minecraft.entity.ai.goal.LookAroundGoal; -import net.minecraft.entity.ai.goal.LookAtEntityGoal; -import net.minecraft.entity.ai.goal.WanderAroundGoal; +import net.minecraft.entity.ai.TargetPredicate; +import net.minecraft.entity.ai.control.FlightMoveControl; +import net.minecraft.entity.ai.goal.*; +import net.minecraft.entity.ai.pathing.BirdNavigation; +import net.minecraft.entity.ai.pathing.EntityNavigation; import net.minecraft.entity.attribute.DefaultAttributeContainer; import net.minecraft.entity.attribute.EntityAttributes; -import net.minecraft.entity.mob.MobEntity; -import net.minecraft.entity.passive.AnimalEntity; -import net.minecraft.entity.passive.PassiveEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.server.world.ServerWorld; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.passive.RabbitEntity; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.Heightmap; import net.minecraft.world.World; -import net.voltexstudios.entity.ModEntities; -import org.jetbrains.annotations.Nullable; -public class VultureEntity extends AnimalEntity { +import java.util.EnumSet; +import java.util.Random; - public final AnimationState idleAnimationState = new AnimationState(); - private int idleAnimationTimeout; +public class VultureEntity extends HostileEntity { - public VultureEntity(EntityType entityType, World world) { + private static final double STANDARD_FLIGHT_HEIGHT = 20; + private static final double STANDARD_FLIGHT_SPEED = 1.5; + private static final double FORWARD_SPEED = 0.2; + + public VultureEntity(EntityType entityType, World world) { super(entityType, world); + this.moveControl = new FlightMoveControl(this, 20, true); + } + + @Override + protected EntityNavigation createNavigation(World world) { + BirdNavigation navigation = new BirdNavigation(this, world); + navigation.setCanPathThroughDoors(false); + navigation.setCanSwim(true); + return navigation; } @Override protected void initGoals() { - this.goalSelector.add(0, new WanderAroundGoal(this, 1.0)); - this.goalSelector.add(1, new LookAtEntityGoal(this, PlayerEntity.class, 6.0F)); - this.goalSelector.add(2, new LookAroundGoal(this)); + this.goalSelector.add(1, new SwimGoal(this)); + this.goalSelector.add(2, new RabbitHunterGoal(this)); + this.goalSelector.add(2, new FlyGoal(this, 2 * STANDARD_FLIGHT_SPEED)); + + this.goalSelector.add(3, new LookAroundGoal(this)); + + this.goalSelector.add(4, new ForwardFlightGoal(this)); + this.goalSelector.add(4, new MaintainHeightGoal(this, STANDARD_FLIGHT_HEIGHT)); + + + this.targetSelector.add(2, new ActiveTargetGoal<>(this, RabbitEntity.class, true)); } - private void setupAnimationStates() { - if (this.idleAnimationTimeout <= 0) { - this.idleAnimationTimeout = 40; - this.idleAnimationState.start(this.age); - } else { - --this.idleAnimationTimeout; + private static class ForwardFlightGoal extends Goal { + private final VultureEntity vulture; + + public ForwardFlightGoal(VultureEntity vulture) { + this.vulture = vulture; + this.setControls(EnumSet.of(Goal.Control.MOVE)); + } + + @Override + public boolean canStart() { + return !vulture.isOnGround(); + } + + @Override + public void tick() { + Vec3d rotation = vulture.getRotationVector(); + Vec3d movement = rotation.multiply(FORWARD_SPEED); + + vulture.setVelocity(movement.x, vulture.getVelocity().y, movement.z); + } + } + + private static class MaintainHeightGoal extends Goal { + private final VultureEntity vulture; + private final double targetHeight; + + public MaintainHeightGoal(VultureEntity vulture, double height) { + this.vulture = vulture; + this.targetHeight = height; + } + + @Override + public boolean canStart() { + return true; + } + + @Override + public void tick() { + double currentY = vulture.getY(); + double groundLevel = vulture.getWorld().getTopY(Heightmap.Type.WORLD_SURFACE, vulture.getBlockPos().getX(), vulture.getBlockPos().getZ()); + double desiredY = groundLevel + targetHeight; + + desiredY += new Random().nextDouble() * 5; + + if (Math.abs(currentY - desiredY) > 1.0) { + vulture.getMoveControl().moveTo( + vulture.getX(), + desiredY, + vulture.getZ(), + STANDARD_FLIGHT_SPEED + ); + } } } @Override - public void tick() { - super.tick(); + public void fall(double heightDifference, boolean onGroundIn, net.minecraft.block.BlockState state, net.minecraft.util.math.BlockPos pos) { + // Kein Fallschaden für den Geier + } - if (this.getWorld().isClient()) { - this.setupAnimationStates(); + public static DefaultAttributeContainer.Builder createVultureAttributes() { + return HostileEntity.createHostileAttributes() + .add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0) + .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.3) + .add(EntityAttributes.GENERIC_FLYING_SPEED, STANDARD_FLIGHT_SPEED) + .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 4.0); + } + + // Benutzerdefinierte Zielklasse zum Jagen von Hasen + private static class RabbitHunterGoal extends Goal { + private final VultureEntity vulture; + private RabbitEntity targetRabbit; + + public RabbitHunterGoal(VultureEntity vulture) { + this.vulture = vulture; + } + + @Override + public boolean canStart() { + this.targetRabbit = findNearestRabbit(); + return this.targetRabbit != null; + } + + @Override + public void tick() { + if (targetRabbit != null) { + // Luftangriff auf den Hasen + vulture.getNavigation().startMovingTo( + targetRabbit.getX(), + targetRabbit.getY() + 1.5, + targetRabbit.getZ(), + 1.2 + ); + + // Angriff, wenn nah genug + if (vulture.distanceTo(targetRabbit) < 2.0) { + vulture.tryAttack(targetRabbit); + } + } + } + + private RabbitEntity findNearestRabbit() { + return vulture.getWorld().getClosestEntity( + RabbitEntity.class, + TargetPredicate.DEFAULT, + vulture, + vulture.getX(), + vulture.getY(), + vulture.getZ(), + vulture.getBoundingBox().expand(25.0) + ); } } - //TODO alter attributes - public static DefaultAttributeContainer.Builder createAttributes() { - return MobEntity.createMobAttributes() - .add(EntityAttributes.GENERIC_MAX_HEALTH, 10.0) - .add(EntityAttributes.GENERIC_FLYING_SPEED, 1.5F) - .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.6F) - .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 10.0) - .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 48.0); - } + // Benutzerdefinierte Zielklasse für Kreisflugverhalten + private static class CircularFlightGoal extends Goal { + private final VultureEntity vulture; + private double circleX, circleZ; + private double angle = 0; - @Override - public boolean isBreedingItem(ItemStack stack) { - return false; - } + public CircularFlightGoal(VultureEntity vulture) { + this.vulture = vulture; + this.setControls(EnumSet.of(Goal.Control.MOVE)); + } - @Nullable - @Override - public PassiveEntity createChild(ServerWorld world, PassiveEntity entity) { - return ModEntities.VULTURE_ENTITY.create(world); + @Override + public boolean canStart() { + // Kreisflug, wenn nicht auf der Jagd + return !vulture.getNavigation().isIdle(); + } + + @Override + public void tick() { + // Kreisfluglogik + angle += 0.1; + double radius = 5.0; + circleX = vulture.getX() + Math.cos(angle) * radius; + circleZ = vulture.getZ() + Math.sin(angle) * radius; + + vulture.getMoveControl().moveTo( + circleX, + vulture.getY() + 3, + circleZ, + STANDARD_FLIGHT_SPEED + ); + } } } diff --git a/src/main/java/net/voltexstudios/item/ModItemGroups.java b/src/main/java/net/voltexstudios/item/ModItemGroups.java new file mode 100644 index 0000000..184de7d --- /dev/null +++ b/src/main/java/net/voltexstudios/item/ModItemGroups.java @@ -0,0 +1,33 @@ +package net.voltexstudios.item; + +import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.voltexstudios.VoltexDesertUpdate; +import net.voltexstudios.blocks.ModBlocks; + +public class ModItemGroups { + + public static final ItemGroup DESERT_UPDATE_GROUP = Registry.register(Registries.ITEM_GROUP, + Identifier.of(VoltexDesertUpdate.MOD_ID, "desert_update"), + FabricItemGroup.builder().icon(() -> new ItemStack(ModItems.DUNE_STAFF)) + .displayName(Text.translatable("itemgroup.voltexdesertupdate.desert_update")) + .entries((displayContext, entries) -> { + entries.add(ModItems.DUNE_STAFF); + + entries.add(ModBlocks.QUICKSAND_BLOCK); + entries.add(ModBlocks.PALM_WOOD); + entries.add(ModBlocks.PALM_PLANKS); + entries.add(ModBlocks.PALM_LEAVES); + entries.add(ModBlocks.PALM_SAPLING); + entries.add(ModBlocks.PALM_LOG); + }).build()); + + public static void registerItemGroups() { + VoltexDesertUpdate.LOGGER.info("Registering Item Groups for " + VoltexDesertUpdate.MOD_ID); + } +} diff --git a/src/main/java/net/voltexstudios/world/ModConfiguredFeatures.java b/src/main/java/net/voltexstudios/world/ModConfiguredFeatures.java new file mode 100644 index 0000000..7bc61da --- /dev/null +++ b/src/main/java/net/voltexstudios/world/ModConfiguredFeatures.java @@ -0,0 +1,44 @@ +package net.voltexstudios.world; + +import net.minecraft.block.Blocks; +import net.minecraft.registry.Registerable; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.intprovider.ConstantIntProvider; +import net.minecraft.util.math.intprovider.UniformIntProvider; +import net.minecraft.world.gen.feature.*; +import net.minecraft.world.gen.feature.size.TwoLayersFeatureSize; +import net.minecraft.world.gen.foliage.AcaciaFoliagePlacer; +import net.minecraft.world.gen.stateprovider.BlockStateProvider; +import net.minecraft.world.gen.trunk.BendingTrunkPlacer; +import net.voltexstudios.VoltexDesertUpdate; +import net.voltexstudios.blocks.ModBlocks; + +public class ModConfiguredFeatures { + + public static final RegistryKey> PALM_KEY = registerKey("palm"); + + public static void bootstrap(Registerable> context) { + + register(context, PALM_KEY, Feature.TREE, new TreeFeatureConfig.Builder( + BlockStateProvider.of(ModBlocks.PALM_LOG), + new BendingTrunkPlacer(3, 2, 0, 4, UniformIntProvider.create(1, 2)), + BlockStateProvider.of(ModBlocks.PALM_LEAVES), + new AcaciaFoliagePlacer(ConstantIntProvider.create(3), ConstantIntProvider.create(1)), + + new TwoLayersFeatureSize(1, 0, 2)) + .build() + ); + + } + + public static RegistryKey> registerKey(String name) { + return RegistryKey.of(RegistryKeys.CONFIGURED_FEATURE, Identifier.of(VoltexDesertUpdate.MOD_ID, name)); + } + + private static > void register(Registerable> context, + RegistryKey> key, F feature, FC configuration) { + context.register(key, new ConfiguredFeature<>(feature, configuration)); + } +} diff --git a/src/main/java/net/voltexstudios/world/ModPlacedFeatures.java b/src/main/java/net/voltexstudios/world/ModPlacedFeatures.java new file mode 100644 index 0000000..f996908 --- /dev/null +++ b/src/main/java/net/voltexstudios/world/ModPlacedFeatures.java @@ -0,0 +1,43 @@ +package net.voltexstudios.world; + +import net.minecraft.registry.Registerable; +import net.minecraft.registry.RegistryKey; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.util.Identifier; +import net.minecraft.world.gen.feature.*; +import net.minecraft.world.gen.placementmodifier.*; +import net.voltexstudios.VoltexDesertUpdate; +import net.voltexstudios.blocks.ModBlocks; + +import java.util.List; + +public class ModPlacedFeatures { + + public static final RegistryKey PALM_PLACED_KEY = registerKey("palm_placed"); + + public static void bootstrap(Registerable context) { + var configuredFeatures = context.getRegistryLookup(RegistryKeys.CONFIGURED_FEATURE); + + + register(context, PALM_PLACED_KEY, configuredFeatures.getOrThrow(ModConfiguredFeatures.PALM_KEY), + VegetationPlacedFeatures.treeModifiersWithWouldSurvive( + PlacedFeatures.createCountExtraModifier(2, 0.1f, 2), ModBlocks.PALM_SAPLING)); + + } + + public static RegistryKey registerKey(String name) { + return RegistryKey.of(RegistryKeys.PLACED_FEATURE, Identifier.of(VoltexDesertUpdate.MOD_ID, name)); + } + + private static void register(Registerable context, RegistryKey key, RegistryEntry> configuration, + List modifiers) { + context.register(key, new PlacedFeature(configuration, List.copyOf(modifiers))); + } + + private static > void register(Registerable context, RegistryKey key, + RegistryEntry> configuration, + PlacementModifier... modifiers) { + register(context, key, configuration, List.of(modifiers)); + } +} diff --git a/src/main/java/net/voltexstudios/world/tree/ModSaplingGenerators.java b/src/main/java/net/voltexstudios/world/tree/ModSaplingGenerators.java new file mode 100644 index 0000000..c6daf90 --- /dev/null +++ b/src/main/java/net/voltexstudios/world/tree/ModSaplingGenerators.java @@ -0,0 +1,13 @@ +package net.voltexstudios.world.tree; + +import net.minecraft.block.SaplingGenerator; +import net.voltexstudios.VoltexDesertUpdate; +import net.voltexstudios.world.ModConfiguredFeatures; + +import java.util.Optional; + +public class ModSaplingGenerators { + + public static final SaplingGenerator PALM = new SaplingGenerator(VoltexDesertUpdate.MOD_ID + ":palm", + Optional.empty(), Optional.of(ModConfiguredFeatures.PALM_KEY), Optional.empty()); +} diff --git a/src/main/resources/assets/voltexdesertupdate/lang/en_us.json b/src/main/resources/assets/voltexdesertupdate/lang/en_us.json index 8caf65a..0f27fb0 100644 --- a/src/main/resources/assets/voltexdesertupdate/lang/en_us.json +++ b/src/main/resources/assets/voltexdesertupdate/lang/en_us.json @@ -1,5 +1,15 @@ { "item.voltexdesertupdate.dune_staff": "Staff of the Dunes", - "entity.voltexdesertupdate.vulture": "Vulture" + "entity.voltexdesertupdate.vulture": "Vulture", + + "itemgroup.voltexdesertupdate.desert_update": "Desert Update", + + "block.voltexdesertupdate.quicksand_block": "Quicksand Block", + "block.voltexdesertupdate.palm_log": "Palm Log", + "block.voltexdesertupdate.palm_wood": "Palm Wood", + "block.voltexdesertupdate.palm_planks": "Palm Planks", + "block.voltexdesertupdate.palm_leaves": "Palm Leaves", + "block.voltexdesertupdate.palm_sapling": "Palm Sapling" + } \ No newline at end of file diff --git a/src/main/resources/assets/voltexdesertupdate/textures/block/palm_leaves.png b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_leaves.png new file mode 100644 index 0000000..0f30d36 Binary files /dev/null and b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_leaves.png differ diff --git a/src/main/resources/assets/voltexdesertupdate/textures/block/palm_log.png b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_log.png new file mode 100644 index 0000000..473d5a9 Binary files /dev/null and b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_log.png differ diff --git a/src/main/resources/assets/voltexdesertupdate/textures/block/palm_log_top.png b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_log_top.png new file mode 100644 index 0000000..fbafe6d Binary files /dev/null and b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_log_top.png differ diff --git a/src/main/resources/assets/voltexdesertupdate/textures/block/palm_sapling.png b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_sapling.png new file mode 100644 index 0000000..2ac1e85 Binary files /dev/null and b/src/main/resources/assets/voltexdesertupdate/textures/block/palm_sapling.png differ diff --git a/src/main/resources/assets/voltexdesertupdate/textures/block/quicksand_block.png b/src/main/resources/assets/voltexdesertupdate/textures/block/quicksand_block.png new file mode 100644 index 0000000..b03c96b Binary files /dev/null and b/src/main/resources/assets/voltexdesertupdate/textures/block/quicksand_block.png differ diff --git a/src/main/resources/assets/voltexdesertupdate/textures/item/palm_sapling.png b/src/main/resources/assets/voltexdesertupdate/textures/item/palm_sapling.png new file mode 100644 index 0000000..2ac1e85 Binary files /dev/null and b/src/main/resources/assets/voltexdesertupdate/textures/item/palm_sapling.png differ diff --git a/src/main/resources/voltexdesertupdate.mixins.json b/src/main/resources/voltexdesertupdate.mixins.json index abac702..25ae644 100644 --- a/src/main/resources/voltexdesertupdate.mixins.json +++ b/src/main/resources/voltexdesertupdate.mixins.json @@ -1,11 +1,15 @@ { - "required": true, - "package": "net.voltexstudios.mixin", - "compatibilityLevel": "JAVA_21", - "mixins": [ - "ExampleMixin" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "package": "net.voltexstudios.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "ExampleMixin", + "LivingEntityAccessor" + ], + "injectors": { + "defaultRequire": 1 + }, + "client": [ + "EntityMixin" + ] } \ No newline at end of file