WorldNotificationHandler.java
package com.hypixel.hytale.server.core.universe.world;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.protocol.BlockParticleEvent;
import com.hypixel.hytale.protocol.BlockPosition;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.Position;
import com.hypixel.hytale.protocol.packets.world.SpawnBlockParticleSystem;
import com.hypixel.hytale.protocol.packets.world.UpdateBlockDamage;
import com.hypixel.hytale.server.core.modules.entity.player.ChunkTracker;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.meta.BlockState;
import com.hypixel.hytale.server.core.universe.world.meta.state.SendableBlockState;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class WorldNotificationHandler {
@Nonnull
private final World world;
public WorldNotificationHandler(@Nonnull World world) {
this.world = world;
}
public void updateState(int x, int y, int z, BlockState state, BlockState oldState) {
this.updateState(x, y, z, state, oldState, (Predicate)null);
}
public void updateState(int x, int y, int z, BlockState state, BlockState oldState, @Nullable Predicate<PlayerRef> skip) {
if (y >= 0 && y < 320) {
Consumer<List<Packet>> removeOldState;
Predicate<PlayerRef> canPlayerSeeOld;
label71: {
if (oldState instanceof SendableBlockState) {
SendableBlockState sendableBlockState = (SendableBlockState)oldState;
if (state != oldState) {
Objects.requireNonNull(sendableBlockState);
removeOldState = sendableBlockState::unloadFrom;
Objects.requireNonNull(sendableBlockState);
canPlayerSeeOld = sendableBlockState::canPlayerSee;
break label71;
}
}
removeOldState = null;
canPlayerSeeOld = null;
}
Predicate<PlayerRef> canPlayerSee;
Consumer<List<Packet>> updateBlockState;
if (state instanceof SendableBlockState) {
SendableBlockState sendableBlockState = (SendableBlockState)state;
Objects.requireNonNull(sendableBlockState);
updateBlockState = sendableBlockState::sendTo;
Objects.requireNonNull(sendableBlockState);
canPlayerSee = sendableBlockState::canPlayerSee;
} else {
updateBlockState = null;
canPlayerSee = null;
}
if (removeOldState != null || updateBlockState != null) {
long indexChunk = ChunkUtil.indexChunkFromBlock(x, z);
List<Packet> packets = new ObjectArrayList<Packet>();
for(PlayerRef playerRef : this.world.getPlayerRefs()) {
ChunkTracker chunkTracker = playerRef.getChunkTracker();
if (chunkTracker.isLoaded(indexChunk) && (skip == null || !skip.test(playerRef))) {
if (removeOldState != null && canPlayerSeeOld.test(playerRef)) {
removeOldState.accept(packets);
}
if (updateBlockState != null && canPlayerSee.test(playerRef)) {
updateBlockState.accept(packets);
}
for(Packet packet : packets) {
playerRef.getPacketHandler().write(packet);
}
packets.clear();
}
}
}
} else {
throw new IllegalArgumentException("Y value is outside the world! " + x + ", " + y + ", " + z);
}
}
public void updateChunk(long indexChunk) {
for(PlayerRef playerRef : this.world.getPlayerRefs()) {
playerRef.getChunkTracker().removeForReload(indexChunk);
}
}
public void sendBlockParticle(double x, double y, double z, int id, @Nonnull BlockParticleEvent particleType) {
this.sendPacketIfChunkLoaded(this.getBlockParticlePacket(x, y, z, id, particleType), MathUtil.floor(x), MathUtil.floor(z));
}
public void sendBlockParticle(@Nonnull PlayerRef playerRef, double x, double y, double z, int id, @Nonnull BlockParticleEvent particleType) {
this.sendPacketIfChunkLoaded(playerRef, this.getBlockParticlePacket(x, y, z, id, particleType), MathUtil.floor(x), MathUtil.floor(z));
}
public void updateBlockDamage(int x, int y, int z, float health, float healthDelta) {
this.sendPacketIfChunkLoaded(this.getBlockDamagePacket(x, y, z, health, healthDelta), x, z);
}
public void updateBlockDamage(int x, int y, int z, float health, float healthDelta, @Nullable Predicate<PlayerRef> filter) {
this.sendPacketIfChunkLoaded(this.getBlockDamagePacket(x, y, z, health, healthDelta), x, z, filter);
}
public void sendPacketIfChunkLoaded(@Nonnull Packet packet, int x, int z) {
long indexChunk = ChunkUtil.indexChunkFromBlock(x, z);
this.sendPacketIfChunkLoaded(packet, indexChunk);
}
public void sendPacketIfChunkLoaded(@Nonnull Packet packet, long indexChunk) {
for(PlayerRef playerRef : this.world.getPlayerRefs()) {
if (playerRef.getChunkTracker().isLoaded(indexChunk)) {
playerRef.getPacketHandler().write(packet);
}
}
}
public void sendPacketIfChunkLoaded(@Nonnull Packet packet, int x, int z, @Nullable Predicate<PlayerRef> filter) {
long indexChunk = ChunkUtil.indexChunkFromBlock(x, z);
this.sendPacketIfChunkLoaded(packet, indexChunk, filter);
}
public void sendPacketIfChunkLoaded(@Nonnull Packet packet, long indexChunk, @Nullable Predicate<PlayerRef> filter) {
for(PlayerRef playerRef : this.world.getPlayerRefs()) {
if ((filter == null || filter.test(playerRef)) && playerRef.getChunkTracker().isLoaded(indexChunk)) {
playerRef.getPacketHandler().write(packet);
}
}
}
private void sendPacketIfChunkLoaded(@Nonnull PlayerRef player, @Nonnull Packet packet, int x, int z) {
long indexChunk = ChunkUtil.indexChunkFromBlock(x, z);
this.sendPacketIfChunkLoaded(player, packet, indexChunk);
}
private void sendPacketIfChunkLoaded(@Nonnull PlayerRef playerRef, @Nonnull Packet packet, long indexChunk) {
if (playerRef.getChunkTracker().isLoaded(indexChunk)) {
playerRef.getPacketHandler().write(packet);
}
}
@Nonnull
public SpawnBlockParticleSystem getBlockParticlePacket(double x, double y, double z, int id, @Nonnull BlockParticleEvent particleType) {
if (!(y < 0.0) && !(y >= 320.0)) {
return new SpawnBlockParticleSystem(id, particleType, new Position(x, y, z));
} else {
throw new IllegalArgumentException("Y value is outside the world! " + x + ", " + y + ", " + z);
}
}
@Nonnull
public UpdateBlockDamage getBlockDamagePacket(int x, int y, int z, float health, float healthDelta) {
if (y >= 0 && y < 320) {
return new UpdateBlockDamage(new BlockPosition(x, y, z), health, healthDelta);
} else {
throw new IllegalArgumentException("Y value is outside the world! " + x + ", " + y + ", " + z);
}
}
}