From 0d36d7cb65b92ea31d5a2676469510603d4e9d0d Mon Sep 17 00:00:00 2001 From: kuroppoi <68156848+kuroppoi@users.noreply.github.com> Date: Sun, 14 Aug 2022 14:35:47 +0200 Subject: [PATCH] Changed some collection messages to prepacked for network efficiency --- .../gameserver/annotations/MessageInfo.java | 3 +- .../gameserver/entity/player/Player.java | 55 +++++++++----- .../NetworkMetaBlockSerializer.java | 28 +++++++ .../brainwine/gameserver/server/Server.java | 2 + .../server/messages/BlockChangeMessage.java | 23 +++--- .../server/messages/BlockMetaMessage.java | 32 ++++---- .../messages/EntityPositionMessage.java | 36 ++++----- .../server/messages/EntityStatusMessage.java | 28 ++++--- .../server/models/BlockChangeData.java | 50 +++++++++++++ .../server/models/EntityPositionData.java | 75 +++++++++++++++++++ .../server/models/EntityStatusData.java | 59 +++++++++++++++ .../server/requests/EntitiesRequest.java | 21 ++++-- .../brainwine/gameserver/zone/MetaBlock.java | 15 +++- .../java/brainwine/gameserver/zone/Zone.java | 57 +++++++++----- 14 files changed, 376 insertions(+), 108 deletions(-) create mode 100644 gameserver/src/main/java/brainwine/gameserver/serialization/NetworkMetaBlockSerializer.java create mode 100644 gameserver/src/main/java/brainwine/gameserver/server/models/BlockChangeData.java create mode 100644 gameserver/src/main/java/brainwine/gameserver/server/models/EntityPositionData.java create mode 100644 gameserver/src/main/java/brainwine/gameserver/server/models/EntityStatusData.java diff --git a/gameserver/src/main/java/brainwine/gameserver/annotations/MessageInfo.java b/gameserver/src/main/java/brainwine/gameserver/annotations/MessageInfo.java index 719efd9..0c130b1 100644 --- a/gameserver/src/main/java/brainwine/gameserver/annotations/MessageInfo.java +++ b/gameserver/src/main/java/brainwine/gameserver/annotations/MessageInfo.java @@ -29,7 +29,8 @@ public @interface MessageInfo { /** * Defines whether or not the values of this message should be part of a collection, * allowing for multiple messages to be sent in a single packet. - * This feature is currently not supported and this option only exists for client compatibility. + * This feature is not supported and this option only exists for client compatibility, + * but you can use the {@code prepacked} option to achieve the same result. * * The default value is false. */ diff --git a/gameserver/src/main/java/brainwine/gameserver/entity/player/Player.java b/gameserver/src/main/java/brainwine/gameserver/entity/player/Player.java index 83b9c52..00a8ce9 100644 --- a/gameserver/src/main/java/brainwine/gameserver/entity/player/Player.java +++ b/gameserver/src/main/java/brainwine/gameserver/entity/player/Player.java @@ -2,6 +2,7 @@ package brainwine.gameserver.entity.player; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -58,6 +59,7 @@ import brainwine.gameserver.server.messages.TeleportMessage; import brainwine.gameserver.server.messages.WardrobeMessage; import brainwine.gameserver.server.messages.XpMessage; import brainwine.gameserver.server.messages.ZoneStatusMessage; +import brainwine.gameserver.server.models.EntityStatusData; import brainwine.gameserver.server.pipeline.Connection; import brainwine.gameserver.util.MapHelper; import brainwine.gameserver.util.MathUtils; @@ -173,11 +175,7 @@ public class Player extends Entity implements CommandExecutor { // Update tracked entities if(now - lastTrackedEntityUpdate >= TRACKED_ENTITY_UPDATE_INTERVAL) { updateTrackedEntities(); - - for(Entity entity : trackedEntities) { - sendMessage(new EntityPositionMessage(entity)); - } - + sendMessage(new EntityPositionMessage(trackedEntities)); lastTrackedEntityUpdate = now; } } @@ -269,21 +267,24 @@ public class Player extends Entity implements CommandExecutor { sendMessage(new HealthMessage(health)); sendMessage(new InventoryMessage(inventory)); sendMessage(new WardrobeMessage(wardrobe)); + sendMessage(new BlockMetaMessage(zone.getGlobalMetaBlocks())); - for(MetaBlock metaBlock : zone.getGlobalMetaBlocks()) { - sendMessage(new BlockMetaMessage(metaBlock)); - } - + // Send skill data for(Skill skill : skills.keySet()) { sendMessage(new SkillMessage(skill, skills.get(skill))); } - for(Player peer : zone.getPlayers()) { - sendMessage(new EntityStatusMessage(peer, EntityStatus.ENTERING)); - sendMessage(new EntityPositionMessage(peer.getId(), peer.getX(), peer.getY(), 0, 0, FacingDirection.EAST, 0, 0, 0)); + // Send peer data + Collection peers = zone.getPlayers(); + sendMessage(new EntityStatusMessage(peers, EntityStatus.ENTERING)); + sendMessage(new EntityPositionMessage(peers)); + + // TODO prepack this as well + for(Player peer : peers) { sendMessage(new EntityItemUseMessage(peer.getId(), 0, peer.getHeldItem(), 0)); } + // Send achievement data for(Achievement achievement : AchievementManager.getAchievements()) { if(hasAchievement(achievement)) { sendMessage(new AchievementMessage(achievement.getTitle(), 0)); @@ -296,6 +297,7 @@ public class Player extends Entity implements CommandExecutor { } } + // And finally, enter the zone! if(isV3()) { sendMessage(new EventMessage("zoneEntered", null)); notify("Welcome to " + zone.getName(), NotificationType.LARGE); @@ -983,16 +985,28 @@ public class Player extends Entity implements CommandExecutor { } private void updateTrackedEntities() { + // Get all entities in range of the player List entitiesInRange = zone.getEntitiesInRange(x, y, ENTITY_VISIBILITY_RANGE); + + // Exclude self entitiesInRange.remove(this); - List enteredEntities = entitiesInRange.stream().filter(entity -> !trackedEntities.contains(entity)) - .collect(Collectors.toList()); - List departedEntities = trackedEntities.stream().filter(entity -> !entitiesInRange.contains(entity)) + + // Get entities that have entered the player's view + List enteredEntities = entitiesInRange.stream() + .filter(entity -> !trackedEntities.contains(entity)) .collect(Collectors.toList()); - for(Entity entity : enteredEntities) { + // Get entities that have left the player's view + List departedEntities = trackedEntities.stream() + .filter(entity -> !entitiesInRange.contains(entity)) + .collect(Collectors.toList()); + + // Create status data for relevant entities + List statuses = new ArrayList<>(); + + for(Entity entity : enteredEntities) { if(entity instanceof Npc) { - sendMessage(new EntityStatusMessage(entity, EntityStatus.ENTERING)); + statuses.add(EntityStatusData.entering(entity)); } entity.addTracker(this); @@ -1000,12 +1014,17 @@ public class Player extends Entity implements CommandExecutor { for(Entity entity : departedEntities) { if(entity instanceof Npc) { - sendMessage(new EntityStatusMessage(entity, EntityStatus.EXITING)); + statuses.add(EntityStatusData.exiting(entity)); } entity.removeTracker(this); } + // Send status data if there is any + if(!statuses.isEmpty()) { + sendMessage(new EntityStatusMessage(statuses)); + } + trackedEntities.clear(); trackedEntities.addAll(entitiesInRange); } diff --git a/gameserver/src/main/java/brainwine/gameserver/serialization/NetworkMetaBlockSerializer.java b/gameserver/src/main/java/brainwine/gameserver/serialization/NetworkMetaBlockSerializer.java new file mode 100644 index 0000000..34d083a --- /dev/null +++ b/gameserver/src/main/java/brainwine/gameserver/serialization/NetworkMetaBlockSerializer.java @@ -0,0 +1,28 @@ +package brainwine.gameserver.serialization; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import brainwine.gameserver.zone.MetaBlock; + +public class NetworkMetaBlockSerializer extends StdSerializer { + + public static final NetworkMetaBlockSerializer INSTANCE = new NetworkMetaBlockSerializer(); + private static final long serialVersionUID = -3597246970639428645L; + + protected NetworkMetaBlockSerializer() { + super(MetaBlock.class); + } + + @Override + public void serialize(MetaBlock metaBlock, JsonGenerator generator, SerializerProvider provider) throws IOException { + generator.writeStartArray(); + generator.writeNumber(metaBlock.getX()); + generator.writeNumber(metaBlock.getY()); + generator.writeObject(metaBlock.getClientMetadata()); + generator.writeEndArray(); + } +} diff --git a/gameserver/src/main/java/brainwine/gameserver/server/Server.java b/gameserver/src/main/java/brainwine/gameserver/server/Server.java index 1a1392a..e5e874f 100644 --- a/gameserver/src/main/java/brainwine/gameserver/server/Server.java +++ b/gameserver/src/main/java/brainwine/gameserver/server/Server.java @@ -22,6 +22,7 @@ import brainwine.gameserver.serialization.BlockSerializer; import brainwine.gameserver.serialization.ItemCodeSerializer; import brainwine.gameserver.serialization.MessageSerializer; import brainwine.gameserver.serialization.NetworkChunkSerializer; +import brainwine.gameserver.serialization.NetworkMetaBlockSerializer; import brainwine.gameserver.serialization.RequestDeserializerModifier; import brainwine.gameserver.server.pipeline.Connection; import brainwine.gameserver.server.pipeline.MessageEncoder; @@ -57,6 +58,7 @@ public class Server { .addSerializer(MessageSerializer.INSTANCE) .addSerializer(BlockSerializer.INSTANCE) .addSerializer(NetworkChunkSerializer.INSTANCE) + .addSerializer(NetworkMetaBlockSerializer.INSTANCE) .addSerializer(ItemCodeSerializer.INSTANCE)) .build(); private static final ObjectWriter writer = mapper.writer(); diff --git a/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockChangeMessage.java b/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockChangeMessage.java index bf686c1..ab63a96 100644 --- a/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockChangeMessage.java +++ b/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockChangeMessage.java @@ -1,25 +1,24 @@ package brainwine.gameserver.server.messages; +import java.util.Arrays; +import java.util.Collection; + import brainwine.gameserver.annotations.MessageInfo; import brainwine.gameserver.item.Item; import brainwine.gameserver.item.Layer; import brainwine.gameserver.server.Message; +import brainwine.gameserver.server.models.BlockChangeData; -@MessageInfo(id = 9, collection = true) +@MessageInfo(id = 9, prepacked = true) public class BlockChangeMessage extends Message { - public int x; - public int y; - public Layer layer; - public int entityId; - public Item item; - public int mod; + public Collection blockChanges; + + public BlockChangeMessage(Collection blockChanges) { + this.blockChanges = blockChanges; + } public BlockChangeMessage(int x, int y, Layer layer, Item item, int mod) { - this.x = x; - this.y = y; - this.layer = layer; - this.item = item; - this.mod = mod; + this(Arrays.asList(new BlockChangeData(x, y, layer, item, mod))); } } diff --git a/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockMetaMessage.java b/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockMetaMessage.java index dfff512..e90282a 100644 --- a/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockMetaMessage.java +++ b/gameserver/src/main/java/brainwine/gameserver/server/messages/BlockMetaMessage.java @@ -1,33 +1,27 @@ package brainwine.gameserver.server.messages; -import java.util.Map; +import java.util.Arrays; +import java.util.Collection; import brainwine.gameserver.annotations.MessageInfo; import brainwine.gameserver.server.Message; -import brainwine.gameserver.util.MapHelper; import brainwine.gameserver.zone.MetaBlock; -@MessageInfo(id = 20, collection = true) +@MessageInfo(id = 20, prepacked = true) public class BlockMetaMessage extends Message { - public int x; - public int y; - public Map metadata; + public Collection metaBlocks; - public BlockMetaMessage(MetaBlock block) { - this.x = block.getX(); - this.y = block.getY(); - this.metadata = MapHelper.copy(block.getMetadata()); - this.metadata.put("i", block.getItem().getId()); - - if(block.hasOwner()) { - this.metadata.put("p", block.getOwner()); - } + public BlockMetaMessage(Collection metaBlocks) { + this.metaBlocks = metaBlocks; } - public BlockMetaMessage(int x, int y, Map metadata) { - this.x = x; - this.y = y; - this.metadata = metadata; + public BlockMetaMessage(MetaBlock metaBlock) { + this(Arrays.asList(metaBlock)); + } + + // TODO Kind of evil... + public BlockMetaMessage(int x, int y) { + this(new MetaBlock(x, y)); } } diff --git a/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityPositionMessage.java b/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityPositionMessage.java index c7f8004..e9c6f43 100644 --- a/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityPositionMessage.java +++ b/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityPositionMessage.java @@ -1,36 +1,30 @@ package brainwine.gameserver.server.messages; +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + import brainwine.gameserver.annotations.MessageInfo; import brainwine.gameserver.entity.Entity; import brainwine.gameserver.entity.FacingDirection; import brainwine.gameserver.server.Message; +import brainwine.gameserver.server.models.EntityPositionData; -@MessageInfo(id = 6, collection = true) +@MessageInfo(id = 6, prepacked = true) public class EntityPositionMessage extends Message { - public int id; - public int x; - public int y; - public int velocityX; - public int velocityY; - public FacingDirection direction; - public int targetX; - public int targetY; - public int animation; + public Collection positions; + + public EntityPositionMessage(Collection entities) { + this.positions = entities.stream().map(EntityPositionData::new).collect(Collectors.toList()); + } public EntityPositionMessage(Entity entity) { - this(entity.getId(), entity.getX(), entity.getY(), entity.getVelocityX(), entity.getVelocityY(), entity.getDirection(), entity.getTargetX(), entity.getTargetY(), entity.getAnimation()); + this.positions = Arrays.asList(new EntityPositionData(entity)); } - public EntityPositionMessage(int id, float x, float y, float velocityX, float velocityY, FacingDirection direction, int targetX, int targetY, int animation) { - this.id = id; - this.x = (int)(x * Entity.POSITION_MODIFIER); - this.y = (int)(y * Entity.POSITION_MODIFIER); - this.velocityX = (int)(velocityX * Entity.VELOCITY_MODIFIER); - this.velocityY = (int)(velocityY * Entity.VELOCITY_MODIFIER); - this.direction = direction; - this.targetX = targetX * Entity.VELOCITY_MODIFIER; - this.targetY = targetY * Entity.VELOCITY_MODIFIER; - this.animation = animation; + public EntityPositionMessage(int id, float x, float y, float velocityX, float velocityY, FacingDirection direction, + int targetX, int targetY, int animation) { + this.positions = Arrays.asList(new EntityPositionData(id, x, y, velocityX, velocityY, direction, targetX, targetY, animation)); } } diff --git a/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityStatusMessage.java b/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityStatusMessage.java index c7ac9f0..accc0d7 100644 --- a/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityStatusMessage.java +++ b/gameserver/src/main/java/brainwine/gameserver/server/messages/EntityStatusMessage.java @@ -1,30 +1,34 @@ package brainwine.gameserver.server.messages; +import java.util.Arrays; +import java.util.Collection; import java.util.Map; +import java.util.stream.Collectors; import brainwine.gameserver.annotations.MessageInfo; import brainwine.gameserver.entity.Entity; import brainwine.gameserver.entity.EntityStatus; import brainwine.gameserver.server.Message; +import brainwine.gameserver.server.models.EntityStatusData; -@MessageInfo(id = 7, collection = true) +@MessageInfo(id = 7, prepacked = true) public class EntityStatusMessage extends Message { - public int id; - public int type; - public String name; - public EntityStatus status; - public Map details; + public Collection statuses; + + public EntityStatusMessage(Collection statuses) { + this.statuses = statuses; + } + + public EntityStatusMessage(Collection entities, EntityStatus status) { + this(entities.stream().map(entity -> new EntityStatusData(entity, status)).collect(Collectors.toList())); + } public EntityStatusMessage(Entity entity, EntityStatus status) { - this(entity.getId(), entity.getType(), entity.getName(), status, entity.getStatusConfig()); + this(Arrays.asList(new EntityStatusData(entity, status))); } public EntityStatusMessage(int id, int type, String name, EntityStatus status, Map details) { - this.id = id; - this.type = type; - this.name = name; - this.status = status; - this.details = details; + this(Arrays.asList(new EntityStatusData(id, type, name, status, details))); } } diff --git a/gameserver/src/main/java/brainwine/gameserver/server/models/BlockChangeData.java b/gameserver/src/main/java/brainwine/gameserver/server/models/BlockChangeData.java new file mode 100644 index 0000000..9723e2b --- /dev/null +++ b/gameserver/src/main/java/brainwine/gameserver/server/models/BlockChangeData.java @@ -0,0 +1,50 @@ +package brainwine.gameserver.server.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; + +import brainwine.gameserver.item.Item; +import brainwine.gameserver.item.Layer; + +@JsonFormat(shape = Shape.ARRAY) +public class BlockChangeData { + + private final int x; + private final int y; + private final Layer layer; + private final int entityId = 0; + private final Item item; + private final int mod; + + public BlockChangeData(int x, int y, Layer layer, Item item, int mod) { + this.x = x; + this.y = y; + this.layer = layer; + this.item = item; + this.mod = mod; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public Layer getLayer() { + return layer; + } + + public int getEntityId() { + return entityId; + } + + public Item getItem() { + return item; + } + + public int getMod() { + return mod; + } +} diff --git a/gameserver/src/main/java/brainwine/gameserver/server/models/EntityPositionData.java b/gameserver/src/main/java/brainwine/gameserver/server/models/EntityPositionData.java new file mode 100644 index 0000000..fd90609 --- /dev/null +++ b/gameserver/src/main/java/brainwine/gameserver/server/models/EntityPositionData.java @@ -0,0 +1,75 @@ +package brainwine.gameserver.server.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; + +import brainwine.gameserver.entity.Entity; +import brainwine.gameserver.entity.FacingDirection; + +@JsonFormat(shape = Shape.ARRAY) +public class EntityPositionData { + + private final int id; + private final int x; + private final int y; + private final int velocityX; + private final int velocityY; + private final FacingDirection direction; + private final int targetX; + private final int targetY; + private final int animation; + + public EntityPositionData(Entity entity) { + this(entity.getId(), entity.getX(), entity.getY(), entity.getVelocityX(), entity.getVelocityY(), entity.getDirection(), + entity.getTargetX(), entity.getTargetY(), entity.getAnimation()); + } + + public EntityPositionData(int id, float x, float y, float velocityX, float velocityY, FacingDirection direction, + int targetX, int targetY, int animation) { + this.id = id; + this.x = (int)(x * Entity.POSITION_MODIFIER); + this.y = (int)(y * Entity.POSITION_MODIFIER); + this.velocityX = (int)(velocityX * Entity.VELOCITY_MODIFIER); + this.velocityY = (int)(velocityY * Entity.VELOCITY_MODIFIER); + this.direction = direction; + this.targetX = targetX * Entity.VELOCITY_MODIFIER; + this.targetY = targetY * Entity.VELOCITY_MODIFIER; + this.animation = animation; + } + + public int getId() { + return id; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getVelocityX() { + return velocityX; + } + + public int getVelocityY() { + return velocityY; + } + + public FacingDirection getDirection() { + return direction; + } + + public int getTargetX() { + return targetX; + } + + public int getTargetY() { + return targetY; + } + + public int getAnimation() { + return animation; + } +} \ No newline at end of file diff --git a/gameserver/src/main/java/brainwine/gameserver/server/models/EntityStatusData.java b/gameserver/src/main/java/brainwine/gameserver/server/models/EntityStatusData.java new file mode 100644 index 0000000..e753976 --- /dev/null +++ b/gameserver/src/main/java/brainwine/gameserver/server/models/EntityStatusData.java @@ -0,0 +1,59 @@ +package brainwine.gameserver.server.models; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; + +import brainwine.gameserver.entity.Entity; +import brainwine.gameserver.entity.EntityStatus; + +@JsonFormat(shape = Shape.ARRAY) +public class EntityStatusData { + + private final int id; + private final int type; + private final String name; + private final EntityStatus status; + private final Map details; + + public EntityStatusData(Entity entity, EntityStatus status) { + this(entity.getId(), entity.getType(), entity.getName(), status, entity.getStatusConfig()); + } + + public EntityStatusData(int id, int type, String name, EntityStatus status, Map details) { + this.id = id; + this.type = type; + this.name = name; + this.status = status; + this.details = details; + } + + public static EntityStatusData entering(Entity entity) { + return new EntityStatusData(entity, EntityStatus.ENTERING); + } + + public static EntityStatusData exiting(Entity entity) { + return new EntityStatusData(entity, EntityStatus.EXITING); + } + + public int getId() { + return id; + } + + public int getType() { + return type; + } + + public String getName() { + return name; + } + + public EntityStatus getStatus() { + return status; + } + + public Map getDetails() { + return details; + } +} diff --git a/gameserver/src/main/java/brainwine/gameserver/server/requests/EntitiesRequest.java b/gameserver/src/main/java/brainwine/gameserver/server/requests/EntitiesRequest.java index 4429de3..0d0c65c 100644 --- a/gameserver/src/main/java/brainwine/gameserver/server/requests/EntitiesRequest.java +++ b/gameserver/src/main/java/brainwine/gameserver/server/requests/EntitiesRequest.java @@ -1,11 +1,14 @@ package brainwine.gameserver.server.requests; +import java.util.ArrayList; +import java.util.List; + import brainwine.gameserver.annotations.RequestInfo; import brainwine.gameserver.entity.Entity; -import brainwine.gameserver.entity.EntityStatus; import brainwine.gameserver.entity.player.Player; import brainwine.gameserver.server.PlayerRequest; import brainwine.gameserver.server.messages.EntityStatusMessage; +import brainwine.gameserver.server.models.EntityStatusData; @RequestInfo(id = 51) public class EntitiesRequest extends PlayerRequest { @@ -15,11 +18,19 @@ public class EntitiesRequest extends PlayerRequest { public void process(Player player) { int count = Math.min(entityIds.length, 10); - for(int i = 0; i < count; i++) { - Entity entity = player.getZone().getEntity(entityIds[i]); + if(count > 0) { + List statuses = new ArrayList<>(); - if(entity != null && player.isTrackingEntity(entity)) { - player.sendMessage(new EntityStatusMessage(entity, EntityStatus.ENTERING)); + for(int i = 0; i < count; i++) { + Entity entity = player.getZone().getEntity(entityIds[i]); + + if(entity != null && player.isTrackingEntity(entity)) { + statuses.add(EntityStatusData.entering(entity)); + } + } + + if(!statuses.isEmpty()) { + player.sendMessage(new EntityStatusMessage(statuses)); } } } diff --git a/gameserver/src/main/java/brainwine/gameserver/zone/MetaBlock.java b/gameserver/src/main/java/brainwine/gameserver/zone/MetaBlock.java index 0653546..a57d8e4 100644 --- a/gameserver/src/main/java/brainwine/gameserver/zone/MetaBlock.java +++ b/gameserver/src/main/java/brainwine/gameserver/zone/MetaBlock.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -39,7 +40,7 @@ public class MetaBlock { } public MetaBlock(int x, int y, Item item) { - this(x, y, item, null); + this(x, y, item, new HashMap<>()); } public MetaBlock(int x, int y, Item item, Map metadata) { @@ -86,6 +87,18 @@ public class MetaBlock { this.metadata = metadata; } + @JsonIgnore + public Map getClientMetadata() { + Map clientMetadata = new HashMap<>(metadata); // Shallow copy + clientMetadata.put("i", item.getId()); + + if(hasOwner()) { + clientMetadata.put("p", owner); + } + + return clientMetadata; + } + public Map getMetadata() { return metadata; } diff --git a/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java b/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java index bbeef1b..2ba90a5 100644 --- a/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java +++ b/gameserver/src/main/java/brainwine/gameserver/zone/Zone.java @@ -44,6 +44,7 @@ import brainwine.gameserver.server.messages.ConfigurationMessage; import brainwine.gameserver.server.messages.LightMessage; import brainwine.gameserver.server.messages.ZoneExploredMessage; import brainwine.gameserver.server.messages.ZoneStatusMessage; +import brainwine.gameserver.server.models.BlockChangeData; import brainwine.gameserver.util.MapHelper; import brainwine.gameserver.util.MathUtils; import brainwine.gameserver.util.Vector2i; @@ -74,6 +75,7 @@ public class Zone { private final WeatherManager weatherManager = new WeatherManager(); private final EntityManager entityManager = new EntityManager(this); private final Queue digQueue = new ArrayDeque<>(); + private final List blockChanges = new ArrayList<>(); private final Set pendingSunlight = new HashSet<>(); private final Map dungeons = new HashMap<>(); private final Map metaBlocks = new HashMap<>(); @@ -163,6 +165,21 @@ public class Zone { } } } + + // Send block changes to players who they are relevant to + if(!blockChanges.isEmpty()) { + for(Player player : getPlayers()) { + List blockChangesNearPlayer = blockChanges.stream() + .filter(blockChange -> player.isChunkActive(blockChange.getX(), blockChange.getY())) + .collect(Collectors.toList()); + + if(!blockChangesNearPlayer.isEmpty()) { + player.sendMessage(new BlockChangeMessage(blockChangesNearPlayer)); + } + } + + blockChanges.clear(); + } } /** @@ -681,7 +698,12 @@ public class Zone { Chunk chunk = getChunk(x, y); chunk.getBlock(x, y).updateLayer(layer, item, mod); chunk.setModified(true); - sendMessageToChunk(new BlockChangeMessage(x, y, layer, item, mod), chunk); + + // Queue block update if there are players in this zone. + // TODO maybe check if the block update was in an active chunk, too? + if(!getPlayers().isEmpty()) { + blockChanges.add(new BlockChangeData(x, y, layer, item, mod)); + } if(layer == Layer.FRONT) { if(item.isWhole()) { @@ -743,34 +765,31 @@ public class Zone { MetaType meta = item.getMeta(); int index = getBlockIndex(x, y); - Map metadata = data == null ? new HashMap<>() : MapHelper.copy(data); - Map toSend = MapHelper.copy(metadata); - toSend.put("i", item.getId()); - - if(owner != null) { - toSend.put("p", owner.getDocumentId()); - } + MetaBlock metaBlock = null; if(item.hasMeta()) { - MetaBlock metaBlock = new MetaBlock(x, y, item, owner, metadata); + metaBlock = new MetaBlock(x, y, item, owner, data); metaBlocks.put(index, metaBlock); indexMetaBlock(index, metaBlock); } else if(metaBlocks.containsKey(index)) { meta = metaBlocks.remove(index).getItem().getMeta(); - toSend.clear(); unindexMetaBlock(index); } switch(meta) { - case LOCAL: - sendMessageToChunk(new BlockMetaMessage(x, y, toSend), getChunk(x, y)); - break; - case GLOBAL: - sendMessage(new BlockMetaMessage(x, y, Collections.emptyMap())); - sendMessage(new BlockMetaMessage(x, y, toSend)); - break; - default: - break; + case LOCAL: + sendMessageToChunk(metaBlock == null ? new BlockMetaMessage(x, y) + : new BlockMetaMessage(metaBlock), getChunk(x, y)); + break; + case GLOBAL: + sendMessage(new BlockMetaMessage(x, y)); // Send empty one first or it won't work for some reason + + if(metaBlock != null) { + sendMessage(new BlockMetaMessage(metaBlock)); + } + break; + default: + break; } }