Skip to content

Commit

Permalink
Merge pull request #1652 from SamB440/feat/tag-sync
Browse files Browse the repository at this point in the history
Synchronise server tags
  • Loading branch information
SamB440 committed Aug 17, 2024
2 parents 588eeae + 90d2ebd commit cd2a182
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 14 deletions.
28 changes: 28 additions & 0 deletions src/main/java/ac/grim/grimac/events/packets/PacketServerTags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package ac.grim.grimac.events.packets;

import ac.grim.grimac.GrimAPI;
import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTags;

public class PacketServerTags extends PacketListenerAbstract {

@Override
public void onPacketSend(PacketSendEvent event) {
if (event.getPacketType() == PacketType.Play.Server.TAGS || event.getPacketType() == PacketType.Configuration.Server.UPDATE_TAGS) {
GrimPlayer player = GrimAPI.INSTANCE.getPlayerDataManager().getPlayer(event.getUser());
if (player == null) return;

WrapperPlayServerTags tags = new WrapperPlayServerTags(event);
final boolean isPlay = event.getPacketType() == PacketType.Play.Server.TAGS;
if (isPlay) {
player.latencyUtils.addRealTimeTask(player.lastTransactionSent.get(), () -> player.tagManager.handleTagSync(tags));
} else {
// This is during configuration stage, player isn't even in the game yet so no need to lag compensate.
player.tagManager.handleTagSync(tags);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public void start() {
PacketEvents.getAPI().getEventManager().registerListener(new CheckManagerListener());
PacketEvents.getAPI().getEventManager().registerListener(new PacketPlayerSteer());

if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
PacketEvents.getAPI().getEventManager().registerListener(new PacketServerTags());
}

if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_18)) {
PacketEvents.getAPI().getEventManager().registerListener(new PacketWorldReaderEighteen());
} else if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_8_8)) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/ac/grim/grimac/player/GrimPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import ac.grim.grimac.utils.data.*;
import ac.grim.grimac.utils.data.packetentity.PacketEntity;
import ac.grim.grimac.utils.data.packetentity.PacketEntitySelf;
import ac.grim.grimac.utils.data.tags.SyncedTags;
import ac.grim.grimac.utils.enums.FluidTag;
import ac.grim.grimac.utils.enums.Pose;
import ac.grim.grimac.utils.latency.*;
Expand Down Expand Up @@ -85,6 +86,7 @@ public class GrimPlayer implements GrimUser {
public ActionManager actionManager;
public PunishmentManager punishmentManager;
public MovementCheckRunner movementCheckRunner;
public SyncedTags tagManager;
// End manager like classes
public Vector clientVelocity = new Vector();
PacketTracker packetTracker;
Expand Down Expand Up @@ -225,6 +227,7 @@ public GrimPlayer(User user) {
actionManager = new ActionManager(this);
checkManager = new CheckManager(this);
punishmentManager = new PunishmentManager(this);
tagManager = new SyncedTags(this);
movementCheckRunner = new MovementCheckRunner(this);

compensatedWorld = new CompensatedWorld(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.data.tags.SyncedTags;
import ac.grim.grimac.utils.nmsutil.*;
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.potion.PotionType;
import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import lombok.Getter;
import lombok.Setter;
Expand Down Expand Up @@ -119,7 +121,8 @@ public PointThreeEstimator(GrimPlayer player) {

// Handle game events that occur between skipped ticks - thanks a lot mojang for removing the idle packet!
public void handleChangeBlock(int x, int y, int z, WrappedBlockState state) {
CollisionBox data = CollisionData.getData(state.getType()).getMovementCollisionBox(player, player.getClientVersion(), state, x, y, z);
final StateType stateType = state.getType();
CollisionBox data = CollisionData.getData(stateType).getMovementCollisionBox(player, player.getClientVersion(), state, x, y, z);
SimpleCollisionBox normalBox = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y, player.z, 0.6f, 1.8f);

// Calculate head hitters. Take a shortcut by checking if the player doesn't intersect with this block, but does
Expand All @@ -130,10 +133,10 @@ public void handleChangeBlock(int x, int y, int z, WrappedBlockState state) {
}

SimpleCollisionBox pointThreeBox = GetBoundingBox.getBoundingBoxFromPosAndSize(player, player.x, player.y - 0.03, player.z, 0.66f, 1.86f);
if ((Materials.isWater(player.getClientVersion(), state) || state.getType() == StateTypes.LAVA) &&
if ((Materials.isWater(player.getClientVersion(), state) || stateType == StateTypes.LAVA) &&
pointThreeBox.isIntersected(new SimpleCollisionBox(x, y, z))) {

if (state.getType() == StateTypes.BUBBLE_COLUMN) {
if (stateType == StateTypes.BUBBLE_COLUMN) {
isNearBubbleColumn = true;
}

Expand Down Expand Up @@ -164,8 +167,8 @@ public void handleChangeBlock(int x, int y, int z, WrappedBlockState state) {
}
}

if (!player.compensatedEntities.getSelf().inVehicle() && ((state.getType() == StateTypes.POWDER_SNOW && player.getInventory().getBoots().getType() == ItemTypes.LEATHER_BOOTS)
|| Materials.isClimbable(state.getType())) && pointThreeBox.isIntersected(new SimpleCollisionBox(x, y, z))) {
if (!player.compensatedEntities.getSelf().inVehicle() && ((stateType == StateTypes.POWDER_SNOW && player.getInventory().getBoots().getType() == ItemTypes.LEATHER_BOOTS)
|| player.tagManager.block(SyncedTags.CLIMBABLE).contains(stateType)) && pointThreeBox.isIntersected(new SimpleCollisionBox(x, y, z))) {
isNearClimbable = true;
}
}
Expand Down Expand Up @@ -245,16 +248,17 @@ private void checkNearbyBlocks(SimpleCollisionBox pointThreeBox) {

// Check for flowing water
Collisions.hasMaterial(player, pointThreeBox, (pair) -> {
WrappedBlockState state = pair.getFirst();
if (Materials.isClimbable(state.getType()) || (state.getType() == StateTypes.POWDER_SNOW && !player.compensatedEntities.getSelf().inVehicle() && player.getInventory().getBoots().getType() == ItemTypes.LEATHER_BOOTS)) {
final WrappedBlockState state = pair.getFirst();
final StateType stateType = state.getType();
if (player.tagManager.block(SyncedTags.CLIMBABLE).contains(stateType) || (stateType == StateTypes.POWDER_SNOW && !player.compensatedEntities.getSelf().inVehicle() && player.getInventory().getBoots().getType() == ItemTypes.LEATHER_BOOTS)) {
isNearClimbable = true;
}

if (BlockTags.TRAPDOORS.contains(state.getType())) {
if (BlockTags.TRAPDOORS.contains(stateType)) {
isNearClimbable = isNearClimbable || Collisions.trapdoorUsableAsLadder(player, pair.getSecond().getX(), pair.getSecond().getY(), pair.getSecond().getZ(), state);
}

if (state.getType() == StateTypes.BUBBLE_COLUMN) {
if (stateType == StateTypes.BUBBLE_COLUMN) {
isNearBubbleColumn = true;
}

Expand Down
66 changes: 66 additions & 0 deletions src/main/java/ac/grim/grimac/utils/data/tags/SyncedTag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ac.grim.grimac.utils.data.tags;

import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTags;

import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;

public final class SyncedTag<T> {

private final ResourceLocation location;
private final Set<T> values;
private final Function<Integer, T> remapper;

private SyncedTag(ResourceLocation location, Function<Integer, T> remapper, Set<T> defaultValues) {
this.location = location;
this.values = new HashSet<>();
this.remapper = remapper;
this.values.addAll(defaultValues);
}

public static <T> Builder<T> builder(ResourceLocation location) {
return new Builder<>(location);
}

public ResourceLocation location() {
return location;
}

public boolean contains(T value) {
return values.contains(value);
}

public void readTagValues(WrapperPlayServerTags.Tag tag) {
// Server is sending tag replacement, clear default values.
values.clear();
for (int id : tag.getValues()) {
values.add(remapper.apply(id));
}
}

public static final class Builder<T> {
private final ResourceLocation location;
private Function<Integer, T> remapper;
private Set<T> defaultValues;

private Builder(ResourceLocation location) {
this.location = location;
}

public Builder<T> remapper(Function<Integer, T> remapper) {
this.remapper = remapper;
return this;
}

public Builder<T> defaults(Set<T> defaultValues) {
this.defaultValues = defaultValues;
return this;
}

public SyncedTag<T> build() {
return new SyncedTag<>(location, remapper, defaultValues);
}
}
}
65 changes: 65 additions & 0 deletions src/main/java/ac/grim/grimac/utils/data/tags/SyncedTags.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ac.grim.grimac.utils.data.tags;

import ac.grim.grimac.player.GrimPlayer;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
import com.github.retrooper.packetevents.resources.ResourceLocation;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerTags;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
* This class stores tags that the client is aware of.
*/
public final class SyncedTags {

private static final ServerVersion VERSION = PacketEvents.getAPI().getServerManager().getVersion();

private static final ResourceLocation BLOCK = VERSION.isNewerThanOrEquals(ServerVersion.V_1_21) ? ResourceLocation.minecraft("block") : ResourceLocation.minecraft("blocks");

public static final ResourceLocation CLIMBABLE = ResourceLocation.minecraft("climbable");

private final GrimPlayer player;
private final Map<ResourceLocation, Map<ResourceLocation, SyncedTag<?>>> synced;

public SyncedTags(GrimPlayer player) {
this.player = player;
this.synced = new HashMap<>();
trackTags(BLOCK, id -> StateTypes.getById(player.getClientVersion(), id),
SyncedTag.<StateType>builder(CLIMBABLE).defaults(BlockTags.CLIMBABLE.getStates()));
}

@SafeVarargs
private final <T> void trackTags(ResourceLocation location, Function<Integer, T> remapper, SyncedTag.Builder<T>... syncedTags) {
final Map<ResourceLocation, SyncedTag<?>> tags = new HashMap<>(syncedTags.length);
for (SyncedTag.Builder<T> syncedTag : syncedTags) {
syncedTag.remapper(remapper);
final SyncedTag<T> built = syncedTag.build();
tags.put(built.location(), built);
}
synced.put(location, tags);
}

public SyncedTag<StateType> block(ResourceLocation tag) {
final Map<ResourceLocation, SyncedTag<?>> blockTags = synced.get(BLOCK);
return (SyncedTag<StateType>) blockTags.get(tag);
}

public void handleTagSync(WrapperPlayServerTags tags) {
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_13)) return;
tags.getTagMap().forEach((location, tagList) -> {
if (!synced.containsKey(location)) return;
final Map<ResourceLocation, SyncedTag<?>> syncedTags = synced.get(location);
tagList.forEach(tag -> {
if (!syncedTags.containsKey(tag.getKey())) return;
syncedTags.get(tag.getKey()).readTagValues(tag);
});
});
}
}
3 changes: 2 additions & 1 deletion src/main/java/ac/grim/grimac/utils/nmsutil/Collisions.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
import ac.grim.grimac.utils.data.Pair;
import ac.grim.grimac.utils.data.VectorData;
import ac.grim.grimac.utils.data.tags.SyncedTags;
import ac.grim.grimac.utils.latency.CompensatedWorld;
import ac.grim.grimac.utils.math.GrimMath;
import ac.grim.grimac.utils.math.VectorUtils;
Expand Down Expand Up @@ -718,7 +719,7 @@ public static boolean onClimbable(GrimPlayer player, double x, double y, double
return player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_17);
}

if (BlockTags.CLIMBABLE.contains(blockMaterial)) {
if (player.tagManager.block(SyncedTags.CLIMBABLE).contains(blockMaterial)) {
return true;
}

Expand Down
4 changes: 0 additions & 4 deletions src/main/java/ac/grim/grimac/utils/nmsutil/Materials.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,6 @@ public static boolean isGlassPane(StateType type) {
return PANES.contains(type);
}

public static boolean isClimbable(StateType type) {
return BlockTags.CLIMBABLE.contains(type);
}

public static boolean isCauldron(StateType type) {
return BlockTags.CAULDRONS.contains(type);
}
Expand Down

0 comments on commit cd2a182

Please sign in to comment.