diff --git a/core/src/main/java/mc/core/GameLoop.java b/core/src/main/java/mc/core/GameLoop.java index b9581dc..27843e9 100644 --- a/core/src/main/java/mc/core/GameLoop.java +++ b/core/src/main/java/mc/core/GameLoop.java @@ -9,8 +9,11 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import mc.core.events.CS_PlayerMoveEvent; import mc.core.events.EventBusGetter; +import mc.core.events.SC_ChunkLoadEvent; import mc.core.player.PlayerManager; import mc.core.time.TimeProcessor; +import mc.core.utils.CompactedCoords; +import mc.core.world.chunk.ChunkSection; import org.springframework.beans.factory.annotation.Autowired; @Slf4j @@ -46,6 +49,36 @@ public class GameLoop extends Thread { log.trace("(GameLoop) playerMoveEventHandler()"); event.getPlayer().getLocation().setXYZ(event.getNewLocation()); + ChunkSection chunkSection = event.getNewLocation().getChunkSection(); + int ncX = chunkSection.getX(); + int ncZ = chunkSection.getZ(); + chunkSection = event.getPlayer().getLocation().getChunkSection(); + int ccX = chunkSection.getX(); + int ccZ = chunkSection.getZ(); + + if (event.isRecalcChunk() || (ncX != ccX && ncZ != ccZ)) { + /* FIXME заменить "8" на актуальный view distance */ + final int viewDistance = 8; + int cMinX = chunkSection.getX() - viewDistance; + int cMaxX = chunkSection.getX() + viewDistance; + int cMinZ = chunkSection.getZ() - viewDistance; + int cMaxZ = chunkSection.getZ() + viewDistance; + + SC_ChunkLoadEvent eventChunkLoad = new SC_ChunkLoadEvent(event.getPlayer()); + for (int cZ = cMinZ; cZ <= cMaxZ; cZ++) { + for (int cX = cMinX; cX <= cMaxX; cX++) { + int compressXZ = CompactedCoords.compressXZ(cX, cZ); + if (!event.getPlayer().getLoadedChunks().contains(compressXZ)) { + eventChunkLoad.getNeedLoadChunks().add(compressXZ); + } + } + } + + if (!eventChunkLoad.getNeedLoadChunks().isEmpty()) { + EventBusGetter.INSTANCE.post(eventChunkLoad); + } + } + // TODO отсылать клиенту только(!) для корректировки позиции // SC_PlayerMoveEvent nextEvent = new SC_PlayerMoveEvent(event.getPlayer()); // nextEvent.setNewLocation(event.getNewLocation()); diff --git a/core/src/main/java/mc/core/events/CS_PlayerMoveEvent.java b/core/src/main/java/mc/core/events/CS_PlayerMoveEvent.java index 5b8b08b..d44f7b1 100644 --- a/core/src/main/java/mc/core/events/CS_PlayerMoveEvent.java +++ b/core/src/main/java/mc/core/events/CS_PlayerMoveEvent.java @@ -18,4 +18,6 @@ public class CS_PlayerMoveEvent extends EventBase { // вообще нужно будет создать реализацию "иммутабл локейшен" для подобных ситуаций @Setter private EntityLocation newLocation; + @Setter + private boolean recalcChunk = false; } diff --git a/core/src/main/java/mc/core/events/SC_ChunkLoadEvent.java b/core/src/main/java/mc/core/events/SC_ChunkLoadEvent.java new file mode 100644 index 0000000..62d35c6 --- /dev/null +++ b/core/src/main/java/mc/core/events/SC_ChunkLoadEvent.java @@ -0,0 +1,16 @@ +package mc.core.events; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import mc.core.player.Player; + +import java.util.ArrayList; +import java.util.List; + +@RequiredArgsConstructor +public class SC_ChunkLoadEvent extends EventBase { + @Getter + private final Player player; + @Getter + private List needLoadChunks = new ArrayList<>(); +} diff --git a/core/src/main/java/mc/core/player/Player.java b/core/src/main/java/mc/core/player/Player.java index faf7877..11c41a3 100644 --- a/core/src/main/java/mc/core/player/Player.java +++ b/core/src/main/java/mc/core/player/Player.java @@ -7,6 +7,7 @@ package mc.core.player; import mc.core.EntityLocation; import mc.core.network.NetChannel; +import java.util.List; import java.util.UUID; public interface Player { @@ -15,10 +16,14 @@ public interface Player { String getName(); boolean isOnline(); + /** Compacted list of Chunk coords (x,z) */ + List getLoadedChunks(); + NetChannel getChannel(); void setChannel(NetChannel channel); EntityLocation getLocation(); + //TODO надо определиться - нужно ли здесь setLocation() или нет boolean isFlying(); void setFlying(boolean value); diff --git a/core/src/main/java/mc/core/player/SimplePlayer.java b/core/src/main/java/mc/core/player/SimplePlayer.java index 990e64f..2472758 100644 --- a/core/src/main/java/mc/core/player/SimplePlayer.java +++ b/core/src/main/java/mc/core/player/SimplePlayer.java @@ -8,6 +8,8 @@ import lombok.Data; import mc.core.EntityLocation; import mc.core.network.NetChannel; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; @Data @@ -20,6 +22,7 @@ public class SimplePlayer implements Player { private EntityLocation location = new EntityLocation(0d, 0d, 0d, 0f, 0f, null); private boolean flying = false; private PlayerSettings settings; + private List loadedChunks = new ArrayList<>(); public void setLocation(EntityLocation location) { this.location.setXYZ(location); diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PlayerEventListener.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PlayerEventListener.java index 5c58142..199c93a 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PlayerEventListener.java +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/PlayerEventListener.java @@ -2,9 +2,13 @@ package mc.core.network.proto_1_12_2.netty; import com.google.common.eventbus.Subscribe; import lombok.extern.slf4j.Slf4j; +import mc.core.events.SC_ChunkLoadEvent; import mc.core.events.SC_PlayerMoveEvent; import mc.core.network.proto_1_12_2.TeleportManager; +import mc.core.network.proto_1_12_2.packets.ChunkDataPacket; import mc.core.network.proto_1_12_2.packets.PlayerPositionAndLookPacket; +import mc.core.utils.CompactedCoords; +import mc.core.world.chunk.ChunkSection; @Slf4j class PlayerEventListener { @@ -18,4 +22,24 @@ class PlayerEventListener { event.getPlayer().getChannel().writeAndFlush(packet); } + + @Subscribe + public void playerChunkLoadHandler(SC_ChunkLoadEvent event) { + log.debug("(SC) playerChunkLoadHandler()"); + + for(Integer compressXZ : event.getNeedLoadChunks()) { + int[] xz = CompactedCoords.uncompressXZ(compressXZ); + ChunkSection chunkSection = event.getPlayer().getLocation().getWorld().getChunk(xz[0], 0, xz[1]); + + ChunkDataPacket packet = new ChunkDataPacket(); + packet.setX(xz[0]); + packet.setZ(xz[1]); + packet.setInitChunk(true); + packet.getChunks().add(chunkSection); + + event.getPlayer().getChannel().write(packet); + } + + event.getPlayer().getChannel().flush(); + } } diff --git a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java index 4d3649e..bce94e5 100644 --- a/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java +++ b/proto_1.12.2_netty/src/main/java/mc/core/network/proto_1_12_2/netty/handlers/LoginHandler.java @@ -6,6 +6,8 @@ package mc.core.network.proto_1_12_2.netty.handlers; import io.netty.channel.Channel; import io.netty.channel.ChannelFutureListener; +import mc.core.events.CS_PlayerMoveEvent; +import mc.core.events.EventBusGetter; import mc.core.network.proto_1_12_2.State; import mc.core.network.proto_1_12_2.TeleportManager; import mc.core.network.proto_1_12_2.netty.wrappers.WrapperNetChannel; @@ -16,6 +18,7 @@ import mc.core.player.PlayerMode; import mc.core.text.Text; import mc.core.text.TextColor; import mc.core.text.TextStyle; +import mc.core.utils.CompactedCoords; import mc.core.world.World; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -85,6 +88,7 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand pkt8.getChunks().add(world.getChunk(0, 0,0)); pkt8.setInitChunk(true); channel.writeAndFlush(pkt8); + player.getLoadedChunks().add(CompactedCoords.compressXZ(0, 0)); // Player Position And Look PlayerPositionAndLookPacket pkt4 = new PlayerPositionAndLookPacket(); @@ -132,6 +136,11 @@ public class LoginHandler extends AbstractStateHandler implements LoginStateHand channel.writeAndFlush(pkt7); playerManager.joinServer(player); + + CS_PlayerMoveEvent event = new CS_PlayerMoveEvent(player, player.getLocation()); + event.setNewLocation(player.getLocation()); + event.setRecalcChunk(true); + EventBusGetter.INSTANCE.post(event); } } }