diff --git a/README.md b/README.md index 532b715..2aa47d7 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,13 @@ Each player has a "personal" stage of an area, the highest online player's diffi - Neural Mobs Are Always Hostile ### Stage 6 +- Mobs No Longer Burn In Sunlight ### Technical Details Each player has a 6-element long list in their data. Each element in the list has a chunk position and time value. Every tick the player will first, find the stage element its current position is in, and increase the time value of that stage element. If the time value when increased is over 24,000 ticks the next stage element will have its chunk set to the players current position, have its time value reset, the old stage element will have the next stage element's old chunk, and have its time value reset. To determine if a player is in a stage element, it checks if the player is within 16 chunks of the stage element's chunk, it starts searching at the last element, ending at the first. The "effective" stage element of a chunk can be found by searching every **online** player for their stage element for the chunk and then picking the highest value. +## End Rods +Most hostile mobs are afraid of End Rods. + ## Credits Thanks to ```sirikaros``` for the backpack textures! \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index db6c0f4..4f8b140 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs = -Xmx1G # Fabric Properties # check these on https://fabricmc.net/use - minecraft_version = 1.16-pre5 + minecraft_version = 1.16-pre6 yarn_build = 1 fabric_loader_version = 0.8.7+build.201 @@ -13,5 +13,4 @@ org.gradle.jvmargs = -Xmx1G # Dependencies # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api - fabric_api_version = 0.12.1+build.361-1.16 - cardinal_components_version = 2.4.0-nightly.1.16-pre4 + fabric_api_version = 0.12.2+build.362-1.16 diff --git a/src/main/java/com/thebrokenrail/twine/Twine.java b/src/main/java/com/thebrokenrail/twine/Twine.java index 21c1250..ecab97b 100644 --- a/src/main/java/com/thebrokenrail/twine/Twine.java +++ b/src/main/java/com/thebrokenrail/twine/Twine.java @@ -2,6 +2,7 @@ package com.thebrokenrail.twine; import com.thebrokenrail.twine.advancement.ChestBoatCriterion; import com.thebrokenrail.twine.advancement.EnderChestBoatCriterion; +import com.thebrokenrail.twine.block.CreativeItemSpawnerBlock; import com.thebrokenrail.twine.block.GlowingObsidianBlock; import com.thebrokenrail.twine.item.BackpackItem; import com.thebrokenrail.twine.item.DivinerItem; @@ -11,10 +12,7 @@ import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; import net.fabricmc.fabric.api.container.ContainerProviderRegistry; import net.fabricmc.fabric.api.tag.TagRegistry; import net.minecraft.block.Block; -import net.minecraft.item.BlockItem; -import net.minecraft.item.Item; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; +import net.minecraft.item.*; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.ScreenHandlerType; import net.minecraft.tag.Tag; @@ -27,6 +25,8 @@ public class Twine implements ModInitializer { public static final GlowingObsidianBlock GLOWING_OBSIDIAN = new GlowingObsidianBlock(); + public static final CreativeItemSpawnerBlock CREATIVE_ITEM_SPAWNER_BLOCK = new CreativeItemSpawnerBlock(); + public static final ItemGroup ITEM_GROUP = FabricItemGroupBuilder.build(new Identifier(NAMESPACE, "item_group"), () -> new ItemStack(GLOWING_OBSIDIAN)); public static final Identifier BACKPACK_SCREEN = new Identifier(NAMESPACE, "backpack"); @@ -59,5 +59,8 @@ public class Twine implements ModInitializer { Registry.register(Registry.BLOCK, new Identifier(NAMESPACE, "glowing_obsidian"), GLOWING_OBSIDIAN); Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "glowing_obsidian"), new BlockItem(GLOWING_OBSIDIAN, new Item.Settings().group(ITEM_GROUP))); + + Registry.register(Registry.BLOCK, new Identifier(NAMESPACE, "creative_item_spawner"), CREATIVE_ITEM_SPAWNER_BLOCK); + Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "creative_item_spawner"), new BlockItem(CREATIVE_ITEM_SPAWNER_BLOCK, new Item.Settings().group(ITEM_GROUP))); } } diff --git a/src/main/java/com/thebrokenrail/twine/block/CreativeItemSpawnerBlock.java b/src/main/java/com/thebrokenrail/twine/block/CreativeItemSpawnerBlock.java new file mode 100644 index 0000000..f93bc13 --- /dev/null +++ b/src/main/java/com/thebrokenrail/twine/block/CreativeItemSpawnerBlock.java @@ -0,0 +1,94 @@ +package com.thebrokenrail.twine.block; + +import net.minecraft.block.*; +import net.minecraft.block.dispenser.DispenserBehavior; +import net.minecraft.block.dispenser.ItemDispenserBehavior; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.state.property.DirectionProperty; +import net.minecraft.state.property.Properties; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.math.BlockPointer; +import net.minecraft.util.math.BlockPointerImpl; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; + +import java.util.Random; + +@SuppressWarnings("deprecation") +public class CreativeItemSpawnerBlock extends Block { + public static final DirectionProperty FACING = DispenserBlock.FACING; + public static final BooleanProperty TRIGGERED = Properties.TRIGGERED; + + public CreativeItemSpawnerBlock() { + super(Settings.of(Material.STONE).strength(-1.0F, 3600000.0F).dropsNothing()); + setDefaultState(stateManager.getDefaultState().with(FACING, Direction.SOUTH).with(TRIGGERED, false)); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + builder.add(FACING, TRIGGERED); + } + + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(FACING, rotation.rotate(state.get(FACING))); + } + + @Override + public BlockState mirror(BlockState state, BlockMirror mirror) { + return state.rotate(mirror.getRotation(state.get(FACING))); + } + + @Override + public void neighborUpdate(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean notify) { + boolean bl = world.isReceivingRedstonePower(pos) || world.isReceivingRedstonePower(pos.up()); + boolean bl2 = state.get(TRIGGERED); + if (bl && !bl2) { + world.getBlockTickScheduler().schedule(pos, this, 4); + world.setBlockState(pos, state.with(TRIGGERED, true), 4); + } else if (!bl && bl2) { + world.setBlockState(pos, state.with(TRIGGERED, false), 4); + } + } + + @Override + public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) { + dispense(world, pos, state); + } + + private void dispense(World world, BlockPos pos, BlockState state) { + DispenserBehavior behavior = new ItemDispenserBehavior() { + @Override + protected void playSound(BlockPointer pointer) { + pointer.getWorld().playSound(null, pointer.getBlockPos(), SoundEvents.ENTITY_ENDERMAN_TELEPORT, SoundCategory.BLOCKS, 1f, 1f); + } + }; + BlockPos invPos = pos.offset(state.get(FACING).getOpposite()); + BlockEntity entity = world.getBlockEntity(invPos); + if (entity instanceof Inventory) { + BlockPointerImpl blockPointerImpl = new BlockPointerImpl(world, pos); + int size = ((Inventory) entity).size(); + for (int i = 0; i < size; i++) { + ItemStack stack = ((Inventory) entity).getStack(i).copy(); + while (!stack.isEmpty()) { + stack = behavior.dispense(blockPointerImpl, stack); + } + } + } + } + + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return getDefaultState().with(FACING, ctx.getSide()); + } +} diff --git a/src/main/java/com/thebrokenrail/twine/block/GlowingObsidianBlock.java b/src/main/java/com/thebrokenrail/twine/block/GlowingObsidianBlock.java index 6317aee..863e5ca 100644 --- a/src/main/java/com/thebrokenrail/twine/block/GlowingObsidianBlock.java +++ b/src/main/java/com/thebrokenrail/twine/block/GlowingObsidianBlock.java @@ -20,7 +20,7 @@ public class GlowingObsidianBlock extends Block { public void onSteppedOn(World world, BlockPos pos, Entity entity) { super.onSteppedOn(world, pos, entity); if (entity instanceof LivingEntity && entity.age % 5 == 0) { - final float amount = 1f; + final float amount = 2f; if (entity instanceof Monster) { ((LivingEntity) entity).heal(amount); } else { diff --git a/src/main/java/com/thebrokenrail/twine/entity/FleeEndRodGoal.java b/src/main/java/com/thebrokenrail/twine/entity/FleeEndRodGoal.java new file mode 100644 index 0000000..a8b51c7 --- /dev/null +++ b/src/main/java/com/thebrokenrail/twine/entity/FleeEndRodGoal.java @@ -0,0 +1,108 @@ +package com.thebrokenrail.twine.entity; + +import net.minecraft.block.Blocks; +import net.minecraft.entity.ai.TargetFinder; +import net.minecraft.entity.ai.goal.Goal; +import net.minecraft.entity.ai.pathing.Path; +import net.minecraft.entity.mob.MobEntityWithAi; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.WorldView; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkStatus; + +public class FleeEndRodGoal extends Goal { + private final MobEntityWithAi mob; + private Vec3d targetPos; + + private Path fleePath; + + private static final int RANGE = 16; + private static final int MAX_Y_DIFFERENCE = 7; + + public FleeEndRodGoal(MobEntityWithAi mob) { + super(); + this.mob = mob; + } + + boolean isTargetPos(WorldView world, BlockPos pos) { + Chunk chunk = world.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, false); + if (chunk == null) { + return false; + } else { + return chunk.getBlockState(pos).isOf(Blocks.END_ROD); + } + } + + private boolean findTargetPos() { + BlockPos blockPos = mob.getBlockPos(); + BlockPos.Mutable mutable = new BlockPos.Mutable(); + + for (int k = 0; k <= MAX_Y_DIFFERENCE; k = k > 0 ? -k : 1 - k) { + for (int l = 0; l < RANGE; ++l) { + for (int m = 0; m <= l; m = m > 0 ? -m : 1 - m) { + for (int n = m < l && m > -l ? l : 0; n <= l; n = n > 0 ? -n : 1 - n) { + mutable.set(blockPos, m, k - 1, n); + if (mob.isInWalkTargetRange(mutable) && isTargetPos(mob.world, mutable)) { + targetPos = new Vec3d(mutable.getX() + 0.5d, mutable.getY(), mutable.getZ() + 0.5d); + return true; + } + } + } + } + } + + return false; + } + + private double squaredDistanceTo(Vec3d vector) { + double d = targetPos.x - vector.x; + double e = targetPos.y - vector.y; + double f = targetPos.z - vector.z; + return d * d + e * e + f * f; + } + + @Override + public boolean canStart() { + if (findTargetPos()) { + Vec3d vec3d = TargetFinder.findTargetAwayFrom(mob, RANGE * 2, MAX_Y_DIFFERENCE * 2, targetPos); + if (vec3d == null) { + return false; + } else if (squaredDistanceTo(vec3d) < mob.squaredDistanceTo(targetPos)) { + return false; + } else { + fleePath = mob.getNavigation().findPathTo(vec3d.x, vec3d.y, vec3d.z, 0); + return fleePath != null; + } + } else { + return false; + } + } + + @Override + public boolean shouldContinue() { + return !mob.getNavigation().isIdle(); + } + + @Override + public void start() { + mob.getNavigation().startMovingAlong(fleePath, SLOW_SPEED); + } + + @Override + public void stop() { + targetPos = null; + } + + private static final float SLOW_SPEED = 1.25f; + private static final float FAST_SPEED = 1.5f; + + @Override + public void tick() { + if (squaredDistanceTo(mob.getPos()) < (RANGE / 2d)) { + mob.getNavigation().setSpeed(FAST_SPEED); + } else { + mob.getNavigation().setSpeed(SLOW_SPEED); + } + } +} diff --git a/src/main/java/com/thebrokenrail/twine/mixin/MixinMobEntity.java b/src/main/java/com/thebrokenrail/twine/mixin/MixinMobEntity.java index 199cdfc..bbcf14c 100644 --- a/src/main/java/com/thebrokenrail/twine/mixin/MixinMobEntity.java +++ b/src/main/java/com/thebrokenrail/twine/mixin/MixinMobEntity.java @@ -2,6 +2,7 @@ package com.thebrokenrail.twine.mixin; import com.thebrokenrail.twine.component.StageDataComponent; import com.thebrokenrail.twine.entity.ExplodeArtificialBlockGoal; +import com.thebrokenrail.twine.entity.FleeEndRodGoal; import com.thebrokenrail.twine.entity.FollowPassiveEntityGoal; import com.thebrokenrail.twine.entity.StandOnGlowingObsidian; import net.minecraft.entity.EntityType; @@ -19,6 +20,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @SuppressWarnings("ConstantConditions") @Mixin(MobEntity.class) @@ -37,6 +39,7 @@ public class MixinMobEntity { if (this instanceof Monster) { if ((Object) this instanceof MobEntityWithAi) { goalSelector.add(1, new StandOnGlowingObsidian((MobEntityWithAi) (Object) this)); + goalSelector.add(3, new FleeEndRodGoal((MobEntityWithAi) (Object) this)); if ((Object) this instanceof CreeperEntity) { goalSelector.add(3, new ExplodeArtificialBlockGoal((MobEntityWithAi) (Object) this)); } @@ -53,4 +56,14 @@ public class MixinMobEntity { } } } + + @Inject(at = @At("HEAD"), method = "isInDaylight", cancellable = true) + public void isInDaylight(CallbackInfoReturnable info) { + StageDataComponent component = StageDataComponent.getFromWorld((ServerWorld) ((ZombieEntity) (Object) this).getEntityWorld()); + ChunkPos chunkPos = new ChunkPos(((ZombieEntity) (Object) this).getBlockPos()); + int stage = component.findEffectiveStageOfChunk((ServerWorld) ((ZombieEntity) (Object) this).getEntityWorld(), chunkPos); + if (stage >= 5) { + info.setReturnValue(false); + } + } } diff --git a/src/main/resources/assets/twine/blockstates/creative_item_spawner.json b/src/main/resources/assets/twine/blockstates/creative_item_spawner.json new file mode 100644 index 0000000..43bd2b0 --- /dev/null +++ b/src/main/resources/assets/twine/blockstates/creative_item_spawner.json @@ -0,0 +1,27 @@ +{ + "variants": { + "facing=down": { + "model": "twine:block/creative_item_spawner", + "x": 90 + }, + "facing=east": { + "model": "twine:block/creative_item_spawner", + "y": 90 + }, + "facing=north": { + "model": "twine:block/creative_item_spawner" + }, + "facing=south": { + "model": "twine:block/creative_item_spawner", + "y": 180 + }, + "facing=up": { + "model": "twine:block/creative_item_spawner", + "x": 270 + }, + "facing=west": { + "model": "twine:block/creative_item_spawner", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/twine/lang/en_us.json b/src/main/resources/assets/twine/lang/en_us.json index b0d093e..058e02f 100644 --- a/src/main/resources/assets/twine/lang/en_us.json +++ b/src/main/resources/assets/twine/lang/en_us.json @@ -6,6 +6,8 @@ "block.twine.glowing_obsidian": "Glowing Obsidian", + "block.twine.creative_item_spawner": "Creative Item Spawner", + "advancements.twine.root.title": "Twine", "advancements.twine.root.description": "A simple survival mod for Minecraft encouraging a nomadic lifestyle", diff --git a/src/main/resources/assets/twine/models/block/creative_item_spawner.json b/src/main/resources/assets/twine/models/block/creative_item_spawner.json new file mode 100644 index 0000000..eacc938 --- /dev/null +++ b/src/main/resources/assets/twine/models/block/creative_item_spawner.json @@ -0,0 +1,12 @@ +{ + "parent": "minecraft:block/cube", + "textures": { + "particle": "twine:block/creative_item_spawner_side", + "down": "twine:block/creative_item_spawner_side", + "up": "twine:block/creative_item_spawner_side", + "north": "twine:block/creative_item_spawner_front", + "east": "twine:block/creative_item_spawner_side", + "south": "twine:block/creative_item_spawner_back", + "west": "twine:block/creative_item_spawner_side" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/twine/models/item/creative_item_spawner.json b/src/main/resources/assets/twine/models/item/creative_item_spawner.json new file mode 100644 index 0000000..47da3c6 --- /dev/null +++ b/src/main/resources/assets/twine/models/item/creative_item_spawner.json @@ -0,0 +1,3 @@ +{ + "parent": "twine:block/creative_item_spawner" +} \ No newline at end of file diff --git a/src/main/resources/assets/twine/textures/block/creative_item_spawner_back.png b/src/main/resources/assets/twine/textures/block/creative_item_spawner_back.png new file mode 100644 index 0000000..d77f01a Binary files /dev/null and b/src/main/resources/assets/twine/textures/block/creative_item_spawner_back.png differ diff --git a/src/main/resources/assets/twine/textures/block/creative_item_spawner_front.png b/src/main/resources/assets/twine/textures/block/creative_item_spawner_front.png new file mode 100644 index 0000000..3536d51 Binary files /dev/null and b/src/main/resources/assets/twine/textures/block/creative_item_spawner_front.png differ diff --git a/src/main/resources/assets/twine/textures/block/creative_item_spawner_side.png b/src/main/resources/assets/twine/textures/block/creative_item_spawner_side.png new file mode 100644 index 0000000..97d8045 Binary files /dev/null and b/src/main/resources/assets/twine/textures/block/creative_item_spawner_side.png differ diff --git a/src/main/resources/assets/twine/textures/item/diviner.png b/src/main/resources/assets/twine/textures/item/diviner.png index 659d237..3217c00 100644 Binary files a/src/main/resources/assets/twine/textures/item/diviner.png and b/src/main/resources/assets/twine/textures/item/diviner.png differ diff --git a/src/main/resources/assets/twine/textures/item/diviner.png.mcmeta b/src/main/resources/assets/twine/textures/item/diviner.png.mcmeta deleted file mode 100644 index 1d13ee1..0000000 --- a/src/main/resources/assets/twine/textures/item/diviner.png.mcmeta +++ /dev/null @@ -1,6 +0,0 @@ -{ - "animation": { - "interpolate": true, - "frametime": 64 - } -} \ No newline at end of file diff --git a/src/main/resources/data/twine/recipes/diviner.json b/src/main/resources/data/twine/recipes/diviner.json index 0b24571..a9a824c 100644 --- a/src/main/resources/data/twine/recipes/diviner.json +++ b/src/main/resources/data/twine/recipes/diviner.json @@ -14,7 +14,7 @@ } }, "result": { - "item": "twine:small_diviner", + "item": "twine:diviner", "count": 1 } } \ No newline at end of file