Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
at master 366 lines 13 kB view raw
1package net.lerariemann.infinity.entity.custom; 2 3import net.lerariemann.infinity.block.custom.AntBlock; 4import net.lerariemann.infinity.util.VersionMethods; 5import net.lerariemann.infinity.util.core.NbtUtils; 6import net.lerariemann.infinity.util.var.BishopBattle; 7import net.minecraft.core.BlockPos; 8import net.minecraft.core.Direction; 9import net.minecraft.nbt.CompoundTag; 10import net.minecraft.resources.ResourceKey; 11import net.minecraft.server.level.ServerLevel; 12import net.minecraft.sounds.SoundEvent; 13import net.minecraft.sounds.SoundEvents; 14import net.minecraft.tags.FluidTags; 15import net.minecraft.world.InteractionHand; 16import net.minecraft.world.InteractionResult; 17import net.minecraft.world.damagesource.DamageSource; 18import net.minecraft.world.entity.Entity; 19import net.minecraft.world.entity.EntityType; 20import net.minecraft.world.entity.LivingEntity; 21import net.minecraft.world.entity.Mob; 22import net.minecraft.world.entity.ai.attributes.AttributeSupplier; 23import net.minecraft.world.entity.ai.attributes.Attributes; 24import net.minecraft.world.entity.ai.goal.FloatGoal; 25import net.minecraft.world.entity.ai.goal.Goal; 26import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; 27import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; 28import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; 29import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; 30import net.minecraft.world.entity.monster.Monster; 31import net.minecraft.world.entity.player.Player; 32import net.minecraft.world.item.ItemStack; 33import net.minecraft.world.level.Level; 34import net.minecraft.world.level.block.Block; 35import net.minecraft.world.level.block.state.BlockState; 36import net.minecraft.world.level.material.FluidState; 37//? if >1.21.4 { 38import net.minecraft.world.level.storage.ValueInput; 39import net.minecraft.world.level.storage.ValueOutput; 40//?} 41import net.minecraft.world.level.storage.loot.LootParams; 42import net.minecraft.world.level.storage.loot.LootTable; 43import net.minecraft.world.phys.Vec3; 44import net.minecraft.world.phys.shapes.CollisionContext; 45import net.minecraft.world.phys.shapes.VoxelShape; 46import org.jetbrains.annotations.Nullable; 47 48import java.util.Optional; 49import java.util.function.BiConsumer; 50import java.util.function.Function; 51 52public class AntEntity extends AbstractChessFigure { 53 @Nullable 54 protected BlockPos lastChangedPos; 55 private Direction direction; 56 private boolean dropsLoot; 57 58 public AntEntity(EntityType<? extends AbstractChessFigure> entityType, Level world) { 59 super(entityType, world); 60 direction = Direction.EAST; 61 dropsLoot = true; 62 } 63 64 @Override 65 public boolean isBlackOrWhite() { 66 return true; 67 } 68 //? if <1.21.2 { 69 /*@Override 70 public boolean shouldDropLoot() { 71 return dropsLoot; 72 } 73 *///?} else { 74 @Override 75 protected boolean dropFromLootTable(ServerLevel level, ResourceKey<LootTable> lootTable, Function<LootParams.Builder, LootParams> paramsBuilder, BiConsumer<ServerLevel, ItemStack> dropConsumer) { 76 if (dropsLoot) 77 return super.dropFromLootTable(level, lootTable, paramsBuilder, dropConsumer); 78 return false; 79 } 80 //?} 81 82 public void addToBattle(BishopBattle battle) { 83 battle.addEntity(this); 84 dropsLoot = false; 85 } 86 87 @Override 88 protected SoundEvent getAmbientSound() { 89 return null; 90 } 91 @Override 92 protected SoundEvent getHurtSound(DamageSource source) { 93 return SoundEvents.SILVERFISH_HURT; 94 } 95 @Override 96 protected SoundEvent getDeathSound() { 97 return SoundEvents.SILVERFISH_DEATH; 98 } 99 100 @Override 101 protected void registerGoals() { 102 targetSelector.addGoal(2, new AntBattleGoal<>(this, Player.class, true)); 103 goalSelector.addGoal(3, new AntBlockRecolorGoal(this)); 104 super.registerGoals(); 105 } 106 @Override 107 protected void initRegularGoals() { 108 goalSelector.addGoal(0, new FloatGoal(this)); 109 goalSelector.addGoal(5, new WanderConditionalGoal(this, 1.0)); 110 goalSelector.addGoal(6, new LookAtEntityConditionalGoal(this, Player.class, 6.0F)); 111 goalSelector.addGoal(7, new LookAroundConditionalGoal(this)); 112 } 113 114 public static AttributeSupplier.Builder createAttributes() { 115 return Monster.createMonsterAttributes() 116 .add(Attributes.MOVEMENT_SPEED, 0.1f) 117 .add(Attributes.MAX_HEALTH, 6); 118 } 119 120 @Override 121 public void readAdditionalSaveData( 122 //? if >1.21.2 { 123 ValueInput 124 //?} else { 125 /*CompoundTag 126 *///?} 127 nbt) { 128 super.readAdditionalSaveData(nbt); 129 this.dropsLoot = NbtUtils.getBoolean(nbt, "dropsLoot", true); 130 this.direction = switch(NbtUtils.getString(nbt, "direction")) { 131 case "N" -> Direction.NORTH; 132 case "W" -> Direction.WEST; 133 case "S" -> Direction.SOUTH; 134 default -> Direction.EAST; 135 }; 136 //? if >1.21.2 { 137 this.lastChangedPos = nbt.read("last_changed_pos", BlockPos.CODEC).orElse(lastChangedPos); 138 //?} else { 139 /*if (nbt.contains("last_changed_pos")) { 140 CompoundTag pos = NbtUtils.getCompound(nbt, "last_changed_pos"); 141 this.lastChangedPos = new BlockPos(NbtUtils.getInt(pos, "x"), NbtUtils.getInt(nbt,"y"), NbtUtils.getInt(nbt, "z")); } 142 *///?} 143 } 144 145 @Override 146 public void addAdditionalSaveData( 147 //? if >1.21.2 { 148 ValueOutput 149 //?} else { 150 /*CompoundTag 151 *///?} 152 nbt) { 153 super.addAdditionalSaveData(nbt); 154 nbt.putBoolean("dropsLoot", dropsLoot); 155 nbt.putString("direction", switch(this.direction) { 156 case NORTH -> "N"; 157 case WEST -> "W"; 158 case SOUTH -> "S"; 159 default -> "E"; 160 }); 161 if (lastChangedPos != null) { 162 //? if >1.21.2 { 163 nbt.store("last_changed_pos", BlockPos.CODEC, lastChangedPos); 164 //?} else { 165 /*CompoundTag pos = new CompoundTag(); 166 pos.putInt("x", lastChangedPos.getX()); 167 pos.putInt("y", lastChangedPos.getY()); 168 pos.putInt("z", lastChangedPos.getZ()); 169 nbt.put("last_changed_pos", pos); 170 *///?} 171 } 172 } 173 174 @Override 175 public boolean shouldPursueRegularGoals() { 176 Level w = level(); 177 Optional<BlockPos> bp = mainSupportingBlockPos; 178 return (bp.isEmpty() 179 || isInBattle() 180 || !AntBlock.isSafeToRecolor(w, bp.get())) 181 && super.shouldPursueRegularGoals(); 182 } 183 184 //? if >1.21 { 185 @Override 186 public boolean canBeLeashed() { 187 return !isInBattle(); 188 } 189 //?} 190 @Override 191 public boolean canStandOnFluid(FluidState state) { 192 return state.is(FluidTags.WATER); 193 } 194 195 public static VoxelShape getWaterCollisionShape(int level) { 196 return Block.box(0.0, 0.0, 0.0, 16.0, level, 16.0); 197 } 198 199 @Override 200 public void aiStep() { 201 super.aiStep(); 202 if (!this.firstTick && this.fluidHeight.getDouble(FluidTags.WATER) > 0.0) { 203 CollisionContext shapeContext = CollisionContext.of(this); 204 if (shapeContext.isAbove(getWaterCollisionShape(15), 205 this.blockPosition(), true) 206 && !this.level().getFluidState(this.blockPosition().above()).is(FluidTags.WATER)) { 207 this.setOnGround(true); 208 } else { 209 this.setDeltaMovement(this.getDeltaMovement().scale(0.5).add(0.0, 0.05, 0.0)); 210 } 211 } 212 } 213 214 @Override 215 public InteractionResult mobInteract(Player player, InteractionHand hand) { 216 if (!this.isVehicle() 217 //? if >1.21 218 && this.getAttributeValue(Attributes.SCALE) > 2 219 && player.getItemInHand(hand).isEmpty()) { 220 this.putPlayerOnBack(player); 221 return VersionMethods.sidedSuccess(this.level().isClientSide()); 222 } 223 return super.mobInteract(player, hand); 224 } 225 protected void putPlayerOnBack(Player player) { 226 if (!this.level().isClientSide()) { 227 player.setYRot(this.getYRot()); 228 player.setXRot(this.getXRot()); 229 player.startRiding(this); 230 } 231 } 232 @Override 233 protected Vec3 getRiddenInput(Player controllingPlayer, Vec3 movementInput) { 234 float f = controllingPlayer.zza; 235 return new Vec3(controllingPlayer.xxa * 0.5f, 0, f < 0 ? f*0.25f : f); 236 } 237 @Override 238 protected float getRiddenSpeed(Player controllingPlayer) { 239 return (float)this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.8f; 240 } 241 @Nullable 242 @Override 243 public LivingEntity getControllingPassenger() { 244 if (this.getFirstPassenger() instanceof Player player) { 245 return player; 246 } 247 return super.getControllingPassenger(); 248 } 249 @Override 250 protected void positionRider(Entity passenger, MoveFunction positionUpdater) { 251 super.positionRider(passenger, positionUpdater); 252 if (passenger instanceof LivingEntity) { 253 ((LivingEntity)passenger).yBodyRot = this.yBodyRot; 254 } 255 } 256 @Override 257 protected void tickRidden(Player controllingPlayer, Vec3 movementInput) { 258 super.tickRidden(controllingPlayer, movementInput); 259 this.setRot(controllingPlayer.getYRot(),controllingPlayer.getXRot() * 0.5F); 260 this.yRotO = this.yBodyRot = this.yHeadRot = this.getYRot(); 261 } 262 263 public static class AntBattleGoal<T extends LivingEntity> extends NearestAttackableTargetGoal<T> { 264 public AntBattleGoal(Mob mob, Class<T> targetClass, boolean checkVisibility) { 265 super(mob, targetClass, checkVisibility); 266 } 267 268 @Override 269 public boolean canUse() { 270 if (mob instanceof AbstractChessFigure e && !e.isInBattle()) return false; 271 return super.canUse(); 272 } 273 } 274 275 public static class AntBlockRecolorGoal extends Goal { 276 private final AntEntity mob; 277 @Nullable 278 private BlockPos targetPos; 279 280 public AntBlockRecolorGoal(AntEntity mob) { 281 this.mob = mob; 282 } 283 284 @Override 285 public boolean canUse() { 286 if (mob.shouldPursueRegularGoals()) return false; 287 Optional<BlockPos> bp = mob.mainSupportingBlockPos; 288 if (bp.isEmpty() || bp.get().equals(mob.lastChangedPos)) return false; 289 mob.lastChangedPos = bp.get(); 290 291 BlockState down = mob.level().getBlockState(bp.get()); 292 AntBlock.Clockwiseness cw = AntBlock.getCW(down.getBlock()); 293 if (cw == null) return false; 294 295 Direction direction = mob.direction; 296 Direction direction2 = cw.equals(AntBlock.Clockwiseness.CW) 297 ? direction.getClockWise() 298 : direction.getCounterClockWise(); 299 300 Block newBlock = AntBlock.recolor(down.getBlock(), cw.equals(AntBlock.Clockwiseness.CCW)); 301 if (newBlock == null) return false; 302 303 targetPos = mob.blockPosition().relative(direction2); 304 mob.level().setBlock(bp.get(), newBlock.withPropertiesOf(down), 19); 305 mob.direction = direction2; 306 return true; 307 } 308 309 @Override 310 public boolean canContinueToUse() { 311 return false; 312 } 313 314 @Override 315 public void start() { 316 if (targetPos == null) return; 317 //? if >1.21 { 318 Vec3 v = targetPos.getBottomCenter(); 319 //?} else { 320 /*Vec3 v = targetPos.getCenter(); 321 *///?} 322 mob.randomTeleport(v.x, v.y, v.z, false); 323 mob.setYRot(mob.direction.toYRot()); 324 } 325 } 326 327 public static class WanderConditionalGoal extends WaterAvoidingRandomStrollGoal { 328 private final AntEntity mob1; 329 public WanderConditionalGoal(AntEntity pathAwareEntity, double d) { 330 super(pathAwareEntity, d); 331 mob1 = pathAwareEntity; 332 } 333 334 @Override 335 public boolean canUse() { 336 return super.canUse() && mob1.shouldPursueRegularGoals(); 337 } 338 } 339 340 public static class LookAroundConditionalGoal extends RandomLookAroundGoal { 341 private final AntEntity mob1; 342 public LookAroundConditionalGoal(AntEntity mob) { 343 super(mob); 344 mob1 = mob; 345 } 346 347 @Override 348 public boolean canUse() { 349 return super.canUse() && mob1.shouldPursueRegularGoals(); 350 } 351 } 352 353 public static class LookAtEntityConditionalGoal extends LookAtPlayerGoal { 354 private final AntEntity mob1; 355 356 public LookAtEntityConditionalGoal(AntEntity mob, Class<? extends LivingEntity> targetType, float range) { 357 super(mob, targetType, range); 358 mob1 = mob; 359 } 360 361 @Override 362 public boolean canUse() { 363 return super.canUse() && mob1.shouldPursueRegularGoals(); 364 } 365 } 366}