@Override public void populate(Chunk chunk, Random random) { Vector3i min = chunk.getBlockMin(); World world = (World) chunk.getWorld(); BlockPos position = new BlockPos(min.getX(), min.getY(), min.getZ()); ShrubType stype = ShrubTypes.TALL_GRASS; List<ShrubType> result; // The vanilla populator places down grass in batches of 128, which is a // decent enough amount in order to get nice 'patches' of grass so we // divide the total count into batches of 128. int n = (int) Math.ceil(this.count.getFlooredAmount(random) / 128f); for (int i = 0; i < n; i++) { BlockPos pos = position.add(random.nextInt(16) + 8, 0, random.nextInt(16) + 8); pos = world.getTopSolidOrLiquidBlock(pos).add(0, 1, 0); if (this.override != null) { Location<Chunk> pos2 = new Location<>(chunk, VecHelper.toVector(pos)); stype = this.override.apply(pos2); } else { result = this.types.get(random); if (result.isEmpty()) { continue; } stype = result.get(0); } BlockTallGrass.EnumType type = (BlockTallGrass.EnumType) (Object) stype; this.tallGrassState = Blocks.tallgrass.getDefaultState().withProperty(BlockTallGrass.TYPE, type); generate(world, random, pos); } }
public static CompletableFuture<Boolean> doesChunkExist( WorldServer world, IChunkLoader chunkLoader, Vector3i chunkCoords) { int x = chunkCoords.getX(); int z = chunkCoords.getZ(); if (!(chunkLoader instanceof IMixinAnvilChunkLoader) || !SpongeChunkLayout.instance.isValidChunk(x, chunkCoords.getY(), z)) { return CompletableFuture.completedFuture(false); } return SpongeScheduler.getInstance() .submitAsyncTask(() -> ((IMixinAnvilChunkLoader) chunkLoader).chunkExists(world, x, z)); }
@Subscribe public void onChunkPreGenerator(ChunkPreGenerateEvent event) { org.spongepowered.api.world.Chunk chunk = event.getChunk(); World world = chunk.getWorld(); final String worldname = world.getName(); if (MainUtil.worldBorder.containsKey(worldname)) { final int border = MainUtil.getBorder(worldname); Vector3i min = world.getBlockMin(); final int x = Math.abs(min.getX()); final int z = Math.abs(min.getZ()); if ((x > border) || (z > border)) { // TODO cancel this chunk from loading // - Currently not possible / this event doesn't seem to be called } } }
/** * Return the blocks that will be moved with this elevator * * @return The blocks that this lift will move */ public LiftContents getContents() { Set<Vector3i> blocks = new HashSet<Vector3i>(); Set<Vector3i> edgeBlocks = new HashSet<Vector3i>(); Vector3i location = position.add(0, -1, 0); travelBlocks(location, location, blocks, new HashSet<Vector3i>(), edgeBlocks); return new LiftContents(this, edgeBlocks, blocks); }
public static CompletableFuture<Optional<DataContainer>> getChunkData( WorldServer world, IChunkLoader chunkLoader, Vector3i chunkCoords) { int x = chunkCoords.getX(); int y = chunkCoords.getY(); int z = chunkCoords.getZ(); if (!(chunkLoader instanceof IMixinAnvilChunkLoader) || !SpongeChunkLayout.instance.isValidChunk(x, y, z)) { return CompletableFuture.completedFuture(Optional.empty()); } File worldDir = ((IMixinAnvilChunkLoader) chunkLoader).getWorldDir().toFile(); return SpongeScheduler.getInstance() .submitAsyncTask( () -> { DataInputStream stream = RegionFileCache.getChunkInputStream(worldDir, x, z); return Optional.ofNullable(readDataFromRegion(stream)); }); }
/** * Go through the blocks, checking for valid ones The way this works is: * * <ul> * <li>Adds the current location to the list of valid locations * <li>Checks if the current block is within {@link LiftPlatesConfig#maxLiftSize} * <li>Makes sure the current block is of the same type and data as the central block * <li>If large lifts are not enabled in the configuration, also checks that the block above is * a pressureplate (If any of the previous conditions are not met, the method does not * continue) * <li>Adds the current location to the list of valid locations * <li>Runs the method on {@link LiftUtil#NSEW_FACES}, excluding locations that have already * been visited, with the same sets of valid and visited locations * </ul> * * @param start The origin block * @param current The current block * @param validLocations The list of already travelled and valid locations * @param visited The list of already travelled (not necessarily valid) locations */ private void travelBlocks( Vector3i start, Vector3i current, Set<Vector3i> validLocations, Set<Vector3i> visited, Set<Vector3i> edgeBlocks) { visited.add(current); LiftPlatesConfig config = manager.getPlugin().getConfiguration(); final int maxDist = config.maxLiftSize * config.maxLiftSize; if (start.distanceSquared(current) > maxDist) { // Too far away edgeBlocks.add(current); return; } final World world = manager.getWorld(); if (!world.getBlock(start).equals(world.getBlock(current))) { // Different block type edgeBlocks.add(current); return; } if (!config.recursiveLifts && !LiftUtil.isPressurePlate( world.getBlockType(current.add(0, 1, 0)))) { // Not a pressure plate edgeBlocks.add(current); return; } validLocations.add(current); for (int i = 1; i < config.liftHeight; ++i) { validLocations.add(current.add(0, i, 0)); } for (Direction face : LiftUtil.NSEW_FACES) { Vector3i newLoc = current.add(face.toVector3d().toInt()); if (visited.contains(newLoc)) { continue; } travelBlocks(start, newLoc, validLocations, visited, edgeBlocks); } }
public BoundingBox2(Vector3i parA, Vector3i parB) { int ax, ay, bx, by; if (parA.getX() < parB.getX()) { ax = parA.getX(); bx = parB.getX(); } else { ax = parB.getX(); bx = parA.getX(); } if (parA.getZ() < parB.getZ()) { ay = parA.getZ(); by = parB.getZ(); } else { ay = parB.getZ(); by = parA.getZ(); } a = new Vector2i(ax, ay); b = new Vector2i(bx, by); }
@Override public Extent getExtentView(Vector3i newMin, Vector3i newMax) { checkBlockBounds(newMin.getX(), newMin.getY(), newMin.getZ()); checkBlockBounds(newMax.getX(), newMax.getY(), newMax.getZ()); return new ExtentViewDownsize(this, newMin, newMax); }
@Override public Optional<Chunk> loadChunk(Vector3i position, boolean shouldGenerate) { return loadChunk(position.getX(), position.getY(), position.getZ(), shouldGenerate); }
@NonnullByDefault @Mixin(net.minecraft.world.World.class) public abstract class MixinWorld implements World, IMixinWorld { private static final Vector3i BLOCK_MIN = new Vector3i(-30000000, 0, -30000000); private static final Vector3i BLOCK_MAX = new Vector3i(30000000, 256, 30000000).sub(1, 1, 1); private static final Vector3i BLOCK_SIZE = BLOCK_MAX.sub(BLOCK_MIN).add(1, 1, 1); private static final Vector2i BIOME_MIN = BLOCK_MIN.toVector2(true); private static final Vector2i BIOME_MAX = BLOCK_MAX.toVector2(true); private static final Vector2i BIOME_SIZE = BIOME_MAX.sub(BIOME_MIN).add(1, 1); private static final String CHECK_NO_ENTITY_COLLISION = "checkNoEntityCollision(Lnet/minecraft/util/AxisAlignedBB;Lnet/minecraft/entity/Entity;)Z"; private static final String GET_ENTITIES_WITHIN_AABB = "Lnet/minecraft/world/World;getEntitiesWithinAABBExcludingEntity(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;)Ljava/util/List;"; public SpongeBlockSnapshotBuilder builder = new SpongeBlockSnapshotBuilder(); private boolean keepSpawnLoaded; private Context worldContext; private SpongeChunkProvider spongegen; protected boolean processingExplosion = false; private SpongeConfig<?> activeConfig; // @formatter:off @Shadow @Final public boolean isRemote; @Shadow @Final public WorldProvider provider; @Shadow @Final public Random rand; @Shadow @Final public List<net.minecraft.entity.Entity> loadedEntityList; @Shadow @Final public List<net.minecraft.tileentity.TileEntity> loadedTileEntityList; @Shadow @Final private net.minecraft.world.border.WorldBorder worldBorder; @Shadow @Final public List<EntityPlayer> playerEntities; @Shadow protected boolean scheduledUpdatesAreImmediate; @Shadow protected WorldInfo worldInfo; @Shadow public abstract net.minecraft.world.border.WorldBorder shadow$getWorldBorder(); @Shadow public abstract EnumDifficulty shadow$getDifficulty(); @Shadow public net.minecraft.world.World init() { // Should never be overwritten because this is @Shadow'ed throw new RuntimeException("Bad things have happened"); } @Shadow public abstract void onEntityAdded(net.minecraft.entity.Entity entityIn); @Shadow public abstract void updateEntity(net.minecraft.entity.Entity ent); @Shadow public abstract net.minecraft.world.chunk.Chunk getChunkFromBlockCoords(BlockPos pos); @Shadow public abstract boolean isBlockLoaded(BlockPos pos); @Shadow public abstract boolean addWeatherEffect(net.minecraft.entity.Entity entityIn); @Shadow public abstract BiomeGenBase getBiomeGenForCoords(BlockPos pos); @Shadow public abstract IChunkProvider getChunkProvider(); @Shadow public abstract WorldChunkManager getWorldChunkManager(); @Shadow @Nullable public abstract net.minecraft.tileentity.TileEntity getTileEntity(BlockPos pos); @Shadow public abstract boolean isBlockPowered(BlockPos pos); @Shadow public abstract IBlockState getBlockState(BlockPos pos); @Shadow public abstract net.minecraft.world.chunk.Chunk getChunkFromChunkCoords(int chunkX, int chunkZ); @Shadow public abstract boolean isChunkLoaded(int x, int z, boolean allowEmpty); @Shadow public abstract net.minecraft.world.Explosion newExplosion( net.minecraft.entity.Entity entityIn, double x, double y, double z, float strength, boolean isFlaming, boolean isSmoking); @Shadow public abstract List<net.minecraft.entity.Entity> getEntities( Class<net.minecraft.entity.Entity> entityType, com.google.common.base.Predicate<net.minecraft.entity.Entity> filter); @Shadow public abstract List<net.minecraft.entity.Entity> getEntitiesWithinAABBExcludingEntity( net.minecraft.entity.Entity entityIn, AxisAlignedBB bb); // @formatter:on @Inject(method = "<init>", at = @At("RETURN")) public void onConstructed( ISaveHandler saveHandlerIn, WorldInfo info, WorldProvider providerIn, Profiler profilerIn, boolean client, CallbackInfo ci) { if (info == null) { SpongeImpl.getLogger() .warn( "World constructed without a WorldInfo! This will likely cause problems. Subsituting dummy info.", new RuntimeException("Stack trace:")); this.worldInfo = new WorldInfo( new WorldSettings(0, WorldSettings.GameType.NOT_SET, false, false, WorldType.DEFAULT), "sponge$dummy_world"); } this.worldContext = new Context(Context.WORLD_KEY, this.worldInfo.getWorldName()); if (SpongeImpl.getGame().getPlatform().getType() == Platform.Type.SERVER) { this.worldBorder.addListener(new PlayerBorderListener(providerIn.getDimensionId())); } this.activeConfig = SpongeHooks.getActiveConfig((net.minecraft.world.World) (Object) this); } @Override public SpongeBlockSnapshot createSpongeBlockSnapshot( IBlockState state, IBlockState extended, BlockPos pos, int updateFlag) { this.builder.reset(); Location<World> location = new Location<>((World) this, VecHelper.toVector(pos)); this.builder .blockState((BlockState) state) .extendedState((BlockState) extended) .worldId(location.getExtent().getUniqueId()) .position(location.getBlockPosition()); Optional<UUID> creator = getCreator(pos.getX(), pos.getY(), pos.getZ()); Optional<UUID> notifier = getNotifier(pos.getX(), pos.getY(), pos.getZ()); if (creator.isPresent()) { this.builder.creator(creator.get()); } if (notifier.isPresent()) { this.builder.notifier(notifier.get()); } if (state.getBlock() instanceof ITileEntityProvider) { net.minecraft.tileentity.TileEntity te = getTileEntity(pos); if (te != null) { TileEntity tile = (TileEntity) te; for (DataManipulator<?, ?> manipulator : tile.getContainers()) { this.builder.add(manipulator); } NBTTagCompound nbt = new NBTTagCompound(); te.writeToNBT(nbt); this.builder.unsafeNbt(nbt); } } return new SpongeBlockSnapshot(this.builder, updateFlag); } @SuppressWarnings("rawtypes") @Inject( method = "getCollidingBoundingBoxes(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/AxisAlignedBB;)Ljava/util/List;", at = @At("HEAD"), cancellable = true) public void onGetCollidingBoundingBoxes( net.minecraft.entity.Entity entity, AxisAlignedBB axis, CallbackInfoReturnable<List> cir) { if (!entity.worldObj.isRemote && SpongeHooks.checkBoundingBoxSize(entity, axis)) { // Removing misbehaved living entities cir.setReturnValue(new ArrayList()); } } @Override public UUID getUniqueId() { return ((WorldProperties) this.worldInfo).getUniqueId(); } @Override public String getName() { return this.worldInfo.getWorldName(); } @Override public Optional<Chunk> getChunk(int x, int y, int z) { if (!SpongeChunkLayout.instance.isValidChunk(x, y, z)) { return Optional.empty(); } WorldServer worldserver = (WorldServer) (Object) this; net.minecraft.world.chunk.Chunk chunk = null; if (worldserver.theChunkProviderServer.chunkExists(x, z)) { chunk = worldserver.theChunkProviderServer.provideChunk(x, z); } return Optional.ofNullable((Chunk) chunk); } @Override public Optional<Chunk> loadChunk(Vector3i position, boolean shouldGenerate) { return loadChunk(position.getX(), position.getY(), position.getZ(), shouldGenerate); } @Override public Optional<Chunk> loadChunk(int x, int y, int z, boolean shouldGenerate) { if (!SpongeChunkLayout.instance.isValidChunk(x, y, z)) { return Optional.empty(); } WorldServer worldserver = (WorldServer) (Object) this; net.minecraft.world.chunk.Chunk chunk = null; if (worldserver.theChunkProviderServer.chunkExists(x, z) || shouldGenerate) { chunk = worldserver.theChunkProviderServer.loadChunk(x, z); } return Optional.ofNullable((Chunk) chunk); } @Override public BlockState getBlock(int x, int y, int z) { checkBlockBounds(x, y, z); return (BlockState) getBlockState(new BlockPos(x, y, z)); } @Override public BlockType getBlockType(int x, int y, int z) { checkBlockBounds(x, y, z); // avoid intermediate object creation from using BlockState return (BlockType) getChunkFromChunkCoords(x >> 4, z >> 4).getBlock(x, y, z); } @Override public void setBlock(int x, int y, int z, BlockState block) { setBlock(x, y, z, block, true); } @Override public BiomeType getBiome(int x, int z) { checkBiomeBounds(x, z); return (BiomeType) this.getBiomeGenForCoords(new BlockPos(x, 0, z)); } @Override public void setBiome(int x, int z, BiomeType biome) { checkBiomeBounds(x, z); ((Chunk) getChunkFromChunkCoords(x >> 4, z >> 4)).setBiome(x, z, biome); } @SuppressWarnings("unchecked") @Override public Collection<Entity> getEntities() { return Lists.newArrayList((Collection<Entity>) (Object) this.loadedEntityList); } @SuppressWarnings("unchecked") @Override public Collection<Entity> getEntities(Predicate<Entity> filter) { // This already returns a new copy return (Collection<Entity>) (Object) this.getEntities( net.minecraft.entity.Entity.class, Functional.java8ToGuava((Predicate<net.minecraft.entity.Entity>) (Object) filter)); } @Override public Optional<Entity> createEntity(EntityType type, Vector3d position) { checkNotNull(type, "The entity type cannot be null!"); checkNotNull(position, "The position cannot be null!"); Entity entity = null; Class<? extends Entity> entityClass = type.getEntityClass(); double x = position.getX(); double y = position.getY(); double z = position.getZ(); if (entityClass.isAssignableFrom(EntityPlayerMP.class) || entityClass.isAssignableFrom(EntityDragonPart.class)) { // Unable to construct these return Optional.empty(); } net.minecraft.world.World world = (net.minecraft.world.World) (Object) this; // Not all entities have a single World parameter as their constructor if (entityClass.isAssignableFrom(EntityLightningBolt.class)) { entity = (Entity) new EntityLightningBolt(world, x, y, z); } else if (entityClass.isAssignableFrom(EntityEnderPearl.class)) { EntityArmorStand tempEntity = new EntityArmorStand(world, x, y, z); tempEntity.posY -= tempEntity.getEyeHeight(); entity = (Entity) new EntityEnderPearl(world, tempEntity); ((EnderPearl) entity).setShooter(ProjectileSource.UNKNOWN); } // Some entities need to have non-null fields (and the easiest way to // set them is to use the more specialised constructor). if (entityClass.isAssignableFrom(EntityFallingBlock.class)) { entity = (Entity) new EntityFallingBlock(world, x, y, z, Blocks.sand.getDefaultState()); } else if (entityClass.isAssignableFrom(EntityItem.class)) { entity = (Entity) new EntityItem(world, x, y, z, new ItemStack(Blocks.stone)); } if (entity == null) { try { entity = ConstructorUtils.invokeConstructor(entityClass, this); ((net.minecraft.entity.Entity) entity).setPosition(x, y, z); } catch (Exception e) { SpongeImpl.getLogger().error(ExceptionUtils.getStackTrace(e)); } } // TODO - replace this with an actual check /* if (entity instanceof EntityHanging) { if (((EntityHanging) entity).facingDirection == null) { // TODO Some sort of detection of a valid direction? // i.e scan immediate blocks for something to attach onto. ((EntityHanging) entity).facingDirection = EnumFacing.NORTH; } if (!((EntityHanging) entity).onValidSurface()) { return Optional.empty(); } }*/ // Last chance to fix null fields if (entity instanceof EntityPotion) { // make sure EntityPotion.potionDamage is not null ((EntityPotion) entity).getPotionDamage(); } else if (entity instanceof EntityPainting) { // This is default when art is null when reading from NBT, could // choose a random art instead? ((EntityPainting) entity).art = EnumArt.KEBAB; } return Optional.ofNullable(entity); } @Override public Optional<Entity> createEntity(DataContainer entityContainer) { // TODO once entity containers are implemented return Optional.empty(); } @Override public Optional<Entity> createEntity(DataContainer entityContainer, Vector3d position) { // TODO once entity containers are implemented return Optional.empty(); } @Override public Optional<Entity> restoreSnapshot(EntitySnapshot snapshot, Vector3d position) { EntitySnapshot entitySnapshot = snapshot.withLocation(new Location<>(this, position)); return entitySnapshot.restore(); } @Override public WorldBorder getWorldBorder() { return (WorldBorder) shadow$getWorldBorder(); } @Override public WorldBorder.ChunkPreGenerate newChunkPreGenerate(Vector3d center, double diameter) { return new SpongeChunkPreGenerate(this, center, diameter); } @Override public Dimension getDimension() { return (Dimension) this.provider; } @Override public boolean doesKeepSpawnLoaded() { return this.keepSpawnLoaded; } @Override public void setKeepSpawnLoaded(boolean keepLoaded) { this.keepSpawnLoaded = keepLoaded; } @Override public SpongeConfig<SpongeConfig.WorldConfig> getWorldConfig() { return ((IMixinWorldInfo) this.worldInfo).getWorldConfig(); } @Override public Optional<Entity> getEntity(UUID uuid) { // Note that MixinWorldServer is properly overriding this to use it's own mapping. for (net.minecraft.entity.Entity entity : this.loadedEntityList) { if (entity.getUniqueID().equals(uuid)) { return Optional.of((Entity) entity); } } return Optional.empty(); } @SuppressWarnings("unchecked") @Override public Iterable<Chunk> getLoadedChunks() { return (List<Chunk>) (List<?>) ((ChunkProviderServer) this.getChunkProvider()).loadedChunks; } @Override public boolean unloadChunk(Chunk chunk) { checkArgument(chunk != null, "Chunk cannot be null!"); return chunk.unloadChunk(); } @Override public WorldCreationSettings getCreationSettings() { WorldProperties properties = this.getProperties(); // Create based on WorldProperties WorldSettings settings = new WorldSettings(this.worldInfo); IMixinWorldSettings mixin = (IMixinWorldSettings) (Object) settings; mixin.setDimensionType(properties.getDimensionType()); mixin.setGeneratorSettings(properties.getGeneratorSettings()); mixin.setGeneratorModifiers(properties.getGeneratorModifiers()); mixin.setEnabled(true); mixin.setKeepSpawnLoaded(this.keepSpawnLoaded); mixin.setLoadOnStartup(properties.loadOnStartup()); return (WorldCreationSettings) (Object) settings; } @Override public void updateWorldGenerator() { IMixinWorldType worldType = (IMixinWorldType) this.getProperties().getGeneratorType(); // Get the default generator for the world type DataContainer generatorSettings = this.getProperties().getGeneratorSettings(); SpongeWorldGenerator newGenerator = worldType.createGenerator(this, generatorSettings); // If the base generator is an IChunkProvider which implements // IPopulatorProvider we request that it add its populators not covered // by the base generation populator if (newGenerator.getBaseGenerationPopulator() instanceof IChunkProvider) { // We check here to ensure that the IPopulatorProvider is one of our mixed in ones and not // from a mod chunk provider extending a provider that we mixed into if (WorldGenConstants.isValid( (IChunkProvider) newGenerator.getBaseGenerationPopulator(), IPopulatorProvider.class)) { ((IPopulatorProvider) newGenerator.getBaseGenerationPopulator()) .addPopulators(newGenerator); } } else if (newGenerator.getBaseGenerationPopulator() instanceof IPopulatorProvider) { // If its not a chunk provider but is a populator provider then we call it as well ((IPopulatorProvider) newGenerator.getBaseGenerationPopulator()).addPopulators(newGenerator); } // Re-apply all world generator modifiers WorldCreationSettings creationSettings = this.getCreationSettings(); for (WorldGeneratorModifier modifier : this.getProperties().getGeneratorModifiers()) { modifier.modifyWorldGenerator(creationSettings, generatorSettings, newGenerator); } this.spongegen = createChunkProvider(newGenerator); this.spongegen.setGenerationPopulators(newGenerator.getGenerationPopulators()); this.spongegen.setPopulators(newGenerator.getPopulators()); this.spongegen.setBiomeOverrides(newGenerator.getBiomeSettings()); ChunkProviderServer chunkProviderServer = (ChunkProviderServer) this.getChunkProvider(); chunkProviderServer.serverChunkGenerator = this.spongegen; } @Override public SpongeChunkProvider createChunkProvider(SpongeWorldGenerator newGenerator) { return new SpongeChunkProvider( (net.minecraft.world.World) (Object) this, newGenerator.getBaseGenerationPopulator(), newGenerator.getBiomeGenerator()); } @Override public void onSpongeEntityAdded(net.minecraft.entity.Entity entity) { this.onEntityAdded(entity); } @Override public WorldGenerator getWorldGenerator() { return this.spongegen; } @Override public WorldProperties getProperties() { return (WorldProperties) this.worldInfo; } @Override public Location<World> getSpawnLocation() { return new Location<>( this, this.worldInfo.getSpawnX(), this.worldInfo.getSpawnY(), this.worldInfo.getSpawnZ()); } @Override public Context getContext() { return this.worldContext; } @Override public Optional<TileEntity> getTileEntity(int x, int y, int z) { net.minecraft.tileentity.TileEntity tileEntity = getTileEntity(new BlockPos(x, y, z)); if (tileEntity == null) { return Optional.empty(); } else { return Optional.of((TileEntity) tileEntity); } } @Override public Vector2i getBiomeMin() { return BIOME_MIN; } @Override public Vector2i getBiomeMax() { return BIOME_MAX; } @Override public Vector2i getBiomeSize() { return BIOME_SIZE; } @Override public Vector3i getBlockMin() { return BLOCK_MIN; } @Override public Vector3i getBlockMax() { return BLOCK_MAX; } @Override public Vector3i getBlockSize() { return BLOCK_SIZE; } @Override public boolean containsBiome(int x, int z) { return VecHelper.inBounds(x, z, BIOME_MIN, BIOME_MAX); } @Override public boolean containsBlock(int x, int y, int z) { return VecHelper.inBounds(x, y, z, BLOCK_MIN, BLOCK_MAX); } private void checkBiomeBounds(int x, int z) { if (!containsBiome(x, z)) { throw new PositionOutOfBoundsException(new Vector2i(x, z), BIOME_MIN, BIOME_MAX); } } private void checkBlockBounds(int x, int y, int z) { if (!containsBlock(x, y, z)) { throw new PositionOutOfBoundsException(new Vector3i(x, y, z), BLOCK_MIN, BLOCK_MAX); } } @Override public Difficulty getDifficulty() { return (Difficulty) (Object) this.shadow$getDifficulty(); } @SuppressWarnings({"unchecked", "rawtypes"}) private List<Player> getPlayers() { return (List) ((net.minecraft.world.World) (Object) this) .getPlayers(EntityPlayerMP.class, Predicates.alwaysTrue()); } @Override public void sendMessage(ChatType type, Text message) { checkNotNull(type, "type"); checkNotNull(message, "message"); for (Player player : this.getPlayers()) { player.sendMessage(type, message); } } @Override public void sendTitle(Title title) { checkNotNull(title, "title"); for (Player player : getPlayers()) { player.sendTitle(title); } } @Override public void resetTitle() { getPlayers().forEach(Player::resetTitle); } @Override public void clearTitle() { getPlayers().forEach(Player::clearTitle); } @SuppressWarnings("unchecked") @Override public Collection<TileEntity> getTileEntities() { return Lists.newArrayList((List<TileEntity>) (Object) this.loadedTileEntityList); } @SuppressWarnings("unchecked") @Override public Collection<TileEntity> getTileEntities(Predicate<TileEntity> filter) { return ((List<TileEntity>) (Object) this.loadedTileEntityList) .stream() .filter(filter) .collect(Collectors.toList()); } @Override public boolean isLoaded() { return DimensionManager.getWorldFromDimId(this.provider.getDimensionId()) != null; } @Override public Optional<String> getGameRule(String gameRule) { return this.getProperties().getGameRule(gameRule); } @Override public Map<String, String> getGameRules() { return this.getProperties().getGameRules(); } @Override public void triggerExplosion(Explosion explosion) { checkNotNull(explosion, "explosion"); checkNotNull(explosion.getOrigin(), "origin"); newExplosion( (net.minecraft.entity.Entity) explosion.getSourceExplosive().orElse(null), explosion.getOrigin().getX(), explosion.getOrigin().getY(), explosion.getOrigin().getZ(), explosion.getRadius(), explosion.canCauseFire(), explosion.shouldBreakBlocks()); } @Override public Extent getExtentView(Vector3i newMin, Vector3i newMax) { checkBlockBounds(newMin.getX(), newMin.getY(), newMin.getZ()); checkBlockBounds(newMax.getX(), newMax.getY(), newMax.getZ()); return new ExtentViewDownsize(this, newMin, newMax); } @Override public Extent getExtentView(DiscreteTransform3 transform) { return new ExtentViewTransform(this, transform); } @Override public MutableBiomeAreaWorker<? extends World> getBiomeWorker() { return new SpongeMutableBiomeAreaWorker<>(this); } @Override public MutableBlockVolumeWorker<? extends World> getBlockWorker() { return new SpongeMutableBlockVolumeWorker<>(this); } @Override public BlockSnapshot createSnapshot(int x, int y, int z) { World world = this; BlockState state = world.getBlock(x, y, z); Optional<TileEntity> te = world.getTileEntity(x, y, z); SpongeBlockSnapshotBuilder builder = new SpongeBlockSnapshotBuilder() .blockState(state) .worldId(world.getUniqueId()) .position(new Vector3i(x, y, z)); Optional<UUID> creator = getCreator(x, y, z); Optional<UUID> notifier = getNotifier(x, y, z); if (creator.isPresent()) { builder.creator(creator.get()); } if (notifier.isPresent()) { builder.notifier(notifier.get()); } if (te.isPresent()) { final TileEntity tileEntity = te.get(); for (DataManipulator<?, ?> manipulator : tileEntity.getContainers()) { builder.add(manipulator); } final NBTTagCompound compound = new NBTTagCompound(); ((net.minecraft.tileentity.TileEntity) tileEntity).writeToNBT(compound); builder.unsafeNbt(compound); } return builder.build(); } @Override public boolean restoreSnapshot(BlockSnapshot snapshot, boolean force, boolean notifyNeighbors) { return snapshot.restore(force, notifyNeighbors); } @Override public boolean restoreSnapshot( int x, int y, int z, BlockSnapshot snapshot, boolean force, boolean notifyNeighbors) { snapshot = snapshot.withLocation(new Location<>(this, new Vector3i(x, y, z))); return snapshot.restore(force, notifyNeighbors); } @Override public Optional<UUID> getCreator(int x, int y, int z) { BlockPos pos = new BlockPos(x, y, z); IMixinChunk spongeChunk = (IMixinChunk) getChunkFromBlockCoords(pos); Optional<User> user = spongeChunk.getBlockOwner(pos); if (user.isPresent()) { return Optional.of(user.get().getUniqueId()); } else { return Optional.empty(); } } @Override public Optional<UUID> getNotifier(int x, int y, int z) { BlockPos pos = new BlockPos(x, y, z); IMixinChunk spongeChunk = (IMixinChunk) getChunkFromBlockCoords(pos); Optional<User> user = spongeChunk.getBlockNotifier(pos); if (user.isPresent()) { return Optional.of(user.get().getUniqueId()); } else { return Optional.empty(); } } @Override public void setCreator(int x, int y, int z, @Nullable UUID uuid) { BlockPos pos = new BlockPos(x, y, z); IMixinChunk spongeChunk = (IMixinChunk) getChunkFromBlockCoords(pos); spongeChunk.setBlockCreator(pos, uuid); } @Override public void setNotifier(int x, int y, int z, @Nullable UUID uuid) { BlockPos pos = new BlockPos(x, y, z); IMixinChunk spongeChunk = (IMixinChunk) getChunkFromBlockCoords(pos); spongeChunk.setBlockNotifier(pos, uuid); } @Nullable @Override public EntityPlayer getClosestPlayerToEntityWhoAffectsSpawning( net.minecraft.entity.Entity entity, double distance) { return this.getClosestPlayerWhoAffectsSpawning(entity.posX, entity.posY, entity.posZ, distance); } @Nullable @Override public EntityPlayer getClosestPlayerWhoAffectsSpawning( double x, double y, double z, double distance) { double bestDistance = -1.0D; EntityPlayer result = null; for (Object entity : this.playerEntities) { EntityPlayer player = (EntityPlayer) entity; if (player == null || player.isDead || !((IMixinEntityPlayer) player).affectsSpawning()) { continue; } double playerDistance = player.getDistanceSq(x, y, z); if ((distance < 0.0D || playerDistance < distance * distance) && (bestDistance == -1.0D || playerDistance < bestDistance)) { bestDistance = playerDistance; result = player; } } return result; } @Redirect( method = "isAnyPlayerWithinRangeAt", at = @At( value = "INVOKE", target = "Lcom/google/common/base/Predicate;apply(Ljava/lang/Object;)Z", remap = false)) public boolean onIsAnyPlayerWithinRangePredicate( com.google.common.base.Predicate<EntityPlayer> predicate, Object object) { EntityPlayer player = (EntityPlayer) object; return !(player.isDead || !((IMixinEntityPlayer) player).affectsSpawning()) && predicate.apply(player); } // For invisibility @Redirect( method = CHECK_NO_ENTITY_COLLISION, at = @At(value = "INVOKE", target = GET_ENTITIES_WITHIN_AABB)) public List<net.minecraft.entity.Entity> filterInvisibile( net.minecraft.world.World world, net.minecraft.entity.Entity entityIn, AxisAlignedBB axisAlignedBB) { List<net.minecraft.entity.Entity> entities = world.getEntitiesWithinAABBExcludingEntity(entityIn, axisAlignedBB); Iterator<net.minecraft.entity.Entity> iterator = entities.iterator(); while (iterator.hasNext()) { net.minecraft.entity.Entity entity = iterator.next(); if (((IMixinEntity) entity).isVanished() && ((IMixinEntity) entity).ignoresCollision()) { iterator.remove(); } } return entities; } @Redirect( method = "getClosestPlayer", at = @At( value = "INVOKE", target = "Lcom/google/common/base/Predicate;apply(Ljava/lang/Object;)Z", remap = false)) private boolean onGetClosestPlayerCheck( com.google.common.base.Predicate<net.minecraft.entity.Entity> predicate, Object entityPlayer) { EntityPlayer player = (EntityPlayer) entityPlayer; IMixinEntity mixinEntity = (IMixinEntity) player; return predicate.apply(player) && !mixinEntity.isVanished(); } /** * @author gabizou - February 7th, 2016 * <p>This will short circuit all other patches such that we control the entities being loaded * by chunkloading and can throw our bulk entity event. This will bypass Forge's hook for * individual entity events, but the SpongeModEventManager will still successfully throw the * appropriate event and cancel the entities otherwise contained. * @param entities The entities being loaded * @param callbackInfo The callback info */ @Final @Inject(method = "loadEntities", at = @At("HEAD"), cancellable = true) private void spongeLoadEntities( Collection<net.minecraft.entity.Entity> entities, CallbackInfo callbackInfo) { if (entities.isEmpty()) { // just return, no entities to load! callbackInfo.cancel(); return; } List<Entity> entityList = new ArrayList<>(); ImmutableList.Builder<EntitySnapshot> snapshotBuilder = ImmutableList.builder(); for (net.minecraft.entity.Entity entity : entities) { entityList.add((Entity) entity); snapshotBuilder.add(((Entity) entity).createSnapshot()); } SpawnCause cause = SpawnCause.builder().type(InternalSpawnTypes.CHUNK_LOAD).build(); List<NamedCause> causes = new ArrayList<>(); causes.add(NamedCause.source(cause)); causes.add(NamedCause.of("World", this)); SpawnEntityEvent.ChunkLoad chunkLoad = SpongeEventFactory.createSpawnEntityEventChunkLoad( Cause.of(causes), entityList, snapshotBuilder.build(), this); SpongeImpl.postEvent(chunkLoad); if (!chunkLoad.isCancelled()) { for (Entity successful : chunkLoad.getEntities()) { this.loadedEntityList.add((net.minecraft.entity.Entity) successful); this.onEntityAdded((net.minecraft.entity.Entity) successful); } } callbackInfo.cancel(); } @Inject(method = "playSoundAtEntity", at = @At("HEAD"), cancellable = true) private void spongePlaySoundAtEntity( net.minecraft.entity.Entity entity, String name, float volume, float pitch, CallbackInfo callbackInfo) { if (((IMixinEntity) entity).isVanished()) { callbackInfo.cancel(); } } @Override public void sendBlockChange(int x, int y, int z, BlockState state) { checkNotNull(state, "state"); S23PacketBlockChange packet = new S23PacketBlockChange(); packet.blockPosition = new BlockPos(x, y, z); packet.blockState = (IBlockState) state; for (EntityPlayer player : this.playerEntities) { if (player instanceof EntityPlayerMP) { ((EntityPlayerMP) player).playerNetServerHandler.sendPacket(packet); } } } @Override public void resetBlockChange(int x, int y, int z) { S23PacketBlockChange packet = new S23PacketBlockChange((net.minecraft.world.World) (Object) this, new BlockPos(x, y, z)); for (EntityPlayer player : this.playerEntities) { if (player instanceof EntityPlayerMP) { ((EntityPlayerMP) player).playerNetServerHandler.sendPacket(packet); } } } /** * @author amaranth - April 25th, 2016 * @reason Avoid 25 chunk map lookups per entity per tick by using neighbor pointers * @param xStart X block start coordinate * @param yStart Y block start coordinate * @param zStart Z block start coordinate * @param xEnd X block end coordinate * @param yEnd Y block end coordinate * @param zEnd Z block end coordinate * @param allowEmpty Whether empty chunks should be accepted * @return If the chunks for the area are loaded */ @Overwrite public boolean isAreaLoaded( int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, boolean allowEmpty) { if (yEnd < 0 || yStart > 255) { return false; } xStart = xStart >> 4; zStart = zStart >> 4; xEnd = xEnd >> 4; zEnd = zEnd >> 4; Chunk base = (Chunk) ((IMixinChunkProviderServer) this.getChunkProvider()).getChunkIfLoaded(xStart, zStart); if (base == null) { return false; } for (int i = xStart; i <= xEnd; i++) { Optional<Chunk> column = base.getNeighbor(Direction.EAST); if (!column.isPresent()) { return false; } Chunk unwrapped = column.get(); for (int j = zStart; j <= zEnd; j++) { Optional<Chunk> row = unwrapped.getNeighbor(Direction.SOUTH); if (!row.isPresent()) { return false; } if (!allowEmpty && ((net.minecraft.world.chunk.Chunk) row.get()).isEmpty()) { return false; } } } return true; } @Override public boolean isProcessingExplosion() { return this.processingExplosion; } @Override public SpongeConfig<?> getActiveConfig() { return this.activeConfig; } @Override public void setActiveConfig(SpongeConfig<?> config) { this.activeConfig = config; } }
/** * Get the chunk at the given chunk coordinate position if it exists or if {@code shouldGenerate} * is true and the chunk is generated. * * @param chunkPosition The position * @param shouldGenerate True to generate a new chunk * @return The loaded or generated chunk, if already generated */ default Optional<Chunk> loadChunk(Vector3i chunkPosition, boolean shouldGenerate) { return this.loadChunk( chunkPosition.getX(), chunkPosition.getY(), chunkPosition.getZ(), shouldGenerate); }
/** * Get the loaded chunk at the given chunk coordinate position. * * @param chunkPosition The position * @return The chunk, if available */ default Optional<Chunk> getChunk(Vector3i chunkPosition) { return getChunk(chunkPosition.getX(), chunkPosition.getY(), chunkPosition.getZ()); }
/** * Get the loaded chunk at the given block coordinate position. * * @param blockPosition The position * @return The chunk, if available */ default Optional<Chunk> getChunkAtBlock(Vector3i blockPosition) { return getChunkAtBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); }