Compare commits

...
68 Commits
Author SHA1 Message Date
Nassim Jahnke 83e44641d0 5.0.4 Release 2024-10-14 17:24:05 +02:00
Nassim Jahnke 50084c112d Fix tag related issues to prepare for 1.21.2
- Inline tag values in 1.21 enchantments
- Fix TagRewriter addTags if the server doesn't send values for a registry
- Send the tags packet in 1.12->1.13 before the play login packet to fix tracking in 1.20->1.20.2
2024-10-14 17:16:01 +02:00
EnZaXD 81682f4921 Change description of dump sub command to be more generic (#4180) 2024-10-13 10:33:58 +02:00
Nassim Jahnke 1c339e8b54 Null check input serializer version
Fixes ViaVersion/ViaBackwards#896
2024-10-11 19:37:35 +02:00
EnZaXD 1a9cda0579 Handle WRITTEN_BOOK_CONTENT component in rewriters as well (#4175)
Closes https://github.com/ViaVersion/ViaVersion/issues/4144
2024-10-10 22:42:21 +02:00
EnZaXD 6ad9a71907 Print book conversion errors to default logger in 1.20.2->1.20.3 (#4158) 2024-10-10 22:37:21 +02:00
Nassim Jahnke 9f24576ba7 Update some dependencies 2024-10-10 21:21:54 +02:00
EnZaXD 8661bbc1fc Update required ViaFabric version, don't require fabric-loader (#4174) 2024-10-10 12:26:32 +02:00
EnZaXD 0b5fa37f96 Put title directly into component in 1.8->1.9 bossbar emulation (#4173)
The JsonParser#parseString detection in CommonBoss will detect " " as valid json (JsonNull) and won't wrap it around ComponentUtil#plainToJson like it should, at some point in the future I would like CommonBoss to only accept a JsonElement instance and not raw strings anymore.

Closes https://github.com/ViaVersion/ViaFabricPlus/issues/494
2024-10-10 12:25:27 +02:00
EnZaXD dab32bafa1 Write correct on ground state in 1.20.5->1.21 placement rotation fix (#4170) 2024-10-09 16:37:30 +02:00
Nassim Jahnke 9e5c541f79 Disable placement rotation fix for now
Closes #4168
2024-10-07 21:43:20 +02:00
EnZaXD 9674c617ca Add option to fix wrong block placement rotation in 1.20.5->1.21 (#4166) 2024-10-06 15:19:05 +02:00
EnZaXD 9df1704357 Fix holder set direct id conversion in 1.20.3->1.20.5 component rewriter (#4164) 2024-10-05 21:34:34 +02:00
EnZaXD c0821de2e2 Define as Sponge plugin for ViaSponge (#4163) 2024-10-02 10:41:59 +02:00
Nassim Jahnke c358c39027 Make clearer distinction between filled and empty data component patch, simplify direct value getting 2024-09-29 13:34:32 +02:00
github-actions[bot]andgradle-update-robot 451b3a2637 Update Gradle Wrapper from 8.10.1 to 8.10.2 (#4161)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-09-29 04:19:11 +02:00
Nassim Jahnke 619eecacf8 Don't add block entity tag if the id is missing 2024-09-26 12:16:06 +02:00
RK_01 6bae039d52 Update mcstructs (#4159) 2024-09-24 19:09:32 +02:00
dependabot[bot] b321029886 Bump gradle-update/update-gradle-wrapper-action from 1 to 2 (#4157)
Bumps [gradle-update/update-gradle-wrapper-action](https://github.com/gradle-update/update-gradle-wrapper-action) from 1 to 2.
- [Release notes](https://github.com/gradle-update/update-gradle-wrapper-action/releases)
- [Changelog](https://github.com/gradle-update/update-gradle-wrapper-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gradle-update/update-gradle-wrapper-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: gradle-update/update-gradle-wrapper-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-23 19:44:27 +02:00
EnZaXD 5287d4fb4f Fix enchantment glint behaviour in 1.10->1.11 (#4156) 2024-09-23 19:24:46 +02:00
EnZaXD a0a2794291 Change player parent to living entity base in 1.9/1.12 entity enums (#4154) 2024-09-20 13:35:58 +02:00
EnZaXD 9e354e956e Update MCStructs (#4153) 2024-09-20 13:35:48 +02:00
EnZaXD 27033e9096 Remove transaction tracking (and cancelling) in 1.16.4->1.17 (#4140) 2024-09-15 21:52:32 +02:00
EnZaXD e436bbe375 Refactor dimension switch handling across all protocols (#4146) 2024-09-15 21:51:29 +02:00
EnZaXD 050a1dbacb Fix set equipment body slot in 1.20.3->.5 if value is not the last (#4149) 2024-09-15 19:14:42 +02:00
github-actions[bot]andgradle-update-robot ae1838d78a Update Gradle Wrapper from 8.10 to 8.10.1. (#4148)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-09-15 09:51:02 +02:00
EnZaXD 7235485802 Cleanup enchantment conversion in 1.12->1.13 to match vanilla (#4147)
Closes https://github.com/ViaVersion/ViaFabricPlus/issues/560
2024-09-14 21:33:18 +02:00
EnZaXD fcb472347e Add EntityTrackerBase#hasClientEntityId and don't use -1 as not set indicator (#4143) 2024-09-14 10:45:19 +02:00
EnZaXD e0ce8cc715 Make EntityTrackerBase#clearEntities call removeEntity for all entries (#4142) 2024-09-12 22:09:52 +02:00
EnZaXD ebc0e61be8 Fix invalid book view not visible in 1.20.3->.5 (#4139) 2024-09-07 10:45:10 +02:00
Nassim Jahnke 95581a6fa5 Fix mapping reading of changed_id type 2024-09-05 10:02:55 +02:00
EnZaXD d0b49009e5 Rewrite display name component in player info packet in 1.20.3->.5 (#4136) 2024-09-04 20:27:38 +02:00
Nassim Jahnke 369b076cad Null check channel in player join listener
Fixes #3390
2024-09-03 16:43:55 +02:00
Nassim Jahnke 6555bcda74 Small cleanup to mapping file loading 2024-09-02 23:21:29 +02:00
Nassim Jahnke e537dbb024 Clean up StructuredItemRewriter, also handle sound events 2024-08-30 19:10:43 +02:00
Nassim Jahnke f92dbb655d Also cache missing protocol paths, don't reverse base protocols 2024-08-30 11:19:32 +02:00
RK_01 0b2dac9056 Copy item in Particle#copy (#4130) 2024-08-29 23:28:39 +02:00
EnZaXD 7cd5514b90 Add PacketWrapper#sendFutureRaw, cleanup login disconnect handling. (#4129)
Removes the special handling in Protocol1_8To1_9 and always send the correct/expected data by the client in ServerboundBaseProtocol1_7 itself. Also prevent sending the packet through the protocol pipeline since packet/format changes should also be handled inside the base protocol.
2024-08-29 21:46:43 +02:00
RK_01 5017d4bbb3 Add Particle#copy (#4126) 2024-08-29 15:32:28 +02:00
EnZaXD 32e51b52aa Cleanup LOGIN/STATUS packet handlers (#4113) 2024-08-28 15:52:28 +02:00
Nassim Jahnke 4f66fd793b Go back to fast entity data list iteration and mutation
This is a fairly hot method and the array list cannot be modified outside of the already managed event cancellation and provided extra list
2024-08-25 18:59:48 +02:00
Nassim Jahnke 2a71612aea Small cleanup of a few rewriters 2024-08-25 18:42:21 +02:00
Nassim Jahnke a993a08b8d Only map between different primitive types when explicitly requested
This would otherwise only happen with unsafe type usage
2024-08-24 18:00:06 +02:00
Nassim Jahnke a9c947517c Don't unnecessarily re-wrap objects in passthrough 2024-08-24 17:10:20 +02:00
Pablo Herrera 2841bf3040 Add option to hide scoreboard numbers (#4122) 2024-08-24 15:49:09 +02:00
RK_01 7edddda36e Split base protocols list (#4118) 2024-08-23 14:09:14 +02:00
RK_01 33de12ceb1 Reset reader before passing packet through protocols (#4117) 2024-08-23 09:42:50 +02:00
RK_01 f8eb57cdbb Fix 1.8->1.9 click sound mappings (#4116) 2024-08-22 19:39:09 +02:00
EnZaXD b2d523f5c0 Add more API for base protocols and skip manually added ones. (#4115) 2024-08-22 17:15:29 +02:00
EnZaXD b586b0d361 Allow client intention packet to be cancelled (#4114) 2024-08-22 10:59:35 +02:00
EnZaXD c6381e7f4d Allow protocols to handle client intention packet (#4112) 2024-08-21 19:58:32 +02:00
EnZaXD 10ee7e1930 Deprecate StoredObject#getUser (#4104) 2024-08-21 19:14:40 +02:00
EnZaXD 78abf8be00 Use RedirectProtocolVersion#getOrigin in InitialBaseProtocol if possible (#4110)
This way, we should be able to get rid of manually adding the base protocol in projects like ViaAprilFools:
https://github.com/ViaVersion/ViaAprilFools/blob/main/common/src/main/java/net/raphimc/viaaprilfools/protocol/s3d_sharewaretov1_14/Protocol3D_SharewareTo1_14.java#L87
2024-08-21 16:56:20 +02:00
EnZaXD 1dde24bb68 [ci skip] Remove outdated comments (#4111) 2024-08-21 16:56:09 +02:00
EnZaXD bc57512ca2 Allow for multiple base protocols per version (#4106) 2024-08-21 14:35:19 +02:00
github-actions[bot]andgradle-update-robot 6ad3beca76 Update Gradle Wrapper from 8.9 to 8.10. (#4105)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2024-08-18 11:04:12 +02:00
EnZaXD 9d75125e41 Make EntityTrackerBase#entities protected (#4103) 2024-08-18 11:03:57 +02:00
RK_01 8ce4112e86 Improve/Fix 1.8->1.9 sound mappings (#4099) 2024-08-14 18:04:37 +02:00
EnZaXD 7d542d5667 Fix ComponentRewriter1_20_5#convertFood behaviour (#4095)
Closes https://github.com/ViaVersion/ViaFabricPlus/issues/517
2024-08-14 15:26:22 +02:00
EnZaXD 7d6599b90e [ci skip] Setup dependabot for GH Actions and add workflow for updating the Gradle Wrapper (#4097) 2024-08-14 15:01:57 +02:00
EnZaXD 1b03e24160 Move VV specific item handling out of component<->nbt conversion in 1.20.3->1.20.5 (#4094)
The current code backups the tag in CUSTOM_DATA inside the toStructuredItem function which in VB is used for to server packets which causes bad data, this PR moves the backup logic out to the VV specific handler and also prevents toOldItem logic for using the backup to ever get executed in VB. The counterpart PR will add proper handling for CUSTOM_DATA.

Fixes https://github.com/ViaVersion/ViaVersion/issues/4092
2024-08-14 09:31:27 +02:00
Nassim Jahnke fcd91bb855 Add item cost and particle types to item rewriter 2024-08-13 12:45:36 +02:00
Nassim Jahnke bda4ea9fd0 [ci skip] Move template protocol into common module
Had to move the rewriter classes into the flattened package to make them package private, but this is nicer than having a separate module just for those
2024-08-13 10:24:20 +02:00
FlorianMichael cbd26ce9d9 [ci skip] Link to our new website instead 2024-08-13 10:14:22 +02:00
Nassim Jahnke 8d53f4aa5a Update mcstructs 2024-08-13 09:59:59 +02:00
EnZaXD 1438f1f68d [ci skip] Update README.md (#4088) 2024-08-11 11:33:12 +02:00
RK_01 61fcf6f895 Update 1.21 version range (#4082) 2024-08-08 17:27:38 +02:00
Nassim Jahnke 736834441d [ci skip] Update shadow 2024-08-08 10:55:56 +02:00
118 changed files with 1696 additions and 1055 deletions

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
@@ -0,0 +1,14 @@
name: Update Gradle Wrapper
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * 0"
jobs:
update-gradle-wrapper:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v2
+4 -4
View File
@@ -9,9 +9,9 @@ it works on any platform you can think of.**
The base ViaVersion jar runs on Paper and Velocity. We also have projects integrating ViaVersion to run
on Fabric, Forge, Bungee, Sponge, or as a standalone proxy to join from basically any client version on
any server version from the past decade. **See [HERE](https://github.com/ViaVersion) for an overview of the different Via\* projects.**
any server version from the past decade. **See [HERE](https://viaversion.com) for an overview of the different Via\* projects.**
Note that ViaVersion will be able to **run best on either Paper servers or Fabric clients** due to having
Note that ViaVersion will be able to **run best on either Paper servers or through [ViaFabricPlus](https://github.com/ViaVersion/ViaFabricPlus?tab=readme-ov-file#viafabricplus)** due to having
direct access to client/server state and more extensive API.
Supported Versions:
@@ -83,7 +83,7 @@ You need JDK 17 or newer to build ViaVersion.
Mapping Files
--------------
Mapping files are generated and managed in our [Mappings repository](https://github.com/ViaVersion/Mappings).
Mapping files are generated and managed in our [Mappings repository](https://github.com/ViaVersion/Mappings). The generated mapping output is stored [here](./common/src/main/resources/assets/viaversion).
Resources
@@ -96,7 +96,7 @@ Resources
License
--------
The entirety of the [API directory](api) (including the legacy API directory) is licensed under the MIT License;
The entirety of the [API directory](api) is licensed under the MIT License;
see [licenses/MIT.md](licenses/MIT.md) for
details.
@@ -464,4 +464,18 @@ public interface ViaVersionConfig extends Config {
* @return true if enabled
*/
boolean cancelBlockSounds();
/**
* Hides scoreboard numbers for 1.20.3+ clients on older server versions.
*
* @return true if enabled
*/
boolean hideScoreboardNumbers();
/**
* Fixes 1.21+ clients on 1.20.5 servers placing water/lava buckets at the wrong location when moving fast.
*
* @return true if enabled
*/
boolean fix1_21PlacementRotation();
}
@@ -29,6 +29,11 @@ public abstract class StoredObject implements StorableObject {
this.user = user;
}
public UserConnection user() {
return this.user;
}
@Deprecated
public UserConnection getUser() {
return user;
}
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.connection;
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketTracker;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
@@ -99,14 +100,33 @@ public interface UserConnection {
void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker);
/**
* Clear stored objects and entity trackers.
* Returns the client world by the given protocol class if present.
*
* @param protocolClass protocol class
* @param <T> client world type
* @return client world if present
*/
@Nullable
<T extends ClientWorld> T getClientWorld(Class<? extends Protocol> protocolClass);
/**
* Adds a client world to the user connection.
* Does not override existing client worlds.
*
* @param protocolClass protocol class
* @param clientWorld client world
*/
void addClientWorld(Class<? extends Protocol> protocolClass, ClientWorld clientWorld);
/**
* Clear stored objects, entity trackers and client worlds.
*/
default void clearStoredObjects() {
clearStoredObjects(false);
}
/**
* Clear stored objects and entity trackers.
* Clear stored objects, entity trackers and client worlds.
* If cleared for a proxy server switch, some stored objects and tracker data will be retained.
*
* @param isServerSwitch whether the clear is due to a server switch
@@ -83,6 +83,10 @@ public interface MappingData {
int getNewAttributeId(int id);
int getNewSoundId(int id);
int getOldSoundId(int i);
/**
* Returns a list of tags to send if present.
*
@@ -203,6 +203,16 @@ public class MappingDataBase implements MappingData {
return checkValidity(id, attributeMappings.getNewId(id), "attributes");
}
@Override
public int getNewSoundId(final int id) {
return checkValidity(id, soundMappings.getNewId(id), "sound");
}
@Override
public int getOldSoundId(final int i) {
return soundMappings.getNewIdOrDefault(i, 0);
}
@Override
public @Nullable List<TagData> getTags(final RegistryType type) {
return tags != null ? tags.get(type) : null;
@@ -315,4 +325,4 @@ public class MappingDataBase implements MappingData {
protected void loadExtras(final CompoundTag data) {
}
}
}
@@ -30,7 +30,6 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.viaversion.nbt.io.NBTIO;
import com.viaversion.nbt.io.TagReader;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.IntTag;
@@ -211,68 +210,64 @@ public class MappingDataLoader {
return null;
}
final ByteTag serializationStragetyTag = tag.getUnchecked("id");
final IntTag mappedSizeTag = tag.getUnchecked("mappedSize");
final byte strategy = serializationStragetyTag.asByte();
final int mappedSize = tag.getIntTag("mappedSize").asInt();
final byte strategy = tag.getByteTag("id").asByte();
final V mappings;
if (strategy == DIRECT_ID) {
final IntArrayTag valuesTag = tag.getIntArrayTag("val");
return IntArrayMappings.of(valuesTag.getValue(), mappedSizeTag.asInt());
return IntArrayMappings.of(valuesTag.getValue(), mappedSize);
} else if (strategy == SHIFTS_ID) {
final IntArrayTag shiftsAtTag = tag.getIntArrayTag("at");
final IntArrayTag shiftsTag = tag.getIntArrayTag("to");
final IntTag sizeTag = tag.getUnchecked("size");
final int[] shiftsAt = shiftsAtTag.getValue();
final int[] shiftsTo = shiftsTag.getValue();
final int size = sizeTag.asInt();
final int[] shiftsAt = tag.getIntArrayTag("at").getValue();
final int[] shiftsTo = tag.getIntArrayTag("to").getValue();
final int size = tag.getIntTag("size").asInt();
mappings = holderSupplier.get(size);
// Handle values until first shift
if (shiftsAt[0] != 0) {
// Add identity values before the first shift
final int to = shiftsAt[0];
for (int id = 0; id < to; id++) {
addConsumer.addTo(mappings, id, id);
}
}
// Handle shifts
// Read shifts
for (int i = 0; i < shiftsAt.length; i++) {
final boolean isLast = i == shiftsAt.length - 1;
final int from = shiftsAt[i];
final int to = i == shiftsAt.length - 1 ? size : shiftsAt[i + 1];
final int to = isLast ? size : shiftsAt[i + 1];
int mappedId = shiftsTo[i];
for (int id = from; id < to; id++) {
addConsumer.addTo(mappings, id, mappedId++);
}
}
} else if (strategy == CHANGES_ID) {
final IntArrayTag changesAtTag = tag.getIntArrayTag("at");
final IntArrayTag valuesTag = tag.getIntArrayTag("val");
final IntTag sizeTag = tag.getUnchecked("size");
final int[] changesAt = tag.getIntArrayTag("at").getValue();
final int[] values = tag.getIntArrayTag("val").getValue();
final int size = tag.getIntTag("size").asInt();
final boolean fillBetween = tag.get("nofill") == null;
final int[] changesAt = changesAtTag.getValue();
final int[] values = valuesTag.getValue();
mappings = holderSupplier.get(sizeTag.asInt());
mappings = holderSupplier.get(size);
int nextUnhandledId = 0;
for (int i = 0; i < changesAt.length; i++) {
final int id = changesAt[i];
final int changedId = changesAt[i];
if (fillBetween) {
// Fill from after the last change to before this change with unchanged ids
final int previousId = i != 0 ? changesAt[i - 1] + 1 : 0;
for (int identity = previousId; identity < id; identity++) {
addConsumer.addTo(mappings, identity, identity);
for (int id = nextUnhandledId; id < changedId; id++) {
addConsumer.addTo(mappings, id, id);
}
nextUnhandledId = changedId + 1;
}
// Assign the changed value
addConsumer.addTo(mappings, id, values[i]);
addConsumer.addTo(mappings, changedId, values[i]);
}
} else if (strategy == IDENTITY_ID) {
final IntTag sizeTag = tag.getUnchecked("size");
return new IdentityMappings(sizeTag.asInt(), mappedSizeTag.asInt());
final IntTag sizeTag = tag.getIntTag("size");
return new IdentityMappings(sizeTag.asInt(), mappedSize);
} else {
throw new IllegalArgumentException("Unknown serialization strategy: " + strategy);
}
return mappingsSupplier.create(mappings, mappedSizeTag.asInt());
return mappingsSupplier.create(mappings, mappedSize);
}
public @Nullable List<String> identifiersFromGlobalIds(final CompoundTag mappingsTag, final String key) {
@@ -295,7 +290,7 @@ public class MappingDataLoader {
* @return map with indexes hashed by their id value
*/
public Object2IntMap<String> indexedObjectToMap(final JsonObject object) {
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(object.size(), .99F);
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(object.size());
map.defaultReturnValue(-1);
for (final Map.Entry<String, JsonElement> entry : object.entrySet()) {
map.put(entry.getValue().getAsString(), Integer.parseInt(entry.getKey()));
@@ -310,7 +305,7 @@ public class MappingDataLoader {
* @return map with indexes hashed by their id value
*/
public Object2IntMap<String> arrayToMap(final JsonArray array) {
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(array.size(), .99F);
final Object2IntMap<String> map = new Object2IntOpenHashMap<>(array.size());
map.defaultReturnValue(-1);
for (int i = 0; i < array.size(); i++) {
map.put(array.get(i).getAsString(), i);
@@ -78,7 +78,7 @@ public interface EntityTracker {
void removeEntity(int id);
/**
* Clears stored entity types and data.
* Clears stored entity types and data, only leaving behind the client entity.
*/
void clearEntities();
@@ -102,11 +102,19 @@ public interface EntityTracker {
@Nullable StoredEntityData entityDataIfPresent(int id);
/**
* Returns the client entity id or -1 if unset.
* Returns whether the client entity id has been set.
*
* @return client entity id or -1 if unset
* @return whether the client entity id has been set
*/
int clientEntityId();
boolean hasClientEntityId();
/**
* Returns the client entity id. Should be wrapped around {@link #hasClientEntityId()}.
*
* @return client entity id
* @throws IllegalStateException if the client entity id has not been set
*/
int clientEntityId() throws IllegalStateException;
/**
* Sets the client entity id.
@@ -169,12 +177,4 @@ public interface EntityTracker {
@Nullable DimensionData dimensionData(int dimensionId);
void setDimensions(Map<String, DimensionData> dimensions);
/**
* Adds the client player entity to the tracker.
* If the client entity has not been set yet, this will return false.
*
* @return whether the client has been tracked
*/
boolean trackClientEntity();
}
@@ -23,13 +23,12 @@
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.connection.StorableObject;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Stored up until 1.14 to be used in chunk sending.
*/
public class ClientWorld implements StorableObject {
private Environment environment;
private Environment environment = Environment.NORMAL;
public ClientWorld() {
}
@@ -38,11 +37,20 @@ public class ClientWorld implements StorableObject {
this.environment = environment;
}
public @Nullable Environment getEnvironment() {
public Environment getEnvironment() {
return environment;
}
public void setEnvironment(final int environmentId) {
/**
* Sets the environment of the world and returns whether the environment was changed.
*
* @param environmentId the id of the environment to set
* @return whether the environment was changed
*/
public boolean setEnvironment(final int environmentId) {
final int previousEnvironmentId = environment.id();
this.environment = Environment.getEnvironmentById(environmentId);
return previousEnvironmentId != environmentId;
}
}
@@ -22,6 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public interface Holder<T> {
/**
@@ -79,4 +81,12 @@ public interface Holder<T> {
* @see #hasId()
*/
int id();
/**
* Returns a new holder with the id rewritten using the given function, or self if this is a direct holder or the id did not change.
*
* @param rewriteFunction the function to rewrite the id
* @return a new holder with the id rewritten, or self
*/
Holder<T> updateId(final Int2IntFunction rewriteFunction);
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
final class HolderImpl<T> implements Holder<T> {
@@ -61,6 +62,22 @@ final class HolderImpl<T> implements Holder<T> {
return id;
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
if (isDirect()) {
return this;
}
final int rewrittenId = rewriteFunction.applyAsInt(id);
if (rewrittenId == id) {
return this;
}
if (rewrittenId == -1) {
throw new IllegalArgumentException("Received invalid id in updateId");
}
return Holder.of(rewrittenId);
}
@Override
public String toString() {
return "HolderImpl{" +
@@ -64,7 +64,7 @@ final class HolderSetImpl extends EitherImpl<String, int[]> implements HolderSet
final int[] ids = ids();
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.apply(ids[i]);
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
}
return new HolderSetImpl(mappedIds);
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.IdHolder;
@@ -72,6 +73,14 @@ public final class Particle implements IdHolder {
arguments.set(index, new ParticleData<>(type, value));
}
public Particle copy() {
final Particle particle = new Particle(id);
for (ParticleData<?> argument : arguments) {
particle.arguments.add(argument.copy());
}
return particle;
}
@Override
public String toString() {
return "Particle{" +
@@ -109,6 +118,14 @@ public final class Particle implements IdHolder {
wrapper.write(type, value);
}
public ParticleData<T> copy() {
if (value instanceof Item item) {
return new ParticleData<>(type, (T) item.copy());
} else {
return new ParticleData<>(type, value);
}
}
@Override
public String toString() {
return "ParticleData{" +
@@ -52,16 +52,14 @@ public interface StructuredData<T> extends IdHolder {
return new EmptyStructuredData<>(key, id);
}
void setValue(final T value);
@Nullable T value();
void write(final ByteBuf buffer);
void setValue(final T value);
void setId(final int id);
StructuredDataKey<T> key();
@Nullable T value();
/**
* Returns whether the structured data is present. Even if true, the value may be null.
*
@@ -77,4 +75,6 @@ public interface StructuredData<T> extends IdHolder {
* @return true if the structured data is empty
*/
boolean isEmpty();
void write(final ByteBuf buffer);
}
@@ -33,6 +33,26 @@ import java.util.Map;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Loosely represents Minecraft's data component patch, but may also be used for an item's full data components.
* <p>
* The most commonly used methods will ignore empty data (aka empty overrides that remove item defaults) since those will rarely be needed.
* These are:
* <ul>
* <li>{@link #get(StructuredDataKey)}</li>
* <li>{@link #set(StructuredDataKey, Object)}</li>
* <li>{@link #set(StructuredDataKey)}</li>
* <li>{@link #getNonEmptyData(StructuredDataKey)}</li>
* <li>{@link #hasValue(StructuredDataKey)}</li>
* </ul>
*
* To interact with empty patches specifically, use:
* <ul>
* <li>{@link #setEmpty(StructuredDataKey)}</li>
* <li>{@link #hasEmpty(StructuredDataKey)}</li>
* </ul>
* Other methods (e.g. {@link #getData(StructuredDataKey)} and {@link #has(StructuredDataKey)}) will handle both empty and non-empty data.
*/
public final class StructuredDataContainer {
private final Map<StructuredDataKey<?>, StructuredData<?>> data;
@@ -55,66 +75,45 @@ public final class StructuredDataContainer {
}
/**
* Returns structured data by id if present.
* Returns the non-empty value by id if present.
*
* @param key serializer id
* @param <T> data type
* @return structured data
* @see #hasEmpty(StructuredDataKey)
*/
public @Nullable <T> T get(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.get(key);
if (data == null || data.isEmpty()) {
return null;
}
//noinspection unchecked
return ((StructuredData<T>) data).value();
}
/**
* Returns structured data by id if present, either empty or non-empty.
*
* @param key serializer id
* @param <T> data type
* @return structured data
*/
public @Nullable <T> StructuredData<T> get(final StructuredDataKey<T> key) {
public @Nullable <T> StructuredData<T> getData(final StructuredDataKey<T> key) {
//noinspection unchecked
return (StructuredData<T>) this.data.get(key);
}
/**
* Returns structured data by id if not empty.
* Returns non-empty structured data by id if present.
*
* @param key serializer id
* @param <T> data type
* @return structured data if not empty
* @return non-empty structured data
*/
public @Nullable <T> StructuredData<T> getNonEmpty(final StructuredDataKey<T> key) {
public @Nullable <T> StructuredData<T> getNonEmptyData(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.get(key);
//noinspection unchecked
final StructuredData<T> data = (StructuredData<T>) this.data.get(key);
return data != null && data.isPresent() ? data : null;
}
/**
* Returns structured data by id if not empty, or creates it.
*
* @param key serializer id
* @param mappingFunction function to create structured data if not present
* @param <T> data type
* @return structured data if not empty
*/
public <T> StructuredData<T> computeIfAbsent(final StructuredDataKey<T> key, final Function<StructuredDataKey<T>, T> mappingFunction) {
final StructuredData<T> data = this.getNonEmpty(key);
if (data != null) {
return data;
}
final int id = serializerId(key);
final StructuredData<T> empty = StructuredData.of(key, mappingFunction.apply(key), id);
this.data.put(key, empty);
return empty;
}
/**
* Updates and returns the structured data by id if not empty.
*
* @param key serializer id
* @param mappingFunction function to update existing data
* @param <T> data type
* @return updated structured data if not empty
*/
public <T> @Nullable StructuredData<T> updateIfPresent(final StructuredDataKey<T> key, final Function<T, T> mappingFunction) {
final StructuredData<T> data = this.getNonEmpty(key);
if (data == null) {
return null;
}
data.setValue(mappingFunction.apply(data.value()));
return data;
return data != null && data.isPresent() ? (StructuredData<T>) data : null;
}
public <T> void set(final StructuredDataKey<T> key, final T value) {
@@ -124,49 +123,105 @@ public final class StructuredDataContainer {
}
}
public <T> void replaceKey(final StructuredDataKey<T> key, final StructuredDataKey<T> toKey) {
replace(key, toKey, Function.identity());
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, V> valueMapper) {
final StructuredData<T> data = remove(key);
if (data == null) {
return;
}
if (data.isPresent()) {
set(toKey, valueMapper.apply(data.value()));
} else {
addEmpty(toKey);
}
}
public void set(final StructuredDataKey<Unit> key) {
this.set(key, Unit.INSTANCE);
}
public void addEmpty(final StructuredDataKey<?> key) {
public void setEmpty(final StructuredDataKey<?> key) {
// Empty optional to override the Minecraft default
this.data.put(key, StructuredData.empty(key, serializerId(key)));
}
/**
* Removes and returns structured data by the given key.
* Updates the structured data by id if not empty.
*
* @param key serializer key
* @param <T> data type
* @return removed structured data
* @param key serializer id
* @param valueMapper function to update existing data
* @param <T> data type
*/
public @Nullable <T> StructuredData<T> remove(final StructuredDataKey<T> key) {
final StructuredData<?> data = this.data.remove(key);
//noinspection unchecked
return data != null ? (StructuredData<T>) data : null;
public <T> void replace(final StructuredDataKey<T> key, final Function<T, @Nullable T> valueMapper) {
final StructuredData<T> data = this.getNonEmptyData(key);
if (data == null) {
return;
}
final T replacement = valueMapper.apply(data.value());
if (replacement != null) {
data.setValue(replacement);
} else {
this.data.remove(key);
}
}
public boolean contains(final StructuredDataKey<?> key) {
public <T> void replaceKey(final StructuredDataKey<T> key, final StructuredDataKey<T> toKey) {
replace(key, toKey, Function.identity());
}
public <T, V> void replace(final StructuredDataKey<T> key, final StructuredDataKey<V> toKey, final Function<T, @Nullable V> valueMapper) {
final StructuredData<?> data = this.data.remove(key);
if (data == null) {
return;
}
if (data.isPresent()) {
//noinspection unchecked
final T value = (T) data.value();
final V replacement = valueMapper.apply(value);
if (replacement != null) {
set(toKey, replacement);
}
} else {
// Also replace the key for empty data
setEmpty(toKey);
}
}
/**
* Removes data by the given key.
*
* @param key data key
* @see #replace(StructuredDataKey, Function)
* @see #replace(StructuredDataKey, StructuredDataKey, Function)
* @see #replaceKey(StructuredDataKey, StructuredDataKey)
*/
public void remove(final StructuredDataKey<?> key) {
this.data.remove(key);
}
/**
* Returns whether there is data for the given key, either empty or non-empty.
*
* @param key data key
* @return whether there data for the given key
* @see #hasEmpty(StructuredDataKey)
* @see #hasValue(StructuredDataKey)
*/
public boolean has(final StructuredDataKey<?> key) {
return this.data.containsKey(key);
}
/**
* Returns whether there is non-empty data for the given key.
*
* @param key data key
* @return whether there is non-empty data for the given key
*/
public boolean hasValue(final StructuredDataKey<?> key) {
final StructuredData<?> data = this.data.get(key);
return data != null && data.isPresent();
}
/**
* Returns whether the structured data has an empty patch/override.
*
* @param key serializer id
* @return whether the structured data has an empty patch/override
*/
public boolean hasEmpty(final StructuredDataKey<?> key) {
final StructuredData<?> data = this.data.get(key);
return data != null && data.isEmpty();
}
/**
* Sets the lookup for serializer ids. Required to call most of the other methods.
*
@@ -101,7 +101,7 @@ public class EntityTypes1_12 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(ENTITY), // Needed for entity (un)tracking
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking
// Living entities as a larger subclass
LIVING_ENTITY(LIVING_ENTITY_BASE),
@@ -99,7 +99,7 @@ public class EntityTypes1_9 {
LIVING_ENTITY_BASE(ENTITY),
ARMOR_STAND(30, LIVING_ENTITY_BASE),
PLAYER(ENTITY), // Needed for entity (un)tracking
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking
// Living entities as a larger subclass
LIVING_ENTITY(48, LIVING_ENTITY_BASE),
@@ -26,6 +26,7 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean showInTooltip) {
@@ -44,6 +45,15 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
}
};
public AttributeModifiers1_21 rewrite(final Int2IntFunction rewriteFunction) {
final AttributeModifier[] modifiers = new AttributeModifier[this.modifiers.length];
for (int i = 0; i < this.modifiers.length; i++) {
final AttributeModifier modifier = this.modifiers[i];
modifiers[i] = new AttributeModifier(rewriteFunction.applyAsInt(modifier.attribute()), modifier.modifier(), modifier.slotType());
}
return new AttributeModifiers1_21(modifiers, showInTooltip);
}
public record AttributeModifier(int attribute, ModifierData modifier, int slotType) {
public static final Type<AttributeModifier> TYPE = new Type<>(AttributeModifier.class) {
@@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record Instrument(Holder<SoundEvent> soundEvent, int useDuration, float range) {
@@ -47,4 +48,8 @@ public record Instrument(Holder<SoundEvent> soundEvent, int useDuration, float r
}
};
public Instrument rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument(soundEvent, useDuration, range);
}
}
@@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Either;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean showInTooltip) {
@@ -56,6 +57,20 @@ public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean
}
};
public JukeboxPlayable rewrite(final Int2IntFunction soundIdRewriteFunction) {
if (song.isRight()) {
return this;
}
final Holder<JukeboxSong> songHolder = this.song.left();
if (songHolder.hasId()) {
return this;
}
final JukeboxSong rewrittenSong = songHolder.value().rewrite(soundIdRewriteFunction);
return rewrittenSong == songHolder.value() ? this : new JukeboxPlayable(Holder.of(rewrittenSong), showInTooltip);
}
public record JukeboxSong(Holder<SoundEvent> soundEvent, Tag description,
float lengthInSeconds, int comparatorOutput) {
@@ -77,5 +92,10 @@ public record JukeboxPlayable(Either<Holder<JukeboxSong>, String> song, boolean
Types.VAR_INT.writePrimitive(buffer, value.comparatorOutput);
}
};
public JukeboxSong rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
}
}
}
@@ -1,56 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.Map;
public record MapDecorations(Map<String, MapDecoration> decorations) {
public static final Type<MapDecorations> TYPE = new Type<>(MapDecorations.class) {
@Override
public MapDecorations read(final ByteBuf buffer) {
final Object2ObjectMap<String, MapDecoration> decorations = new Object2ObjectOpenHashMap<>();
final int size = Types.VAR_INT.readPrimitive(buffer);
for (int i = 0; i < size; i++) {
final String id = Types.STRING.read(buffer);
final MapDecoration decoration = MapDecoration.TYPE.read(buffer);
decorations.put(id, decoration);
}
return new MapDecorations(decorations);
}
@Override
public void write(final ByteBuf buffer, final MapDecorations value) {
Types.VAR_INT.writePrimitive(buffer, value.decorations.size());
for (final Map.Entry<String, MapDecoration> entry : value.decorations.entrySet()) {
Types.STRING.write(buffer, entry.getKey());
MapDecoration.TYPE.write(buffer, entry.getValue());
}
}
};
}
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api.protocol;
import com.google.common.collect.Range;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
@@ -73,13 +74,14 @@ public interface ProtocolManager {
Protocol getBaseProtocol();
/**
* Returns the base protocol for a specific server protocol version.
* Returns the base protocols for a specific server and client protocol version.
* The standard base protocols deal with status and login packets for userconnection initialization.
*
* @param clientVersion client protocol version
* @param serverVersion server protocol version
* @return base protocol for the given server protocol version if present, else null
* @return base protocols for the given server and client protocol version
*/
@Nullable Protocol getBaseProtocol(ProtocolVersion serverVersion);
List<Protocol> getBaseProtocols(@Nullable ProtocolVersion clientVersion, @Nullable ProtocolVersion serverVersion);
/**
* Returns an immutable collection of registered protocols.
@@ -120,11 +122,12 @@ public interface ProtocolManager {
* Registers and initializes a base protocol. Base Protocols registered later have higher priority.
* Only base protocol will always be added to pipeline.
*
* @param direction direction of the base protocol
* @param baseProtocol base protocol to register
* @param supportedProtocols protocol versions supported by the base protocol
* @throws IllegalArgumentException if the protocol is not a base protocol as given by {@link Protocol#isBaseProtocol()}
*/
void registerBaseProtocol(Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols);
void registerBaseProtocol(Direction direction, Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols);
/**
* Calculates and returns the protocol path from a client protocol version to server protocol version.
@@ -145,6 +145,18 @@ public interface PacketWrapper {
*/
<T> T passthrough(Type<T> type) throws InformativeException;
/**
* Take a value from the input and write to the output, mapping the output type.
* This only works for types implementing {@link com.viaversion.viaversion.api.type.TypeConverter}, which is generally only the primitive wrapper types.
*
* @param type The type to read.
* @param mappedType The type to write.
* @param <T> The return type of the type you wish to pass through.
* @return The type which was read/written.
* @throws InformativeException If it failed to read or write
*/
<T> T passthroughAndMap(Type<?> type, Type<T> mappedType) throws InformativeException;
/**
* Take all the inputs and write them to the output.
*
@@ -224,6 +236,14 @@ public interface PacketWrapper {
*/
void sendRaw() throws InformativeException;
/**
* Sends this packet to the associated user, submitted to netty's event loop.
* <b>Unlike {@link #sendFuture(Class)}, this method does not handle the pipeline with packet id and data changes.</b>
*
* @throws InformativeException if it fails to write
*/
ChannelFuture sendFutureRaw() throws InformativeException;
/**
* Sends this packet to the associated user, submitted to netty's event loop.
* <b>Unlike {@link #send(Class)}, this method does not handle the pipeline with packet id and data changes.</b>
@@ -54,7 +54,7 @@ public abstract class PacketHandlers implements PacketHandler {
* @param type type to map
*/
public <T> void map(Type<T> type) {
handler(wrapper -> wrapper.write(type, wrapper.read(type)));
handler(wrapper -> wrapper.passthrough(type));
}
/**
@@ -63,8 +63,8 @@ public abstract class PacketHandlers implements PacketHandler {
* @param oldType old type
* @param newType new type
*/
public void map(Type oldType, Type newType) {
handler(wrapper -> wrapper.write(newType, wrapper.read(oldType)));
public void map(Type<?> oldType, Type<?> newType) {
handler(wrapper -> wrapper.passthroughAndMap(oldType, newType));
}
/**
@@ -84,7 +84,7 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_20_2 = register(764, "1.20.2");
public static final ProtocolVersion v1_20_3 = register(765, "1.20.3-1.20.4", new SubVersionRange("1.20", 3, 4));
public static final ProtocolVersion v1_20_5 = register(766, "1.20.5-1.20.6", new SubVersionRange("1.20", 5, 6));
public static final ProtocolVersion v1_21 = register(767, "1.21");
public static final ProtocolVersion v1_21 = register(767, "1.21-1.21.1", new SubVersionRange("1.21", 0, 1));
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
public static ProtocolVersion register(int version, String name) {
+1 -1
View File
@@ -8,5 +8,5 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.github.johnrengelman", "shadow", "8.1.1")
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.0")
}
@@ -5,7 +5,7 @@ plugins {
tasks {
// Variable replacements
processResources {
filesMatching(listOf("plugin.yml", "fabric.mod.json")) {
filesMatching(listOf("plugin.yml", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
expand("version" to project.version, "description" to project.description, "url" to "https://viaversion.com")
}
}
@@ -4,7 +4,7 @@ import org.gradle.jvm.tasks.Jar
plugins {
id("via.base-conventions")
id("maven-publish")
id("com.github.johnrengelman.shadow")
id("com.gradleup.shadow")
}
tasks {
@@ -112,7 +112,10 @@ public class JoinListener implements Listener {
return;
}
// The connection has already closed, that was a quick leave
if (!channel.isOpen()) return;
// Channel may be null if a plugin is manually calling the event for a non-player...
if (channel == null || !channel.isOpen()) {
return;
}
UserConnection user = getUserConnection(channel);
if (user == null) {
@@ -30,7 +30,7 @@ public class DumpSubCmd implements ViaSubCommand {
@Override
public String description() {
return "Dump information about your server, this is helpful if you report bugs.";
return "Dump information about your platform implementation, this is helpful if you report bugs.";
}
@Override
@@ -25,14 +25,14 @@ import com.viaversion.viaversion.api.protocol.version.BlockedProtocolVersions;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.BlockedProtocolVersionsImpl;
import com.viaversion.viaversion.util.Config;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class AbstractViaConfig extends Config implements ViaVersionConfig {
@@ -94,6 +94,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean enforceSecureChat;
private boolean handleInvalidItemCount;
private boolean cancelBlockSounds;
private boolean hideScoreboardNumbers;
private boolean fix1_21PlacementRotation;
protected AbstractViaConfig(final File configFile, final Logger logger) {
super(configFile, logger);
@@ -161,6 +163,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
enforceSecureChat = getBoolean("enforce-secure-chat", false);
handleInvalidItemCount = getBoolean("handle-invalid-item-count", false);
cancelBlockSounds = getBoolean("cancel-block-sounds", true);
hideScoreboardNumbers = getBoolean("hide-scoreboard-numbers", false);
fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", false);
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
@@ -542,4 +546,14 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
public boolean cancelBlockSounds() {
return cancelBlockSounds;
}
@Override
public boolean hideScoreboardNumbers() {
return hideScoreboardNumbers;
}
@Override
public boolean fix1_21PlacementRotation() {
return fix1_21PlacementRotation;
}
}
@@ -23,6 +23,7 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.platform.ViaInjector;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.Direction;
@@ -58,6 +59,7 @@ public class UserConnectionImpl implements UserConnection {
private final long id = IDS.incrementAndGet();
private final Map<Class<?>, StorableObject> storedObjects = new ConcurrentHashMap<>();
private final Map<Class<? extends Protocol>, EntityTracker> entityTrackers = new HashMap<>();
private final Map<Class<? extends Protocol>, ClientWorld> clientWorlds = new HashMap<>();
private final PacketTracker packetTracker = new PacketTracker(this);
private final Set<UUID> passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
@@ -125,9 +127,17 @@ public class UserConnectionImpl implements UserConnection {
@Override
public void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker) {
if (!entityTrackers.containsKey(protocolClass)) {
entityTrackers.put(protocolClass, tracker);
}
entityTrackers.putIfAbsent(protocolClass, tracker);
}
@Override
public @Nullable <T extends ClientWorld> T getClientWorld(final Class<? extends Protocol> protocolClass) {
return (T) clientWorlds.get(protocolClass);
}
@Override
public void addClientWorld(final Class<? extends Protocol> protocolClass, final ClientWorld clientWorld) {
clientWorlds.putIfAbsent(protocolClass, clientWorld);
}
@Override
@@ -142,7 +152,6 @@ public class UserConnectionImpl implements UserConnection {
});
for (EntityTracker tracker : entityTrackers.values()) {
tracker.clearEntities();
tracker.trackClientEntity();
}
} else {
for (StorableObject object : storedObjects.values()) {
@@ -150,6 +159,7 @@ public class UserConnectionImpl implements UserConnection {
}
storedObjects.clear();
entityTrackers.clear();
clientWorlds.clear();
}
}
@@ -34,10 +34,10 @@ import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeListener {
private final Int2ObjectMap<TrackedEntity> entities = new Int2ObjectOpenHashMap<>();
protected final Int2ObjectMap<TrackedEntity> entities = new Int2ObjectOpenHashMap<>();
private final UserConnection connection;
private final EntityType playerType;
private int clientEntityId = -1;
private Integer clientEntityId;
private int currentWorldSectionHeight = -1;
private int currentMinY;
private String currentWorld;
@@ -87,7 +87,6 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
return entity != null && entity.hasData() ? entity.data() : null;
}
//TODO Soft memory leak: Remove entities on respawn in protocols prior to 1.18 (1.16+ only when the worldname is different)
@Override
public void removeEntity(int id) {
entities.remove(id);
@@ -95,11 +94,27 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
@Override
public void clearEntities() {
entities.clear();
// Call wrapper function in case protocols need to do additional removals
for (final int id : entities.keySet().toIntArray()) {
removeEntity(id);
}
// Re-add the client entity. Keep the call above to untrack attached data if necessary
if (clientEntityId != null) {
entities.put(clientEntityId.intValue(), new TrackedEntityImpl(playerType));
}
}
@Override
public int clientEntityId() {
public boolean hasClientEntityId() {
return clientEntityId != null;
}
@Override
public int clientEntityId() throws IllegalStateException {
if (clientEntityId == null) {
throw new IllegalStateException("Client entity id not set");
}
return clientEntityId;
}
@@ -107,7 +122,7 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
public void setClientEntityId(int clientEntityId) {
Preconditions.checkNotNull(playerType);
final TrackedEntity oldEntity;
if (this.clientEntityId != -1 && (oldEntity = entities.remove(this.clientEntityId)) != null) {
if (this.clientEntityId != null && (oldEntity = entities.remove(this.clientEntityId.intValue())) != null) {
entities.put(clientEntityId, oldEntity);
} else {
entities.put(clientEntityId, new TrackedEntityImpl(playerType));
@@ -116,15 +131,6 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
this.clientEntityId = clientEntityId;
}
@Override
public boolean trackClientEntity() {
if (clientEntityId != -1) {
entities.put(clientEntityId, new TrackedEntityImpl(playerType));
return true;
}
return false;
}
@Override
public int currentWorldSectionHeight() {
return currentWorldSectionHeight;
@@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.protocol.ProtocolManager;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.ProtocolPathKey;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
@@ -38,10 +39,9 @@ import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
import com.viaversion.viaversion.protocol.packet.VersionedPacketTransformerImpl;
import com.viaversion.viaversion.protocols.base.BaseProtocol;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_16;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_7;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.base.InitialBaseProtocol;
import com.viaversion.viaversion.protocols.base.v1_7.ClientboundBaseProtocol1_7;
import com.viaversion.viaversion.protocols.base.v1_7.ServerboundBaseProtocol1_7;
import com.viaversion.viaversion.protocols.v1_10to1_11.Protocol1_10To1_11;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viaversion.protocols.v1_11to1_11_1.Protocol1_11To1_11_1;
@@ -74,6 +74,7 @@ import com.viaversion.viaversion.protocols.v1_19_4to1_20.Protocol1_19_4To1_20;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.Protocol1_19To1_19_1;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_3;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.Protocol1_20_3To1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.Protocol1_9_1To1_9_3;
@@ -109,14 +110,15 @@ import java.util.logging.Level;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ProtocolManagerImpl implements ProtocolManager {
private static final Protocol BASE_PROTOCOL = new BaseProtocol();
private static final Protocol BASE_PROTOCOL = new InitialBaseProtocol();
// Input Version -> Output Version & Protocol (Allows fast lookup)
private final Object2ObjectMap<ProtocolVersion, Object2ObjectMap<ProtocolVersion, Protocol>> registryMap = new Object2ObjectOpenHashMap<>(32);
private final Map<Class<? extends Protocol>, Protocol<?, ?, ?, ?>> protocols = new HashMap<>(64);
private final Map<ProtocolPathKey, List<ProtocolPathEntry>> pathCache = new ConcurrentHashMap<>();
private final Set<ProtocolVersion> supportedVersions = new HashSet<>();
private final List<Pair<Range<ProtocolVersion>, Protocol>> baseProtocols = Lists.newCopyOnWriteArrayList();
private final List<Pair<Range<ProtocolVersion>, Protocol>> serverboundBaseProtocols = Lists.newCopyOnWriteArrayList();
private final List<Pair<Range<ProtocolVersion>, Protocol>> clientboundBaseProtocols = Lists.newCopyOnWriteArrayList();
private final ReadWriteLock mappingLoaderLock = new ReentrantReadWriteLock();
private Map<Class<? extends Protocol>, CompletableFuture<Void>> mappingLoaderFutures = new HashMap<>();
@@ -137,8 +139,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
// Base Protocol
BASE_PROTOCOL.initialize();
BASE_PROTOCOL.register(Via.getManager().getProviders());
registerBaseProtocol(new BaseProtocol1_7(), Range.closedOpen(ProtocolVersion.v1_7_2, ProtocolVersion.v1_16));
registerBaseProtocol(new BaseProtocol1_16(), Range.atLeast(ProtocolVersion.v1_16));
registerBaseProtocol(Direction.CLIENTBOUND, new ClientboundBaseProtocol1_7(), Range.atLeast(ProtocolVersion.v1_7_2));
registerBaseProtocol(Direction.SERVERBOUND, new ServerboundBaseProtocol1_7(), Range.atLeast(ProtocolVersion.v1_7_2));
registerProtocol(new Protocol1_8To1_9(), ProtocolVersion.v1_9, ProtocolVersion.v1_8);
registerProtocol(new Protocol1_9To1_9_1(), Arrays.asList(ProtocolVersion.v1_9_1, ProtocolVersion.v1_9_2), ProtocolVersion.v1_9);
@@ -234,7 +236,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public void registerBaseProtocol(Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols) {
public void registerBaseProtocol(Direction direction, Protocol baseProtocol, Range<ProtocolVersion> supportedProtocols) {
Preconditions.checkArgument(baseProtocol.isBaseProtocol(), "Protocol is not a base protocol");
final ProtocolVersion lower = supportedProtocols.hasLowerBound() ? supportedProtocols.lowerEndpoint() : null;
final ProtocolVersion upper = supportedProtocols.hasUpperBound() ? supportedProtocols.upperEndpoint() : null;
@@ -243,7 +245,11 @@ public class ProtocolManagerImpl implements ProtocolManager {
baseProtocol.initialize();
baseProtocols.add(new Pair<>(supportedProtocols, baseProtocol));
if (direction == Direction.SERVERBOUND) {
serverboundBaseProtocols.add(new Pair<>(supportedProtocols, baseProtocol));
} else {
clientboundBaseProtocols.add(new Pair<>(supportedProtocols, baseProtocol));
}
baseProtocol.register(Via.getManager().getProviders());
if (Via.getManager().isInitialized()) {
refreshVersions();
@@ -273,12 +279,14 @@ public class ProtocolManagerImpl implements ProtocolManager {
ProtocolPathKey protocolKey = new ProtocolPathKeyImpl(clientVersion, serverVersion);
List<ProtocolPathEntry> protocolList = pathCache.get(protocolKey);
if (protocolList != null) {
return protocolList;
return protocolList.isEmpty() ? null : protocolList;
}
// Calculate path
Object2ObjectSortedMap<ProtocolVersion, Protocol> outputPath = getProtocolPath(new Object2ObjectLinkedOpenHashMap<>(), clientVersion, serverVersion);
if (outputPath == null) {
// Also cache that there is no path
pathCache.put(protocolKey, List.of());
return null;
}
@@ -365,13 +373,23 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public @Nullable Protocol getBaseProtocol(ProtocolVersion serverVersion) {
for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : Lists.reverse(baseProtocols)) {
if (rangeProtocol.key().contains(serverVersion)) {
return rangeProtocol.value();
public List<Protocol> getBaseProtocols(@Nullable ProtocolVersion clientVersion, @Nullable ProtocolVersion serverVersion) {
final List<Protocol> list = new ArrayList<>();
if (clientVersion != null) {
for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : serverboundBaseProtocols) {
if (rangeProtocol.key().contains(clientVersion)) {
list.add(rangeProtocol.value());
}
}
}
return null;
if (serverVersion != null) {
for (Pair<Range<ProtocolVersion>, Protocol> rangeProtocol : clientboundBaseProtocols) {
if (rangeProtocol.key().contains(serverVersion)) {
list.add(rangeProtocol.value());
}
}
}
return list;
}
@Override
@@ -518,7 +536,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
Preconditions.checkArgument(!mappingsLoaded);
// If this log message is missing, something is wrong
Via.getPlatform().getLogger().info("Finished mapping loading, shutting down loader executor!");
Via.getPlatform().getLogger().info("Finished mapping loading, shutting down loader executor.");
mappingsLoaded = true;
mappingLoaderExecutor.shutdown();
mappingLoaderExecutor = null;
@@ -24,8 +24,10 @@ import java.util.Comparator;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Special protocol version that compares to another version. This can be used for e.g. April Fool versions which are depending
* on vanilla game versions.
* Intended API class for protocol versions with the version type {@link VersionType#SPECIAL}.
* <p>
* Compares equal to the given origin version and allows base protocol determination via {@link #getBaseProtocolVersion()}
* which can be null for special cases where there is no base protocol.
*/
public class RedirectProtocolVersion extends ProtocolVersion {
@@ -55,4 +57,11 @@ public class RedirectProtocolVersion extends ProtocolVersion {
public ProtocolVersion getOrigin() {
return origin;
}
/**
* @return the protocol version used to determine the base protocol, null in case there is no base protocol.
*/
public @Nullable ProtocolVersion getBaseProtocolVersion() {
return origin;
}
}
@@ -123,7 +123,7 @@ public class PacketWrapperImpl implements PacketWrapper {
continue;
}
if (currentIndex == index) {
packetValue.setValue(attemptTransform(type, value));
packetValue.setValue(value);
return;
}
currentIndex++;
@@ -133,23 +133,26 @@ public class PacketWrapperImpl implements PacketWrapper {
@Override
public <T> T read(Type<T> type) {
if (readableObjects.isEmpty()) {
Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer.");
// We could in the future log input read values, but honestly for things like bulk maps, mem waste D:
try {
return type.read(inputBuffer);
} catch (Exception e) {
throw createInformativeException(e, type, packetValues.size() + 1);
}
}
return readableObjects.isEmpty() ? readFromBuffer(type) : pollReadableObject(type).value;
}
PacketValue readValue = readableObjects.poll();
private <T> T readFromBuffer(Type<T> type) {
Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer.");
try {
return type.read(inputBuffer);
} catch (Exception e) {
throw createInformativeException(e, type, packetValues.size() + 1);
}
}
private <T> PacketValue<T> pollReadableObject(Type<T> type) {
PacketValue<?> readValue = readableObjects.poll();
Type<?> readType = readValue.type();
if (readType == type
|| (type.getBaseClass() == readType.getBaseClass()
&& type.getOutputClass() == readType.getOutputClass())) {
//noinspection unchecked
return (T) readValue.value();
return (PacketValue<T>) readValue;
} else {
throw createInformativeException(new IOException("Unable to read type " + type.getTypeName() + ", found " + readValue.type().getTypeName()), type, readableObjects.size());
}
@@ -157,7 +160,7 @@ public class PacketWrapperImpl implements PacketWrapper {
@Override
public <T> void write(Type<T> type, T value) {
packetValues.add(new PacketValue<>(type, attemptTransform(type, value)));
packetValues.add(new PacketValue<>(type, value));
}
/**
@@ -167,7 +170,7 @@ public class PacketWrapperImpl implements PacketWrapper {
* @param value value
* @return value if already matching, else the converted value or possibly unmatched value
*/
private <T> @Nullable T attemptTransform(Type<T> expectedType, @Nullable T value) {
private <T> @Nullable T attemptTransform(Type<T> expectedType, @Nullable Object value) {
if (value != null && !expectedType.getOutputClass().isAssignableFrom(value.getClass())) {
// Attempt conversion
if (expectedType instanceof TypeConverter<?>) {
@@ -177,14 +180,33 @@ public class PacketWrapperImpl implements PacketWrapper {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + expectedType.getOutputClass());
}
return value;
//noinspection unchecked
return (T) value;
}
@Override
public <T> T passthrough(Type<T> type) throws InformativeException {
T value = read(type);
write(type, value);
return value;
if (readableObjects.isEmpty()) {
T value = readFromBuffer(type);
packetValues.add(new PacketValue<>(type, value));
return value;
} else {
PacketValue<T> value = pollReadableObject(type);
packetValues.add(value);
return value.value;
}
}
@Override
public <T> T passthroughAndMap(Type<?> type, Type<T> mappedType) throws InformativeException {
if (type == mappedType) {
return passthrough(mappedType);
}
final Object value = read(type);
final T mappedValue = attemptTransform(mappedType, value);
write(mappedType, mappedValue);
return mappedValue;
}
@Override
@@ -318,7 +340,7 @@ public class PacketWrapperImpl implements PacketWrapper {
}
return user().sendRawPacketFuture(output);
}
return user().getChannel().newFailedFuture(new RuntimeException("Tried to send cancelled packet"));
return cancelledFuture();
}
@Override
@@ -326,6 +348,21 @@ public class PacketWrapperImpl implements PacketWrapper {
sendRaw(true);
}
@Override
public ChannelFuture sendFutureRaw() throws InformativeException {
if (isCancelled()) {
return cancelledFuture();
}
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
try {
writeToBuffer(output);
return user().sendRawPacketFuture(output.retain());
} finally {
output.release();
}
}
@Override
public void scheduleSendRaw() throws InformativeException {
sendRaw(false);
@@ -349,6 +386,10 @@ public class PacketWrapperImpl implements PacketWrapper {
}
}
private ChannelFuture cancelledFuture() {
return user().getChannel().newFailedFuture(new RuntimeException("Tried to send cancelled packet"));
}
@Override
public PacketWrapperImpl create(int packetId) {
return new PacketWrapperImpl(packetId, null, user());
@@ -1,30 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.base;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import java.util.UUID;
public class BaseProtocol1_16 extends BaseProtocol1_7 {
@Override
protected UUID passthroughLoginUUID(final PacketWrapper wrapper) {
return wrapper.passthrough(Types.UUID);
}
}
@@ -35,6 +35,7 @@ import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.protocol.RedirectProtocolVersion;
import com.viaversion.viaversion.protocol.version.BaseVersionProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
@@ -42,19 +43,24 @@ import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import java.util.ArrayList;
import java.util.List;
public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
/**
* Initial base protocol which is kept always in the pipeline.
* <p>
* State tracking for configuration state is done via {@link AbstractProtocol#registerConfigurationChangeHandlers()}
*/
public class InitialBaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
private static final int STATUS_INTENT = 1;
private static final int LOGIN_INTENT = 2;
private static final int TRANSFER_INTENT = 3;
public BaseProtocol() {
public InitialBaseProtocol() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
}
@Override
protected void registerPackets() {
// Handshake Packet
// Setup protocol pipeline + track initial state
registerServerbound(ServerboundHandshakePackets.CLIENT_INTENTION, wrapper -> {
int protocolVersion = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.STRING); // Server Address
@@ -89,16 +95,22 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
ProtocolManager protocolManager = Via.getManager().getProtocolManager();
List<ProtocolPathEntry> protocolPath = protocolManager.getProtocolPath(info.protocolVersion(), serverProtocol);
// Add Base Protocol
ProtocolPipeline pipeline = info.getPipeline();
// Special versions might compare equal to normal versions and would break this getter
// Save manually added protocols for later
List<Protocol> alreadyAdded = new ArrayList<>(pipeline.pipes());
// Special versions might compare equal to normal versions and would the normal lookup,
// platforms can use the RedirectProtocolVersion API or need to manually handle their base protocols.
ProtocolVersion clientboundBaseProtocolVersion = null;
if (serverProtocol.getVersionType() != VersionType.SPECIAL) {
final Protocol baseProtocol = protocolManager.getBaseProtocol(serverProtocol);
// Platforms might add their base protocol manually (e.g. SPECIAL versions)
if (baseProtocol != null) {
pipeline.add(baseProtocol);
}
clientboundBaseProtocolVersion = serverProtocol;
} else if (serverProtocol instanceof RedirectProtocolVersion version) {
clientboundBaseProtocolVersion = version.getBaseProtocolVersion();
}
// Add base protocols
for (final Protocol protocol : protocolManager.getBaseProtocols(info.protocolVersion(), clientboundBaseProtocolVersion)) {
pipeline.add(protocol);
}
// Add other protocols
@@ -118,11 +130,22 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
wrapper.set(Types.VAR_INT, 0, serverProtocol.getOriginalVersion());
}
// Send client intention into the pipeline in case protocols down the line need to transform it
try {
final List<Protocol> protocols = new ArrayList<>(pipeline.pipes());
protocols.removeAll(alreadyAdded); // Skip all manually added protocols to prevent double handling
wrapper.resetReader();
wrapper.apply(Direction.SERVERBOUND, State.HANDSHAKE, protocols);
} catch (CancelException e) {
wrapper.cancel();
}
if (Via.getManager().isDebug()) {
Via.getPlatform().getLogger().info("User connected with protocol: " + info.protocolVersion() + " and serverProtocol: " + info.serverProtocolVersion());
Via.getPlatform().getLogger().info("Protocol pipeline: " + pipeline.pipes());
}
// Set initial state
if (state == STATUS_INTENT) {
info.setState(State.STATUS);
} else if (state == LOGIN_INTENT) {
@@ -162,4 +185,4 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
protected PacketTypesProvider<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> createPacketTypesProvider() {
return BasePacketTypesProvider.INSTANCE;
}
}
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.base;
package com.viaversion.viaversion.protocols.base.v1_7;
import com.google.common.base.Joiner;
import com.google.gson.JsonElement;
@@ -26,7 +26,6 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
@@ -35,25 +34,25 @@ import com.viaversion.viaversion.api.protocol.version.VersionProvider;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocol.ProtocolManagerImpl;
import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ClientboundStatusPackets;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.GsonUtil;
import io.netty.channel.ChannelFuture;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public class ClientboundBaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public BaseProtocol1_7() {
public ClientboundBaseProtocol1_7() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
}
@Override
protected void registerPackets() {
// Handle server pinging sent by the client
registerClientbound(ClientboundStatusPackets.STATUS_RESPONSE, new PacketHandlers() {
@Override
public void register() {
@@ -128,60 +127,27 @@ public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, Bas
}
});
// Login Success Packet
// Track player name/uuid and setup connection + track state
registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
ProtocolInfo info = wrapper.user().getProtocolInfo();
if (info.protocolVersion().olderThan(ProtocolVersion.v1_20_2)) { // On 1.20.2+, wait for the login ack
info.setState(State.PLAY);
}
UUID uuid = passthroughLoginUUID(wrapper);
info.setUuid(uuid);
String username = wrapper.passthrough(Types.STRING);
info.setUsername(username);
// Add to ported clients
Via.getManager().getConnectionManager().onLoginSuccess(wrapper.user());
if (!info.getPipeline().hasNonBaseProtocols()) { // Only base protocol
wrapper.user().setActive(false);
}
if (Via.getManager().isDebug()) {
// Print out the route to console
Via.getPlatform().getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
username,
info.protocolVersion().getName(),
Joiner.on(", ").join(info.getPipeline().pipes(), ", ")
});
}
});
// Login Start Packet
registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> {
final UserConnection user = wrapper.user();
final ProtocolVersion protocol = user.getProtocolInfo().protocolVersion();
if (Via.getConfig().blockedProtocolVersions().contains(protocol)) {
if (!user.getChannel().isOpen() || !user.shouldApplyBlockProtocol()) {
return;
}
wrapper.cancel(); // cancel current
final String disconnectMessage = ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg());
final PacketWrapper disconnectPacket = PacketWrapper.create(ClientboundLoginPackets.LOGIN_DISCONNECT, user);
disconnectPacket.write(Types.COMPONENT, ComponentUtil.plainToJson(disconnectMessage));
// Send and close
final ChannelFuture future = disconnectPacket.sendFuture(null);
future.addListener(f -> user.getChannel().close());
}
});
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setState(State.CONFIGURATION);
if (info.serverProtocolVersion().olderThan(ProtocolVersion.v1_16)) {
String uuidString = wrapper.passthrough(Types.STRING);
if (uuidString.length() == 32) { // Trimmed UUIDs are 32 characters
// Trimmed
uuidString = addDashes(uuidString);
}
info.setUuid(UUID.fromString(uuidString));
} else {
final UUID uuid = wrapper.passthrough(Types.UUID);
info.setUuid(uuid);
}
final String username = wrapper.passthrough(Types.STRING);
info.setUsername(username);
// Setup connection
onLoginSuccess(wrapper.user());
});
}
@@ -199,13 +165,28 @@ public class BaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, Bas
return idBuff.toString();
}
protected UUID passthroughLoginUUID(PacketWrapper wrapper) {
String uuidString = wrapper.passthrough(Types.STRING);
if (uuidString.length() == 32) { // Trimmed UUIDs are 32 characters
// Trimmed
uuidString = addDashes(uuidString);
public static void onLoginSuccess(final UserConnection connection) {
final ProtocolInfo info = connection.getProtocolInfo();
if (info.protocolVersion().olderThan(ProtocolVersion.v1_20_2)) { // On 1.20.2+, wait for the login ack
info.setState(State.PLAY);
}
// Add to ported clients
Via.getManager().getConnectionManager().onLoginSuccess(connection);
if (!info.getPipeline().hasNonBaseProtocols()) { // Only base protocol
connection.setActive(false);
}
if (Via.getManager().isDebug()) {
// Print out the route to console
Via.getPlatform().getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
info.getUsername(),
info.protocolVersion().getName(),
Joiner.on(", ").join(info.getPipeline().pipes(), ", ")
});
}
return UUID.fromString(uuidString);
}
@Override
@@ -0,0 +1,91 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.base.v1_7;
import com.google.gson.JsonObject;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import io.netty.channel.ChannelFuture;
public class ServerboundBaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
public ServerboundBaseProtocol1_7() {
super(BaseClientboundPacket.class, BaseClientboundPacket.class, BaseServerboundPacket.class, BaseServerboundPacket.class);
}
@Override
protected void registerPackets() {
// State tracking
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setState(State.CONFIGURATION);
});
// Handle blocked version disconnect
registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> {
final UserConnection user = wrapper.user();
final ProtocolVersion protocol = user.getProtocolInfo().protocolVersion();
if (Via.getConfig().blockedProtocolVersions().contains(protocol)) {
if (!user.getChannel().isOpen() || !user.shouldApplyBlockProtocol()) {
return;
}
wrapper.cancel(); // cancel current
final String disconnectMessage = ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg());
final PacketWrapper disconnectPacket = PacketWrapper.create(ClientboundLoginPackets.LOGIN_DISCONNECT, user);
final JsonObject object = ComponentUtil.plainToJson(disconnectMessage);
if (protocol.olderThanOrEqualTo(ProtocolVersion.v1_8)) {
disconnectPacket.write(Types.STRING, object.toString());
} else {
disconnectPacket.write(Types.COMPONENT, object);
}
// Send and close
final ChannelFuture future = disconnectPacket.sendFutureRaw();
future.addListener(f -> user.getChannel().close());
}
});
}
@Override
public boolean isBaseProtocol() {
return true;
}
@Override
protected PacketTypesProvider<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> createPacketTypesProvider() {
return BasePacketTypesProvider.INSTANCE;
}
}
@@ -15,26 +15,31 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.template.protocols.rewriter;
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.RecipeRewriter1_20_3;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import com.viaversion.viaversion.template.protocols.Protocol1_99To_98;
// To replace if needed:
// ChunkType1_20_2
// RecipeRewriter1_20_3
public final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_20_5, ServerboundPacket1_20_5, Protocol1_99To_98> {
// Types1_21, Types1_OLD
final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_21, ServerboundPacket1_20_5, Protocol1_99To_98> {
public BlockItemPacketRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol, /*TypesOLD.ITEM, TypesOLD.ITEM_ARRAY, */Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY);
super(protocol, Types1_21.ITEM, Types1_21.ITEM_ARRAY);
/*super(protocol,
Types1_OLD.ITEM, Types1_OLD.ITEM_ARRAY, Types1_21.ITEM, Types1_21.ITEM_ARRAY,
Types1_OLD.ITEM_COST, Types1_OLD.OPTIONAL_ITEM_COST, Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST,
Types1_OLD.PARTICLE, Types1_21.PARTICLE
);*/
}
@Override
@@ -42,31 +47,31 @@ public final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<Cl
// Register block and block state id changes
// Other places using block state id mappings: Spawn particle, entity data, entity spawn (falling blocks)
// Tags and statistics use block (!) ids
final BlockRewriter<ClientboundPacket1_20_5> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_20_5.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_20_5.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_20_5.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_20_5.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_20_5.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_20_5.BLOCK_ENTITY_DATA);
final BlockRewriter<ClientboundPacket1_21> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21.BLOCK_ENTITY_DATA);
// Registers item id changes
// Other places using item ids are: Entity data, tags, statistics, effect
// registerOpenWindow(ClientboundPackets1_20_5.OPEN_WINDOW); - If a new container type was added
registerCooldown(ClientboundPackets1_20_5.COOLDOWN);
registerSetContent1_17_1(ClientboundPackets1_20_5.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_20_5.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_20_5.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_20_5.SET_EQUIPMENT);
// registerOpenWindow(ClientboundPackets1_21.OPEN_WINDOW); - If a new container type was added
registerCooldown(ClientboundPackets1_21.COOLDOWN);
registerSetContent1_17_1(ClientboundPackets1_21.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_21.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21.SET_EQUIPMENT);
registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerMerchantOffers1_20_5(ClientboundPackets1_20_5.MERCHANT_OFFERS, Types1_20_5.ITEM_COST, Types1_20_5.ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST);
registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
registerLevelParticles1_20_5(ClientboundPackets1_20_5.LEVEL_PARTICLES, Types1_20_5.PARTICLE, Types1_20_5.PARTICLE);
registerExplosion(ClientboundPackets1_20_5.EXPLODE, Types1_20_5.PARTICLE, Types1_20_5.PARTICLE); // Rewrites the included sound and particles
registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES);
registerExplosion(ClientboundPackets1_21.EXPLODE); // Rewrites the included sound and particles
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_20_5.UPDATE_RECIPES);
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_21.UPDATE_RECIPES);
// OR do this if serialization of recipes changed and override the relevant method
// Add new serializers to RecipeRewriter, or extend the last one for changes
// new RecipeRewriter1_20_3<ClientboundPackets1_20_5>(this) {}.register1_20_5(ClientboundPackets1_20_5.DECLARE_RECIPES);
// new RecipeRewriter1_20_3<ClientboundPacket1_21>(this) {}.register1_20_5(ClientboundPackets1_21.DECLARE_RECIPES);
}
}
}
@@ -15,25 +15,24 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.template.protocols.rewriter;
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.template.protocols.Protocol1_99To_98;
import com.viaversion.viaversion.util.Key;
// Replace if needed
// Types1_OLD
// Types1_20_5
public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_20_5, Protocol1_99To_98> {
// Types1_21
final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_21, Protocol1_99To_98> {
public EntityPacketRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol);
@@ -42,17 +41,17 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
@Override
public void registerPackets() {
// Tracks entities, applies entity data rewrites registered below, untracks entities
registerTrackerWithData1_19(ClientboundPackets1_20_5.ADD_ENTITY, EntityTypes1_20_5.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_20_5.SET_ENTITY_DATA, /*Types1_OLD_ENTITY_DATA_LIST, */Types1_20_5.ENTITY_DATA_LIST); // Specify old and new entity data list if changed
registerRemoveEntities(ClientboundPackets1_20_5.REMOVE_ENTITIES);
registerTrackerWithData1_19(ClientboundPackets1_21.ADD_ENTITY, EntityTypes1_20_5.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21.SET_ENTITY_DATA, /*Types1_OLD_ENTITY_DATA_LIST, */Types1_21.ENTITY_DATA_LIST); // Specify old and new entity data list if changed
registerRemoveEntities(ClientboundPackets1_21.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundConfigurationPackets1_20_5.REGISTRY_DATA, wrapper -> {
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, wrapper -> {
final String registryKey = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING));
final RegistryEntry[] entries = wrapper.passthrough(Types.REGISTRY_ENTRY_ARRAY);
handleRegistryData1_20_5(wrapper.user(), registryKey, entries); // Caches dimensions to access data like height later and tracks the amount of biomes sent for chunk data
});
protocol.registerClientbound(ClientboundPackets1_20_5.LOGIN, new PacketHandlers() {
protocol.registerClientbound(ClientboundPackets1_21.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Entity id
@@ -71,7 +70,7 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
}
});
protocol.registerClientbound(ClientboundPackets1_20_5.RESPAWN, wrapper -> {
protocol.registerClientbound(ClientboundPackets1_21.RESPAWN, wrapper -> {
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
final String world = wrapper.passthrough(Types.STRING);
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking
@@ -82,24 +81,23 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
protected void registerRewrites() {
/* Uncomment if entity data classes changed
filter().mapDataType(typeId -> {
final int id = typeId;
int id = typeId;
if (id >= SomeAddedIndex) {
id++;
}
return Types1_20_5.ENTITY_DATA_TYPES.byId(id);
return Types1_21.ENTITY_DATA_TYPES.byId(id);
});*/
// Registers registry type id changes
registerEntityDataTypeHandler(
Types1_20_5.ENTITY_DATA_TYPES.itemType,
Types1_20_5.ENTITY_DATA_TYPES.blockStateType,
Types1_20_5.ENTITY_DATA_TYPES.optionalBlockStateType,
Types1_20_5.ENTITY_DATA_TYPES.particleType,
Types1_20_5.ENTITY_DATA_TYPES.particlesType,
Types1_20_5.ENTITY_DATA_TYPES.componentType,
Types1_20_5.ENTITY_DATA_TYPES.optionalComponentType
Types1_21.ENTITY_DATA_TYPES.itemType,
Types1_21.ENTITY_DATA_TYPES.blockStateType,
Types1_21.ENTITY_DATA_TYPES.optionalBlockStateType,
Types1_21.ENTITY_DATA_TYPES.particleType,
Types1_21.ENTITY_DATA_TYPES.particlesType,
Types1_21.ENTITY_DATA_TYPES.componentType,
Types1_21.ENTITY_DATA_TYPES.optionalComponentType
);
// Minecarts are special
registerBlockStateHandler(EntityTypes1_20_5.ABSTRACT_MINECART, 11);
}
@@ -113,4 +111,4 @@ public final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPa
public EntityType typeFromId(final int type) {
return EntityTypes1_20_5.getTypeFromId(type);
}
}
}
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.template.protocols;
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
@@ -25,65 +25,63 @@ import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.template.protocols.rewriter.BlockItemPacketRewriter1_99;
import com.viaversion.viaversion.template.protocols.rewriter.EntityPacketRewriter1_99;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
// Placeholders to replace (in the entire package):
// Protocol1_99To_98, EntityPacketRewriter1_99, BlockItemPacketRewriter1_99
// ClientboundPacket1_20_5
// Protocol1_99To_98, EntityPacketRewriter1_99, BlockItemPacketRewriter1_99 - move the latter two to a rewriter package
// ClientboundPacket1_21
// ServerboundPacket1_20_5
// EntityTypes1_20_5 (MAPPED type)
// 1.99, 1.98
public final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_20_5, ClientboundPacket1_20_5, ServerboundPacket1_20_5, ServerboundPacket1_20_5> {
final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, ClientboundPacket1_21, ServerboundPacket1_20_5, ServerboundPacket1_20_5> {
public static final MappingData MAPPINGS = new MappingDataBase("1.98", "1.99");
private final EntityPacketRewriter1_99 entityRewriter = new EntityPacketRewriter1_99(this);
private final BlockItemPacketRewriter1_99 itemRewriter = new BlockItemPacketRewriter1_99(this);
private final TagRewriter<ClientboundPacket1_20_5> tagRewriter = new TagRewriter<>(this);
private final TagRewriter<ClientboundPacket1_21> tagRewriter = new TagRewriter<>(this);
public Protocol1_99To_98() {
// Passing the class types into the super constructor is needed for automatic packet type id remapping, but can otherwise be omitted
super(ClientboundPacket1_20_5.class, ClientboundPacket1_20_5.class, ServerboundPacket1_20_5.class, ServerboundPacket1_20_5.class);
super(ClientboundPacket1_21.class, ClientboundPacket1_21.class, ServerboundPacket1_20_5.class, ServerboundPacket1_20_5.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_20_5.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_20_5.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundPackets1_21.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
final SoundRewriter<ClientboundPacket1_20_5> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_20_5.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_20_5.SOUND_ENTITY);
final SoundRewriter<ClientboundPacket1_21> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND_ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_20_5.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_20_5.UPDATE_ATTRIBUTES);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21.UPDATE_ATTRIBUTES);
// Uncomment if an existing type changed serialization format. Mappings for argument type keys can also be defined in mapping files
/*final CommandRewriter1_19_4<ClientboundPackets1_20_5> commandRewriter = new CommandRewriter1_19_4<ClientboundPackets1_20_5>(this) {
/*new CommandRewriter1_19_4<>(this) {
@Override
public void handleArgument(final PacketWrapper wrapper, final String argumentType) throws Exception {
public void handleArgument(final PacketWrapper wrapper, final String argumentType) {
if (argumentType.equals("minecraft:abc")) {
// New argument
wrapper.write(Type.INT, 0);
wrapper.write(Types.INT, 0);
} else {
super.handleArgument(wrapper, argumentType);
}
}
}.registerDeclareCommands1_19(ClientboundPackets1_20_5.DECLARE_COMMANDS);*/
}.registerDeclareCommands1_19(ClientboundPackets1_21.COMMANDS);*/
}
@Override
@@ -92,7 +90,7 @@ public final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1
// EntityTypes1_20_5.initialize(this);
// Uncomment if a new particle was added = ids shifted; requires a new Types_ class copied from the last
/*Types1_20_5.PARTICLE.filler(this)
/*Types1_21.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST)
@@ -130,17 +128,17 @@ public final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1
}
@Override
public TagRewriter<ClientboundPacket1_20_5> getTagRewriter() {
public TagRewriter<ClientboundPacket1_21> getTagRewriter() {
return tagRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_20_5, ClientboundPacket1_20_5, ServerboundPacket1_20_5, ServerboundPacket1_20_5> createPacketTypesProvider() {
protected PacketTypesProvider<ClientboundPacket1_21, ClientboundPacket1_21, ServerboundPacket1_20_5, ServerboundPacket1_20_5> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_20_5.class, ClientboundConfigurationPackets1_20_5.class),
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class)
);
}
}
}
@@ -99,7 +99,7 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
});
registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_11.class);
Chunk chunk = wrapper.passthrough(ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()));
@@ -120,31 +120,6 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
}
});
registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
}
});
registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
}
});
this.registerClientbound(ClientboundPackets1_9_3.LEVEL_EVENT, new PacketHandlers() {
@Override
public void register() {
@@ -238,11 +213,8 @@ public class Protocol1_10To1_11 extends AbstractProtocol<ClientboundPackets1_9_3
@Override
public void init(UserConnection userConnection) {
// Entity tracker
userConnection.addEntityTracker(this.getClass(), new EntityTracker1_11(userConnection));
if (!userConnection.has(ClientWorld.class))
userConnection.put(new ClientWorld());
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -24,7 +24,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class PotionColorMappings1_11 {
//<oldData> to <newData, isInstant> mapping
private static final Int2ObjectMap<Pair<Integer, Boolean>> POTIONS = new Int2ObjectOpenHashMap<>(37, 0.99F);
private static final Int2ObjectMap<Pair<Integer, Boolean>> POTIONS = new Int2ObjectOpenHashMap<>(37);
static {
addRewrite(0, 3694022, false);
@@ -20,6 +20,7 @@ package com.viaversion.viaversion.protocols.v1_10to1_11.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11.EntityType;
@@ -48,6 +49,34 @@ public class EntityPacketRewriter1_11 extends EntityRewriter<ClientboundPackets1
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_11.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_10To1_11.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.protocols.v1_10to1_11.rewriter;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Types;
@@ -55,6 +56,22 @@ public class ItemPacketRewriter1_11 extends ItemRewriter<ClientboundPackets1_9_3
item.setAmount(1);
}
EntityMappings1_11.toClientItem(item);
if (item == null || item.tag() == null) {
return item;
}
CompoundTag tag = item.tag();
// 1.10 will display item glint if the list tag is present, 1.11+ only if at least one element is present
ListTag enchTag = tag.getListTag("ench");
if (enchTag != null && enchTag.isEmpty()) {
tag.putBoolean(nbtTagName("clearEnch"), true);
CompoundTag dummyTag = new CompoundTag();
dummyTag.putShort("id", Short.MAX_VALUE);
enchTag.add(dummyTag);
}
return item;
}
@@ -63,10 +80,16 @@ public class ItemPacketRewriter1_11 extends ItemRewriter<ClientboundPackets1_9_3
if (item == null) {
return null;
}
if (item.tag() != null && item.tag().contains(nbtTagName())) {
item.setAmount(item.tag().<ByteTag>removeUnchecked(nbtTagName()).asByte());
if (item.tag().isEmpty()) {
item.setTag(null);
CompoundTag tag = item.tag();
if (tag != null) {
if (tag.contains(nbtTagName())) {
item.setAmount(tag.<ByteTag>removeUnchecked(nbtTagName()).asByte());
if (tag.isEmpty()) {
item.setTag(null);
}
}
if (tag.remove(nbtTagName("clearEnch")) != null) {
tag.put("ench", new ListTag());
}
}
EntityMappings1_11.toServerItem(item);
@@ -78,4 +101,4 @@ public class ItemPacketRewriter1_11 extends ItemRewriter<ClientboundPackets1_9_3
}
return item;
}
}
}
@@ -72,7 +72,7 @@ public class Protocol1_11_1To1_12 extends AbstractProtocol<ClientboundPackets1_9
});
registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11_1To1_12.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());
Chunk chunk = wrapper.passthrough(type);
@@ -101,38 +101,6 @@ public class Protocol1_11_1To1_12 extends AbstractProtocol<ClientboundPackets1_9
}
});
registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
map(Types.UNSIGNED_BYTE);
map(Types.INT);
handler(wrapper -> {
UserConnection user = wrapper.user();
ClientWorld clientChunks = user.get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
// Reset recipes
if (user.getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_13)) {
wrapper.create(ClientboundPackets1_13.UPDATE_RECIPES, packetWrapper -> packetWrapper.write(Types.VAR_INT, 0))
.scheduleSend(Protocol1_12_2To1_13.class);
}
});
}
});
registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
}
});
new SoundRewriter<>(this, this::getNewSoundId).registerSound(ClientboundPackets1_9_3.SOUND);
@@ -205,9 +173,7 @@ public class Protocol1_11_1To1_12 extends AbstractProtocol<ClientboundPackets1_9
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTrackerBase(userConnection, EntityTypes1_12.EntityType.PLAYER));
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -23,7 +23,7 @@ import java.util.Set;
public class AchievementTranslations1_12 {
private static final Object2ObjectOpenHashMap<String, String> ACHIEVEMENTS = new Object2ObjectOpenHashMap<>(150, 0.99f);
private static final Object2ObjectOpenHashMap<String, String> ACHIEVEMENTS = new Object2ObjectOpenHashMap<>(150);
private static final Set<String> SPECIAL_ACHIEVEMENTS = new HashSet<>(10);
static {
@@ -196,4 +196,4 @@ public class AchievementTranslations1_12 {
return SPECIAL_ACHIEVEMENTS.contains(key);
}
}
}
@@ -17,13 +17,18 @@
*/
package com.viaversion.viaversion.protocols.v1_11_1to1_12.rewriter;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_12;
import com.viaversion.viaversion.api.type.types.version.Types1_9;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.Protocol1_11_1To1_12;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.rewriter.EntityRewriter;
@@ -35,6 +40,40 @@ public class EntityPacketRewriter1_12 extends EntityRewriter<ClientboundPackets1
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_9_3.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
map(Types.UNSIGNED_BYTE);
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11_1To1_12.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
// Reset recipes
if (wrapper.user().getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_13)) {
wrapper.create(ClientboundPackets1_13.UPDATE_RECIPES, packetWrapper -> packetWrapper.write(Types.VAR_INT, 0))
.scheduleSend(Protocol1_12_2To1_13.class);
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT);
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_11_1To1_12.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_9_3.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
@@ -62,7 +101,7 @@ public class EntityPacketRewriter1_12 extends EntityRewriter<ClientboundPackets1
map(Types.SHORT); // 9 - Velocity X
map(Types.SHORT); // 10 - Velocity Y
map(Types.SHORT); // 11 - Velocity Z
map(Types1_12.ENTITY_DATA_LIST); // 12 - Entity data
map(Types1_9.ENTITY_DATA_LIST, Types1_12.ENTITY_DATA_LIST); // 12 - Entity data
// Track mob and rewrite entity data
handler(trackerAndRewriterHandler(Types1_12.ENTITY_DATA_LIST));
@@ -70,7 +109,7 @@ public class EntityPacketRewriter1_12 extends EntityRewriter<ClientboundPackets1
});
registerRemoveEntities(ClientboundPackets1_9_3.REMOVE_ENTITIES);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types1_12.ENTITY_DATA_LIST);
registerSetEntityData(ClientboundPackets1_9_3.SET_ENTITY_DATA, Types1_9.ENTITY_DATA_LIST, Types1_12.ENTITY_DATA_LIST);
}
@Override
@@ -34,6 +34,7 @@ import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
@@ -145,7 +146,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
}).scheduleSend(Protocol1_12_2To1_13.class);
// Send tags packet
w.create(ClientboundPackets1_13.UPDATE_TAGS, wrapper -> {
final PacketWrapper tagsPacket = w.create(ClientboundPackets1_13.UPDATE_TAGS, wrapper -> {
wrapper.write(Types.VAR_INT, MAPPINGS.getBlockTags().size()); // block tags
for (Map.Entry<String, int[]> tag : MAPPINGS.getBlockTags().entrySet()) {
wrapper.write(Types.STRING, tag.getKey());
@@ -164,7 +165,13 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
// Needs copy as other protocols may modify it
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, tag.getValue().clone());
}
}).scheduleSend(Protocol1_12_2To1_13.class);
});
if (w.user().getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_2)) {
// Make sure it's included in the configuration packets
tagsPacket.send(Protocol1_12_2To1_13.class);
} else {
tagsPacket.scheduleSend(Protocol1_12_2To1_13.class);
}
};
@Override
@@ -173,11 +180,11 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
WorldPacketRewriter1_13.register(this);
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_DISCONNECT.getId(), ClientboundLoginPackets.LOGIN_DISCONNECT.getId(), wrapper -> {
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_DISCONNECT, wrapper -> {
componentRewriter.processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT));
});
registerClientbound(State.STATUS, ClientboundStatusPackets.STATUS_RESPONSE.getId(), ClientboundStatusPackets.STATUS_RESPONSE.getId(), new PacketHandlers() {
registerClientbound(State.STATUS, ClientboundStatusPackets.STATUS_RESPONSE, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING);
@@ -401,23 +408,6 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
}
});
registerClientbound(ClientboundPackets1_12_1.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
if (Via.getConfig().isServersideBlockConnections()) {
ConnectionData.clearBlockStorage(wrapper.user());
}
});
handler(SEND_DECLARE_COMMANDS_AND_TAGS);
}
});
registerClientbound(ClientboundPackets1_12_1.SET_OBJECTIVE, new PacketHandlers() {
@Override
public void register() {
@@ -844,9 +834,9 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTrackerBase(userConnection, EntityTypes1_13.EntityType.PLAYER));
userConnection.addClientWorld(this.getClass(), new ClientWorld());
userConnection.put(new TabCompleteTracker());
if (!userConnection.has(ClientWorld.class))
userConnection.put(new ClientWorld());
userConnection.put(new BlockStorage());
if (Via.getConfig().isServersideBlockConnections()) {
if (Via.getManager().getProviders().get(BlockConnectionProvider.class) instanceof PacketBlockConnectionProvider) {
@@ -54,8 +54,8 @@ import java.util.Map.Entry;
public final class ConnectionData {
public static BlockConnectionProvider blockConnectionProvider;
static final Object2IntMap<String> KEY_TO_ID = new Object2IntOpenHashMap<>(8582, .99F);
static final IntSet OCCLUDING_STATES = new IntOpenHashSet(377, .99F);
static final Object2IntMap<String> KEY_TO_ID = new Object2IntOpenHashMap<>(8582);
static final IntSet OCCLUDING_STATES = new IntOpenHashSet(377);
static Int2ObjectMap<ConnectionHandler> connectionHandlerMap = new Int2ObjectOpenHashMap<>();
static Int2ObjectMap<BlockData> blockConnectionData = new Int2ObjectOpenHashMap<>();
private static final BlockChangeRecord1_8[] EMPTY_RECORDS = new BlockChangeRecord1_8[0];
@@ -173,7 +173,7 @@ public final class ConnectionData {
KEY_TO_ID.put(key, id);
}
connectionHandlerMap = new Int2ObjectOpenHashMap<>(3650, .99F);
connectionHandlerMap = new Int2ObjectOpenHashMap<>(3650);
if (!Via.getConfig().isReduceBlockStorageMemory()) {
blockConnectionData = new Int2ObjectOpenHashMap<>(2048);
@@ -21,7 +21,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
public class EntityIdMappings1_13 {
private static final Int2IntMap ENTITY_TYPES = new Int2IntOpenHashMap(83, .99F);
private static final Int2IntMap ENTITY_TYPES = new Int2IntOpenHashMap(83);
static {
ENTITY_TYPES.defaultReturnValue(-1);
@@ -121,4 +121,4 @@ public class EntityIdMappings1_13 {
public static Int2IntMap getEntityTypes() {
return ENTITY_TYPES;
}
}
}
@@ -28,6 +28,7 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_12;
import com.viaversion.viaversion.api.type.types.version.Types1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.ConnectionData;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.EntityIdMappings1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.data.ParticleIdMappings1_13;
import com.viaversion.viaversion.protocols.v1_12to1_12_1.packet.ClientboundPackets1_12_1;
@@ -132,7 +133,7 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
ClientWorld clientChunks = wrapper.user().getClientWorld(Protocol1_12_2To1_13.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
@@ -141,6 +142,24 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
}
});
protocol.registerClientbound(ClientboundPackets1_12_1.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_12_2To1_13.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
if (Via.getConfig().isServersideBlockConnections()) {
ConnectionData.clearBlockStorage(wrapper.user());
}
tracker(wrapper.user()).clearEntities();
}
});
handler(Protocol1_12_2To1_13.SEND_DECLARE_COMMANDS_AND_TAGS);
}
});
protocol.registerClientbound(ClientboundPackets1_12_1.UPDATE_MOB_EFFECT, new PacketHandlers() {
@Override
public void register() {
@@ -235,4 +254,4 @@ public class EntityPacketRewriter1_13 extends EntityRewriter<ClientboundPackets1
public EntityType objectTypeFromId(int type) {
return EntityTypes1_13.getTypeFromId(type, true);
}
}
}
@@ -304,23 +304,15 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
if (ench != null) {
ListTag<CompoundTag> enchantments = new ListTag<>(CompoundTag.class);
for (CompoundTag enchEntry : ench) {
NumberTag idTag = enchEntry.getNumberTag("id");
if (idTag == null) {
continue;
}
short oldId = enchEntry.getShort("id", (short) 0);
CompoundTag enchantmentEntry = new CompoundTag();
short oldId = idTag.asShort();
String newId = Protocol1_12_2To1_13.MAPPINGS.getOldEnchantmentsIds().get(oldId);
if (newId == null) {
newId = "viaversion:legacy/" + oldId;
}
enchantmentEntry.putString("id", newId);
NumberTag levelTag = enchEntry.getNumberTag("lvl");
if (levelTag != null) {
enchantmentEntry.putShort("lvl", levelTag.asShort());
}
enchantmentEntry.putShort("lvl", enchEntry.getShort("lvl", (short) 0));
enchantments.add(enchantmentEntry);
}
@@ -589,10 +581,7 @@ public class ItemPacketRewriter1_13 extends ItemRewriter<ClientboundPackets1_12_
}
if (oldId != null) {
enchEntry.putShort("id", oldId);
NumberTag levelTag = enchantmentEntry.getNumberTag("lvl");
if (levelTag != null) {
enchEntry.putShort("lvl", levelTag.asShort());
}
enchEntry.putShort("lvl", enchantmentEntry.getShort("lvl", (short) 0));
ench.add(enchEntry);
}
}
@@ -53,7 +53,7 @@ import java.util.Iterator;
import java.util.Optional;
public class WorldPacketRewriter1_13 {
private static final IntSet VALID_BIOMES = new IntOpenHashSet(70, .99F);
private static final IntSet VALID_BIOMES = new IntOpenHashSet(70);
static {
// Client will crash if it receives an invalid biome id
@@ -325,7 +325,7 @@ public class WorldPacketRewriter1_13 {
});
protocol.registerClientbound(ClientboundPackets1_12_1.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_12_2To1_13.class);
BlockStorage storage = wrapper.user().get(BlockStorage.class);
ChunkType1_9_3 type = ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment());
@@ -26,7 +26,7 @@ import java.util.Map;
// TODO Fix memory leak lolz (only a smol one tho)
public class BlockStorage implements StorableObject {
private static final IntSet WHITELIST = new IntOpenHashSet(46, .99F);
private static final IntSet WHITELIST = new IntOpenHashSet(46);
private final Map<BlockPosition, ReplacementData> blocks = new HashMap<>();
static {
@@ -121,9 +121,7 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol<ClientboundPackets1_1
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTracker1_14(userConnection));
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -145,4 +143,4 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol<ClientboundPackets1_1
public TagRewriter<ClientboundPackets1_13> getTagRewriter() {
return tagRewriter;
}
}
}
@@ -204,7 +204,7 @@ public class EntityPacketRewriter1_14 extends EntityRewriter<ClientboundPackets1
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
// Store the player
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
ClientWorld clientChunks = wrapper.user().getClientWorld(Protocol1_13_2To1_14.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
@@ -125,7 +125,7 @@ public class WorldPacketRewriter1_14 {
});
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13_2To1_14.class);
Chunk chunk = wrapper.read(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()));
wrapper.write(ChunkType1_14.TYPE, chunk);
@@ -282,21 +282,26 @@ public class WorldPacketRewriter1_14 {
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
short difficulty = wrapper.read(Types.UNSIGNED_BYTE); // 19w11a removed difficulty from respawn
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13_2To1_14.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
if (!clientWorld.setEnvironment(dimensionId)) {
return;
}
EntityTracker1_14 entityTracker = wrapper.user().getEntityTracker(Protocol1_13_2To1_14.class);
entityTracker.clearEntities();
// The client may reset the center chunk if dimension is changed
entityTracker.setForceSendCenterChunk(true);
});
handler(wrapper -> {
short difficulty = wrapper.read(Types.UNSIGNED_BYTE); // 19w11a removed difficulty from respawn
PacketWrapper difficultyPacket = wrapper.create(ClientboundPackets1_14.CHANGE_DIFFICULTY);
difficultyPacket.write(Types.UNSIGNED_BYTE, difficulty);
difficultyPacket.write(Types.BOOLEAN, false); // Unknown value added in 19w11a
difficultyPacket.scheduleSend(protocol.getClass());
});
handler(wrapper -> {
// Manually send the packet and update the viewdistance after
wrapper.send(Protocol1_13_2To1_14.class);
wrapper.cancel();
@@ -134,9 +134,7 @@ public class Protocol1_13To1_13_1 extends AbstractProtocol<ClientboundPackets1_1
@Override
public void init(UserConnection userConnection) {
userConnection.addEntityTracker(this.getClass(), new EntityTrackerBase(userConnection, EntityTypes1_13.EntityType.PLAYER));
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.addClientWorld(this.getClass(), new ClientWorld());
}
@Override
@@ -17,6 +17,7 @@
*/
package com.viaversion.viaversion.protocols.v1_13to1_13_1.rewriter;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_13;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
@@ -34,6 +35,36 @@ public class EntityPacketRewriter1_13_1 extends EntityRewriter<ClientboundPacket
@Override
protected void registerPackets() {
protocol.registerClientbound(ClientboundPackets1_13.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
// Store the player
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_13_1.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_13_1.class);
int dimensionId = wrapper.get(Types.INT, 0);
if (clientWorld.setEnvironment(dimensionId)) {
tracker(wrapper.user()).clearEntities();
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.ADD_ENTITY, new PacketHandlers() {
@Override
public void register() {
@@ -19,9 +19,6 @@ package com.viaversion.viaversion.protocols.v1_13to1_13_1.rewriter;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_13;
@@ -35,7 +32,7 @@ public class WorldPacketRewriter1_13_1 {
BlockRewriter<ClientboundPackets1_13> blockRewriter = BlockRewriter.legacy(protocol);
protocol.registerClientbound(ClientboundPackets1_13.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_13To1_13_1.class);
Chunk chunk = wrapper.passthrough(ChunkType1_13.forEnvironment(clientWorld.getEnvironment()));
blockRewriter.handleChunk(chunk);
@@ -84,33 +81,5 @@ public class WorldPacketRewriter1_13_1 {
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Entity ID
map(Types.UNSIGNED_BYTE); // 1 - Gamemode
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
// Store the player
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientChunks.setEnvironment(dimensionId);
});
}
});
protocol.registerClientbound(ClientboundPackets1_13.RESPAWN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
}
});
}
}
@@ -86,7 +86,10 @@ public class EntityPacketRewriter1_15 extends EntityRewriter<ClientboundPackets1
@Override
public void register() {
map(Types.INT);
handler(wrapper -> wrapper.write(Types.LONG, 0L)); // Level Seed
handler(wrapper -> {
tracker(wrapper.user()).clearEntities();
wrapper.write(Types.LONG, 0L); // Level Seed
});
}
});
@@ -81,14 +81,14 @@ public class Protocol1_15_2To1_16 extends AbstractProtocol<ClientboundPackets1_1
new StatisticsRewriter<>(this).register(ClientboundPackets1_15.AWARD_STATS);
// Login Success
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE.getId(), ClientboundLoginPackets.GAME_PROFILE.getId(), wrapper -> {
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
// Transform string to a uuid
UUID uuid = UUID.fromString(wrapper.read(Types.STRING));
wrapper.write(Types.UUID, uuid);
});
// Motd Status - line breaks are no longer allowed for player samples
registerClientbound(State.STATUS, ClientboundStatusPackets.STATUS_RESPONSE.getId(), ClientboundStatusPackets.STATUS_RESPONSE.getId(), wrapper -> {
registerClientbound(State.STATUS, ClientboundStatusPackets.STATUS_RESPONSE, wrapper -> {
String original = wrapper.passthrough(Types.STRING);
JsonObject object = GsonUtil.getGson().fromJson(original, JsonObject.class);
JsonObject players = object.getAsJsonObject("players");
@@ -263,4 +263,4 @@ public class Protocol1_15_2To1_16 extends AbstractProtocol<ClientboundPackets1_1
public TagRewriter<ClientboundPackets1_15> getTagRewriter() {
return tagRewriter;
}
}
}
@@ -119,6 +119,8 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
map(Types.LONG); // Seed
map(Types.UNSIGNED_BYTE); // Gamemode
handler(wrapper -> {
tracker(wrapper.user()).clearEntities();
wrapper.write(Types.BYTE, (byte) -1); // Previous gamemode, set to none
// <= 1.14.4 didn't keep attributes on respawn and 1.15.x always kept them
@@ -145,9 +147,8 @@ public class EntityPacketRewriter1_16 extends EntityRewriter<ClientboundPackets1
handler(DIMENSION_HANDLER); // Dimension
map(Types.LONG); // Seed
map(Types.UNSIGNED_BYTE); // Max players
handler(playerTrackerHandler());
handler(wrapper -> {
wrapper.user().getEntityTracker(Protocol1_15_2To1_16.class).addEntity(wrapper.get(Types.INT, 0), EntityTypes1_16.PLAYER);
final String type = wrapper.read(Types.STRING);// level type
wrapper.passthrough(Types.VAR_INT); // View distance
wrapper.passthrough(Types.BOOLEAN); // Reduced debug info
@@ -72,6 +72,8 @@ public class EntityPacketRewriter1_16_2 extends EntityRewriter<ClientboundPacket
protocol.registerClientbound(ClientboundPackets1_16.RESPAWN, wrapper -> {
String dimensionType = wrapper.read(Types.STRING);
wrapper.write(Types.NAMED_COMPOUND_TAG, getDimensionData(dimensionType));
tracker(wrapper.user()).clearEntities();
});
}
@@ -37,7 +37,6 @@ import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.EntityPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.ItemPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.WorldPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.storage.InventoryAcknowledgements;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
@@ -68,7 +67,7 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
wrapper.write(Types.STRING, type.resourceLocation());
// Id conversion
tagRewriter.handle(wrapper, tagRewriter.getRewriter(type), tagRewriter.getNewTags(type));
tagRewriter.handle(wrapper, type);
// Stop iterating after entity types
if (type == RegistryType.ENTITY) {
@@ -192,7 +191,6 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
@Override
public void init(UserConnection user) {
addEntityTracker(user, new EntityTrackerBase(user, EntityTypes1_17.PLAYER));
user.put(new InventoryAcknowledgements());
}
@Override
@@ -214,4 +212,4 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
public TagRewriter<ClientboundPackets1_16_2> getTagRewriter() {
return tagRewriter;
}
}
}
@@ -116,6 +116,8 @@ public final class EntityPacketRewriter1_17 extends EntityRewriter<ClientboundPa
protocol.registerClientbound(ClientboundPackets1_16_2.RESPAWN, wrapper -> {
CompoundTag dimensionData = wrapper.passthrough(Types.NAMED_COMPOUND_TAG);
addNewDimensionData(dimensionData);
tracker(wrapper.user()).clearEntities();
});
protocol.registerClientbound(ClientboundPackets1_16_2.UPDATE_ATTRIBUTES, new PacketHandlers() {
@@ -29,7 +29,6 @@ import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_16_4to1_17.Protocol1_16_4To1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ClientboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.storage.InventoryAcknowledgements;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import com.viaversion.viaversion.rewriter.RecipeRewriter;
@@ -97,7 +96,6 @@ public final class ItemPacketRewriter1_17 extends ItemRewriter<ClientboundPacket
if (!accepted) {
// Use the new ping packet to replace the removed acknowledgement, extra bit for fast dismissal
int id = (1 << 30) | (inventoryId << 16) | (confirmationId & 0xFFFF);
wrapper.user().get(InventoryAcknowledgements.class).addId(id);
PacketWrapper pingPacket = wrapper.create(ClientboundPackets1_17.PING);
pingPacket.write(Types.INT, id);
@@ -111,7 +109,7 @@ public final class ItemPacketRewriter1_17 extends ItemRewriter<ClientboundPacket
protocol.registerServerbound(ServerboundPackets1_17.PONG, null, wrapper -> {
int id = wrapper.read(Types.INT);
// Check extra bit for fast dismissal
if ((id & (1 << 30)) != 0 && wrapper.user().get(InventoryAcknowledgements.class).removeId(id)) {
if ((id & (1 << 30)) != 0) {
// Decode our requested inventory acknowledgement
short inventoryId = (short) ((id >> 16) & 0xFF);
short confirmationId = (short) (id & 0xFFFF);
@@ -232,7 +232,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
cancelServerbound(ServerboundPackets1_19.CHAT_PREVIEW);
// Login changes
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE.getId(), ClientboundLoginPackets.GAME_PROFILE.getId(), new PacketHandlers() {
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, new PacketHandlers() {
@Override
public void register() {
map(Types.UUID); // UUID
@@ -241,7 +241,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
}
});
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), new PacketHandlers() {
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Server id
@@ -253,7 +253,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), new PacketHandlers() {
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Name
@@ -261,7 +261,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketHandlers() {
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE_ARRAY_PRIMITIVE); // Keys
@@ -351,4 +351,4 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
public TagRewriter<ClientboundPackets1_18> getTagRewriter() {
return tagRewriter;
}
}
}
@@ -279,7 +279,7 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
}
});
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), new PacketHandlers() {
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Server id
@@ -291,7 +291,7 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
});
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), new PacketHandlers() {
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Name
@@ -302,7 +302,7 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
map(Types.OPTIONAL_UUID); // Profile uuid
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketHandlers() {
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE_ARRAY_PRIMITIVE); // Public key
@@ -384,4 +384,4 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
public TagRewriter<ClientboundPackets1_19_1> getTagRewriter() {
return tagRewriter;
}
}
}
@@ -79,8 +79,8 @@ public final class EntityPacketRewriter1_20 extends EntityRewriter<ClientboundPa
final ListTag<CompoundTag> damageTypes = TagUtil.getRegistryEntries(registry, "damage_type");
int highestId = -1;
for (final CompoundTag damageType : damageTypes) {
final IntTag id = damageType.getUnchecked("id");
highestId = Math.max(highestId, id.asInt());
final int id = damageType.getInt("id");
highestId = Math.max(highestId, id);
}
// AaaaAAAaa
@@ -228,7 +228,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), new PacketHandlers() {
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Name
@@ -246,7 +246,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
read(Types.OPTIONAL_UUID); // Profile uuid
}
});
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), new PacketHandlers() {
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, new PacketHandlers() {
@Override
public void register() {
map(Types.STRING); // Server id
@@ -261,7 +261,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
});
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketHandlers() {
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE_ARRAY_PRIMITIVE); // Keys
@@ -281,7 +281,7 @@ public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPack
});
}
});
registerClientbound(State.LOGIN, ClientboundLoginPackets.CUSTOM_QUERY.getId(), ClientboundLoginPackets.CUSTOM_QUERY.getId(), new PacketHandlers() {
registerClientbound(State.LOGIN, ClientboundLoginPackets.CUSTOM_QUERY, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT);
@@ -17,6 +17,7 @@
*/
package com.viaversion.viaversion.protocols.v1_20_2to1_20_3;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
@@ -28,18 +29,11 @@ import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvide
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_20_3;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.rewriter.CommandRewriter1_19_4;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPacket1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPacket1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ClientboundConfigurationPackets1_20_3;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ClientboundPacket1_20_3;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ClientboundPackets1_20_3;
@@ -47,6 +41,12 @@ import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ServerboundPackets1_20_3;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.BlockItemPacketRewriter1_20_3;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.EntityPacketRewriter1_20_3;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPacket1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPacket1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPackets1_20_2;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
@@ -107,8 +107,13 @@ public final class Protocol1_20_2To1_20_3 extends AbstractProtocol<ClientboundPa
final byte action = wrapper.passthrough(Types.BYTE); // Method
if (action == 0 || action == 2) {
convertComponent(wrapper); // Display Name
wrapper.passthrough(Types.VAR_INT); // Render type
wrapper.write(Types.BOOLEAN, false); // Null number format
final int render = wrapper.passthrough(Types.VAR_INT); // Render type
if (render == 0 && Via.getConfig().hideScoreboardNumbers()) { // 0 = "integer", 1 = "hearts"
wrapper.write(Types.BOOLEAN, true); // has number format
wrapper.write(Types.VAR_INT, 0); // Blank format
} else {
wrapper.write(Types.BOOLEAN, false); // has number format
}
}
});
@@ -300,7 +305,7 @@ public final class Protocol1_20_2To1_20_3 extends AbstractProtocol<ClientboundPa
registerServerbound(ServerboundConfigurationPackets1_20_2.RESOURCE_PACK, resourcePackStatusHandler());
registerClientbound(ClientboundConfigurationPackets1_20_2.RESOURCE_PACK, ClientboundConfigurationPackets1_20_3.RESOURCE_PACK_PUSH, resourcePackHandler(ClientboundConfigurationPackets1_20_3.RESOURCE_PACK_POP));
registerClientbound(ClientboundConfigurationPackets1_20_2.UPDATE_TAGS, tagRewriter.getGenericHandler());
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_20_2.UPDATE_TAGS);
}
private PacketHandler resourcePackStatusHandler() {
@@ -17,10 +17,10 @@
*/
package com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter;
import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.ParticleMappings;
@@ -31,17 +31,18 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_20_3;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPacket1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.rewriter.RecipeRewriter1_20_2;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_3;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ServerboundPacket1_20_3;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ServerboundPackets1_20_3;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPacket1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.rewriter.RecipeRewriter1_20_2;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.logging.Level;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class BlockItemPacketRewriter1_20_3 extends ItemRewriter<ClientboundPacket1_20_2, ServerboundPacket1_20_3, Protocol1_20_2To1_20_3> {
@@ -167,7 +168,9 @@ public final class BlockItemPacketRewriter1_20_3 extends ItemRewriter<Clientboun
final JsonElement updatedComponent = ComponentUtil.convertJson(pageTag.getValue(), SerializerVersion.V1_19_4, SerializerVersion.V1_20_3);
pageTag.setValue(updatedComponent.toString());
} catch (final Exception e) {
Via.getManager().debugHandler().error("Error during book conversion", e);
if (!Via.getConfig().isSuppressConversionWarnings()) {
protocol.getLogger().log(Level.SEVERE, "Error during book conversion: " + pageTag.getValue(), e);
}
}
}
}
}
@@ -103,6 +103,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
componentRewriter.registerBossEvent(ClientboundPackets1_20_3.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_20_3.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_20_3.TAB_LIST);
componentRewriter.registerPlayerInfoUpdate1_20_3(ClientboundPackets1_20_3.PLAYER_INFO_UPDATE);
componentRewriter.registerPing();
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO, wrapper -> {
@@ -285,6 +286,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
tagRewriter.renameTag(RegistryType.ITEM, "minecraft:axolotl_tempt_items", "minecraft:axolotl_food");
tagRewriter.removeTag(RegistryType.ITEM, "minecraft:tools");
tagRewriter.addEmptyTags(RegistryType.BLOCK, "minecraft:badlands_terracotta");
tagRewriter.addEmptyTags(RegistryType.ITEM, "minecraft:enchantable/mace");
super.onMappingDataLoaded();
}
@@ -304,8 +304,10 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
wrapper.passthrough(Types.FLOAT); // Knockback Z
wrapper.passthrough(Types.VAR_INT); // Block interaction type
protocol.getEntityRewriter().rewriteParticle(wrapper, Types1_20_3.PARTICLE, Types1_20_5.PARTICLE); // Small explosion particle
protocol.getEntityRewriter().rewriteParticle(wrapper, Types1_20_3.PARTICLE, Types1_20_5.PARTICLE); // Large explosion particle
final Particle smallExplosionParticle = wrapper.passthroughAndMap(Types1_20_3.PARTICLE, Types1_20_5.PARTICLE);
final Particle largeExplosionParticle = wrapper.passthroughAndMap(Types1_20_3.PARTICLE, Types1_20_5.PARTICLE);
rewriteParticle(wrapper.user(), smallExplosionParticle);
rewriteParticle(wrapper.user(), largeExplosionParticle);
final String sound = wrapper.read(Types.STRING);
final Float range = wrapper.read(Types.OPTIONAL_FLOAT);
@@ -376,13 +378,15 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return StructuredItem.empty();
}
// Add the original as custom data, to be re-used for creative clients as well
final CompoundTag tag = item.tag();
final Item structuredItem = toStructuredItem(connection, item);
// Add the original as custom data, to be re-used for creative clients as well
if (tag != null) {
tag.putBoolean(nbtTagName(), true);
structuredItem.dataContainer().set(StructuredDataKey.CUSTOM_DATA, tag);
}
final Item structuredItem = toStructuredItem(connection, item);
// Add data components to fix issues in older protocols
appendItemDataFixComponents(connection, structuredItem);
@@ -412,10 +416,11 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
final StructuredDataContainer data = item.dataContainer();
data.setIdLookup(protocol, true);
final StructuredData<CompoundTag> customData = data.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
final StructuredData<CompoundTag> customData = data.getNonEmptyData(StructuredDataKey.CUSTOM_DATA);
final CompoundTag tag = customData != null ? customData.value() : new CompoundTag();
final DataItem dataItem = new DataItem(item.identifier(), (byte) item.amount(), tag);
if (customData != null && tag.remove(nbtTagName()) != null) {
if (!dataConverter.backupInconvertibleData() && customData != null && tag.remove(nbtTagName()) != null) {
// Skip for VB since it's used for incoming item data
return dataItem;
}
@@ -483,7 +488,11 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
if (blockEntityTag != null) {
final CompoundTag clonedTag = blockEntityTag.copy();
updateBlockEntityTag(connection, data, clonedTag);
item.dataContainer().set(StructuredDataKey.BLOCK_ENTITY_DATA, clonedTag);
// Not always needed, e.g. shields that had the base color in a block entity tag before
if (blockEntityTag.contains("id")) {
item.dataContainer().set(StructuredDataKey.BLOCK_ENTITY_DATA, clonedTag);
}
}
final CompoundTag debugProperty = tag.getCompoundTag("DebugProperty");
@@ -605,8 +614,6 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
// Restore original data components
restoreFromBackupTag(backupTag, data);
}
data.set(StructuredDataKey.CUSTOM_DATA, tag);
return item;
}
@@ -1160,47 +1167,63 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
}
private void updateWrittenBookPages(final UserConnection connection, final StructuredDataContainer data, final CompoundTag tag) {
final String title = tag.getString("title");
final String author = tag.getString("author");
final ListTag<StringTag> pagesTag = tag.getListTag("pages", StringTag.class);
final CompoundTag filteredPagesTag = tag.getCompoundTag("filtered_pages");
if (pagesTag == null) {
return;
boolean valid = author != null && title != null && title.length() <= 32 && pagesTag != null;
if (valid) {
for (final StringTag page : pagesTag) {
if (page.getValue().length() > Short.MAX_VALUE) {
valid = false;
break;
}
}
}
final List<FilterableComponent> pages = new ArrayList<>();
for (int i = 0; i < pagesTag.size(); i++) {
final StringTag page = pagesTag.get(i);
Tag filtered = null;
if (filteredPagesTag != null) {
final StringTag filteredPage = filteredPagesTag.getStringTag(String.valueOf(i));
if (filteredPage != null) {
try {
filtered = jsonToTag(connection, filteredPage);
} catch (final Exception e) {
// A 1.20.4 client would display the broken json raw, but a 1.20.5 client would die
continue;
if (valid) {
final CompoundTag filteredPagesTag = tag.getCompoundTag("filtered_pages");
for (int i = 0; i < pagesTag.size(); i++) {
final StringTag page = pagesTag.get(i);
Tag filtered = null;
if (filteredPagesTag != null) {
final StringTag filteredPage = filteredPagesTag.getStringTag(String.valueOf(i));
if (filteredPage != null) {
try {
filtered = jsonToTag(connection, filteredPage);
} catch (final Exception e) {
// A 1.20.4 client would display the broken json raw, but a 1.20.5 client would die
continue;
}
}
}
}
final Tag parsedPage;
try {
parsedPage = jsonToTag(connection, page);
} catch (final Exception e) {
// Same as above
continue;
}
final Tag parsedPage;
try {
parsedPage = jsonToTag(connection, page);
} catch (final Exception e) {
// Same as above
continue;
}
pages.add(new FilterableComponent(parsedPage, filtered));
pages.add(new FilterableComponent(parsedPage, filtered));
}
} else {
final CompoundTag invalidPage = new CompoundTag();
invalidPage.putString("text", "* Invalid book tag *");
invalidPage.putString("color", "#AA0000"); // dark red
pages.add(new FilterableComponent(invalidPage, null));
}
final String title = tag.getString("title", "");
final String filteredTitle = tag.getString("filtered_title"); // Nullable
final String author = tag.getString("author", "");
final int generation = tag.getInt("generation");
final boolean resolved = tag.getBoolean("resolved");
final WrittenBook writtenBook = new WrittenBook(
new FilterableString(limit(title, 32), limit(filteredTitle, 32)),
author,
new FilterableString(limit(title == null ? "" : title, 32), limit(filteredTitle, 32)),
author == null ? "" : author,
clamp(generation, 0, 3),
pages.toArray(new FilterableComponent[0]),
resolved
@@ -396,6 +396,14 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
}
protected CompoundTag convertCanPlaceOn(final AdventureModePredicate value) {
return convertBlockPredicate(value);
}
protected CompoundTag convertCanBreak(final AdventureModePredicate value) {
return convertBlockPredicate(value);
}
protected CompoundTag convertBlockPredicate(final AdventureModePredicate value) {
final CompoundTag tag = new CompoundTag();
final ListTag<CompoundTag> predicates = new ListTag<>(CompoundTag.class);
for (final BlockPredicate predicate : value.predicates()) {
@@ -404,8 +412,7 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
convertHolderSet(predicateTag, "blocks", predicate.holderSet());
}
if (predicate.propertyMatchers() != null) {
final CompoundTag state = convertPredicate(predicate);
predicateTag.put("state", state);
predicateTag.put("state", createState(predicate));
}
if (predicate.tag() != null) {
predicateTag.put("nbt", predicate.tag());
@@ -420,8 +427,10 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
return tag;
}
protected CompoundTag convertPredicate(final BlockPredicate predicate) {
// Not an own conversion method, just to avoid high nesting
protected CompoundTag createState(BlockPredicate predicate) {
final CompoundTag state = new CompoundTag();
for (final StatePropertyMatcher matcher : predicate.propertyMatchers()) {
final Either<String, StatePropertyMatcher.RangedMatcher> match = matcher.matcher();
if (match.isLeft()) {
@@ -441,10 +450,6 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
return state;
}
protected CompoundTag convertCanBreak(final AdventureModePredicate value) {
return convertCanPlaceOn(value);
}
protected CompoundTag convertAttributeModifiers(final AttributeModifiers1_20_5 value) {
final CompoundTag tag = new CompoundTag();
final ListTag<CompoundTag> modifiers = new ListTag<>(CompoundTag.class);
@@ -500,7 +505,7 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
protected CompoundTag convertFood(final FoodProperties value) {
final CompoundTag tag = new CompoundTag();
tag.put("nutrition", convertNonNegativeInt(value.nutrition()));
tag.putFloat("saturation_modifier", value.saturationModifier());
tag.putFloat("saturation", value.saturationModifier());
if (value.canAlwaysEat()) {
tag.putBoolean("can_always_eat", true);
}
@@ -946,7 +951,17 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
if (set.hasTagKey()) {
tag.putString(name, set.tagKey());
} else {
tag.put(name, new IntArrayTag(set.ids()));
final ListTag<StringTag> identifiers = new ListTag<>(StringTag.class);
for (final int id : set.ids()) {
// Can use old block list because new ids are only at the end :tm:
final String identifier = Protocol1_20_3To1_20_5.MAPPINGS.blockName(id);
if (identifier == null) {
continue;
}
identifiers.add(new StringTag(identifier));
}
tag.put(name, identifiers);
}
}
@@ -83,13 +83,16 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
byte slot;
do {
slot = wrapper.read(Types.BYTE);
if (type != null && type.isOrHasParent(EntityTypes1_20_5.ABSTRACT_HORSE) && slot == 4) {
slot = 6; // Map chest slot index to body slot index for horses
final int rawSlot = slot & 0x7F;
if (type != null && type.isOrHasParent(EntityTypes1_20_5.ABSTRACT_HORSE) && rawSlot == 4) {
final boolean lastSlot = (slot & 0xFFFFFF80) == 0;
slot = (byte) (lastSlot ? 6 : 6 | 0xFFFFFF80); // Map chest slot index to body slot index for horses
}
wrapper.write(Types.BYTE, slot);
Item item = protocol.getItemRewriter().handleItemToClient(wrapper.user(), wrapper.read(Types.ITEM1_20_2));
wrapper.write(Types1_20_5.ITEM, item);
} while (slot < 0);
} while ((slot & 0xFFFFFF80) != 0);
});
protocol.registerClientbound(ClientboundConfigurationPackets1_20_3.REGISTRY_DATA, wrapper -> {
@@ -72,7 +72,6 @@ import java.util.Collections;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
// 1.20.5 data component -> 1.20.3 nbt conversion
public final class StructuredDataConverter {
static final int HIDE_ENCHANTMENTS = 1;
@@ -45,6 +45,7 @@ import com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter.BlockItemPacke
import com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter.ComponentRewriter1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter.EntityPacketRewriter1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.EfficiencyAttributeStorage;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.OnGroundTracker;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
@@ -216,12 +217,18 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol<ClientboundPack
tagRewriter.addEmptyTags(RegistryType.ENTITY, "minecraft:can_turn_in_boats", "minecraft:deflects_projectiles", "minecraft:immune_to_infested",
"minecraft:immune_to_oozing", "minecraft:no_anger_from_wind_charge");
tagRewriter.addTag(RegistryType.ENCHANTMENT, "minecraft:curse", 10, 41); // Binding and vanishing curse
// Add other enchantment tags empty
tagRewriter.addEmptyTags(RegistryType.ENCHANTMENT, "double_trade_price", "in_enchanting_table", "non_treasure", "on_mob_spawn_equipment", "on_random_loot",
"on_traded_equipment", "prevents_bee_spawns_when_mining", "prevents_decorated_pot_shattering", "prevents_ice_melting", "prevents_infested_spawns", "smelts_loot",
"tooltip_order", "tradeable", "treasure", "exclusive_set/armor", "exclusive_set/boots", "exclusive_set/bow", "exclusive_set/crossbow", "exclusive_set/damage",
"exclusive_set/mining", "exclusive_set/riptide");
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_20_5.PLAYER));
connection.put(new EfficiencyAttributeStorage());
connection.put(new OnGroundTracker());
}
@Override
@@ -258,4 +265,4 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol<ClientboundPack
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class)
);
}
}
}
@@ -19,13 +19,14 @@ package com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
@@ -37,6 +38,7 @@ import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.data.AttributeModifierMappings1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.OnGroundTracker;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import java.util.Arrays;
@@ -48,7 +50,11 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
private static final List<String> DISCS = List.of("11", "13", "5", "blocks", "cat", "chirp", "far", "mall", "mellohi", "otherside", "pigstep", "relic", "stal", "strad", "wait", "ward");
public BlockItemPacketRewriter1_21(final Protocol1_20_5To1_21 protocol) {
super(protocol, Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY, Types1_21.ITEM, Types1_21.ITEM_ARRAY);
super(protocol,
Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY, Types1_21.ITEM, Types1_21.ITEM_ARRAY,
Types1_20_5.ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST, Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST,
Types1_20_5.PARTICLE, Types1_21.PARTICLE
);
}
@Override
@@ -66,10 +72,10 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
registerAdvancements1_20_3(ClientboundPackets1_20_5.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_20_5.SET_EQUIPMENT);
registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerMerchantOffers1_20_5(ClientboundPackets1_20_5.MERCHANT_OFFERS, Types1_20_5.ITEM_COST, Types1_21.ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST, Types1_21.OPTIONAL_ITEM_COST);
registerMerchantOffers1_20_5(ClientboundPackets1_20_5.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
registerLevelParticles1_20_5(ClientboundPackets1_20_5.LEVEL_PARTICLES, Types1_20_5.PARTICLE, Types1_21.PARTICLE);
registerExplosion(ClientboundPackets1_20_5.EXPLODE, Types1_20_5.PARTICLE, Types1_21.PARTICLE); // Rewrites the included sound and particles
registerLevelParticles1_20_5(ClientboundPackets1_20_5.LEVEL_PARTICLES);
registerExplosion(ClientboundPackets1_20_5.EXPLODE); // Rewrites the included sound and particles
protocol.registerClientbound(ClientboundPackets1_20_5.HORSE_SCREEN_OPEN, wrapper -> {
wrapper.passthrough(Types.UNSIGNED_BYTE); // Container id
@@ -102,8 +108,23 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
protocol.registerServerbound(ServerboundPackets1_20_5.USE_ITEM, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Hand
wrapper.passthrough(Types.VAR_INT); // Sequence
wrapper.read(Types.FLOAT); // Y rotation
wrapper.read(Types.FLOAT); // X rotation
final float yaw = wrapper.read(Types.FLOAT); // Y rotation
final float pitch = wrapper.read(Types.FLOAT); // X rotation
if (!Via.getConfig().fix1_21PlacementRotation()) {
return;
}
final OnGroundTracker tracker = wrapper.user().get(OnGroundTracker.class);
// Not correct but *enough* for vanilla/normal servers to have block placement synchronized
final PacketWrapper playerRotation = wrapper.create(ServerboundPackets1_20_5.MOVE_PLAYER_ROT);
playerRotation.write(Types.FLOAT, yaw);
playerRotation.write(Types.FLOAT, pitch);
playerRotation.write(Types.BOOLEAN, tracker.onGround());
playerRotation.sendToServer(Protocol1_20_5To1_21.class);
wrapper.sendToServer(Protocol1_20_5To1_21.class);
wrapper.cancel();
});
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_20_5.UPDATE_RECIPES);
@@ -119,7 +140,7 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
updateItemData(item);
final StructuredDataContainer dataContainer = item.dataContainer();
if (dataContainer.contains(StructuredDataKey.RARITY)) {
if (dataContainer.has(StructuredDataKey.RARITY)) {
return item;
}
@@ -190,14 +211,14 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
public static void resetRarityValues(final Item item, final String tagName) {
final StructuredDataContainer dataContainer = item.dataContainer();
final StructuredData<CompoundTag> customData = dataContainer.getNonEmpty(StructuredDataKey.CUSTOM_DATA);
final CompoundTag customData = dataContainer.get(StructuredDataKey.CUSTOM_DATA);
if (customData == null) {
return;
}
if (customData.value().remove(tagName) != null) {
if (customData.remove(tagName) != null) {
dataContainer.remove(StructuredDataKey.RARITY);
if (customData.value().isEmpty()) {
if (customData.isEmpty()) {
dataContainer.remove(StructuredDataKey.CUSTOM_DATA);
}
}
@@ -212,4 +233,4 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter<Cl
identifier = identifier.substring("minecraft:music_disc_".length());
return DISCS.indexOf(identifier);
}
}
}
@@ -18,6 +18,7 @@
package com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
@@ -33,9 +34,11 @@ import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.data.Enchantments1_20
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.data.Paintings1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.EfficiencyAttributeStorage;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.OnGroundTracker;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.util.ArrayUtil;
import com.viaversion.viaversion.util.Key;
@@ -128,6 +131,36 @@ public final class EntityPacketRewriter1_21 extends EntityRewriter<ClientboundPa
// Resend attribute modifiers from items
wrapper.user().get(EfficiencyAttributeStorage.class).onRespawn(wrapper.user());
});
// Tracks on ground state for block interactions
if (!Via.getConfig().fix1_21PlacementRotation()) {
return;
}
protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_POS, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.user().get(OnGroundTracker.class).setOnGround(wrapper.passthrough(Types.BOOLEAN));
});
protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_ROT, wrapper -> {
wrapper.passthrough(Types.FLOAT); // Yaw
wrapper.passthrough(Types.FLOAT); // Pitch
wrapper.user().get(OnGroundTracker.class).setOnGround(wrapper.passthrough(Types.BOOLEAN));
});
protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_POS_ROT, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.passthrough(Types.FLOAT); // Yaw
wrapper.passthrough(Types.FLOAT); // Pitch
wrapper.user().get(OnGroundTracker.class).setOnGround(wrapper.passthrough(Types.BOOLEAN));
});
protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_STATUS_ONLY, wrapper -> {
wrapper.user().get(OnGroundTracker.class).setOnGround(wrapper.passthrough(Types.BOOLEAN));
});
}
@Override
@@ -15,20 +15,19 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_16_4to1_17.storage;
package com.viaversion.viaversion.protocols.v1_20_5to1_21.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
public final class InventoryAcknowledgements implements StorableObject {
private final IntList ids = new IntArrayList();
public final class OnGroundTracker implements StorableObject {
public void addId(int id) {
ids.add(id);
private boolean onGround;
public boolean onGround() {
return onGround;
}
public boolean removeId(int id) {
return ids.rem(id);
public void setOnGround(final boolean onGround) {
this.onGround = onGround;
}
}
@@ -116,12 +116,12 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
});
registerClientbound(ClientboundPackets1_19_4.UPDATE_TAGS, wrapper -> {
tagRewriter.getGenericHandler().handle(wrapper);
tagRewriter.handleGeneric(wrapper);
wrapper.resetReader();
wrapper.user().put(new LastTags(wrapper));
});
registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.UPDATE_TAGS.getId(), ClientboundConfigurationPackets1_20_2.UPDATE_TAGS.getId(), wrapper -> {
tagRewriter.getGenericHandler().handle(wrapper);
registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.UPDATE_TAGS, wrapper -> {
tagRewriter.handleGeneric(wrapper);
wrapper.resetReader();
wrapper.user().put(new LastTags(wrapper));
});
@@ -131,7 +131,7 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
wrapper.write(Types.VAR_INT, (int) slot);
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), wrapper -> {
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO, wrapper -> {
wrapper.passthrough(Types.STRING); // Name
final UUID uuid = wrapper.read(Types.UUID);
@@ -144,7 +144,7 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
// We need to wait for it send the login ack before actually sending the play login,
// hence packets are added to a queue. With the data from the login packet, we sent what is needed
// during the configuration phase before finally transitioning to the play state with the client as well.
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE.getId(), ClientboundLoginPackets.GAME_PROFILE.getId(), wrapper -> {
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
wrapper.user().get(ConfigurationState.class).setBridgePhase(BridgePhase.PROFILE_SENT);
wrapper.user().getProtocolInfo().setServerState(State.PLAY);
});
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.protocols.v1_20to1_20_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.TagData;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2;
@@ -34,15 +35,14 @@ public class LastTags implements StorableObject {
public LastTags(final PacketWrapper wrapper) {
final int length = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < length; i++) {
final List<Tag> tags = new ArrayList<>();
final List<TagData> tags = new ArrayList<>();
final String registryKey = wrapper.passthrough(Types.STRING);
final int tagsSize = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < tagsSize; j++) {
final String key = wrapper.passthrough(Types.STRING);
final int[] ids = wrapper.passthrough(Types.VAR_INT_ARRAY_PRIMITIVE);
tags.add(new Tag(key, ids));
tags.add(new TagData(key, ids));
}
this.registryTags.add(new RegistryTags(registryKey, tags));
}
}
@@ -57,17 +57,14 @@ public class LastTags implements StorableObject {
for (final RegistryTags registryTag : registryTags) {
packet.write(Types.STRING, registryTag.registryKey);
packet.write(Types.VAR_INT, registryTag.tags.size());
for (final Tag tag : registryTag.tags) {
packet.write(Types.STRING, tag.key);
packet.write(Types.VAR_INT_ARRAY_PRIMITIVE, Arrays.copyOf(tag.ids, tag.ids.length));
for (final TagData tag : registryTag.tags) {
packet.write(Types.STRING, tag.identifier());
packet.write(Types.VAR_INT_ARRAY_PRIMITIVE, Arrays.copyOf(tag.entries(), tag.entries().length));
}
}
packet.send(Protocol1_20To1_20_2.class);
}
private record RegistryTags(String registryKey, List<Tag> tags) {
}
private record Tag(String key, int[] ids) {
private record RegistryTags(String registryKey, List<TagData> tags) {
}
}
@@ -43,7 +43,7 @@ import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.ItemPacketRewriter
import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.PlayerPacketRewriter1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.SpawnPacketRewriter1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.rewriter.WorldPacketRewriter1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientChunks;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientWorld1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.CommandBlockStorage;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.InventoryTracker;
@@ -83,14 +83,7 @@ public class Protocol1_8To1_9 extends AbstractProtocol<ClientboundPackets1_8, Cl
protected void registerPackets() {
super.registerPackets();
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_DISCONNECT.getId(), ClientboundLoginPackets.LOGIN_DISCONNECT.getId(), wrapper -> {
if (wrapper.isReadable(Types.COMPONENT, 0)) {
// Already written as component in the base protocol
return;
}
STRING_TO_JSON.write(wrapper, wrapper.read(Types.STRING));
});
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_DISCONNECT, wrapper -> STRING_TO_JSON.write(wrapper, wrapper.read(Types.STRING)));
// Other Handlers
SpawnPacketRewriter1_9.register(this);
@@ -111,20 +104,12 @@ public class Protocol1_8To1_9 extends AbstractProtocol<ClientboundPackets1_8, Cl
@Override
public void init(UserConnection userConnection) {
// Entity tracker
userConnection.addEntityTracker(this.getClass(), new EntityTracker1_9(userConnection));
// Chunk tracker
userConnection.put(new ClientChunks());
// Movement tracker
userConnection.put(new MovementTracker());
// Inventory tracker
userConnection.put(new InventoryTracker());
// CommandBlock storage
userConnection.put(new CommandBlockStorage());
userConnection.addClientWorld(this.getClass(), new ClientWorld1_9());
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.put(new MovementTracker());
userConnection.put(new InventoryTracker());
userConnection.put(new CommandBlockStorage());
}
@Override
@@ -22,7 +22,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
public class EffectIdMappings1_9 {
private static final Int2IntMap EFFECTS = new Int2IntOpenHashMap(19, .99F);
private static final Int2IntMap EFFECTS = new Int2IntOpenHashMap(19);
static {
addRewrite(1005, 1010); //Play music disc
@@ -27,7 +27,7 @@ public class PotionIdMappings1_9 {
public static final Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
public static final Map<Integer, String> POTION_ID_TO_NAME = new HashMap<>();
public static final Int2IntMap POTION_INDEX = new Int2IntOpenHashMap(36, .99F);
public static final Int2IntMap POTION_INDEX = new Int2IntOpenHashMap(36);
static {
register(-1, "empty");
@@ -25,8 +25,8 @@ public enum SoundEffectMappings1_9 {
MOB_HORSE_ZOMBIE_IDLE("mob.horse.zombie.idle", "entity.zombie_horse.ambient", SoundCategories1_8.NEUTRAL),
NOTE_SNARE("note.snare", "block.note.snare", SoundCategories1_8.RECORD),
RANDOM_WOOD_CLICK("random.wood_click", "block.wood_button.click_on", SoundCategories1_8.BLOCK),
DIG_GRAVEL("dig.gravel", "block.gravel.place", SoundCategories1_8.BLOCK),
RANDOM_BOWHIT("random.bowhit", "block.tripwire.detach", SoundCategories1_8.NEUTRAL),
DIG_GRAVEL("dig.gravel", "block.gravel.break", SoundCategories1_8.BLOCK),
RANDOM_BOWHIT("random.bowhit", "entity.arrow.hit", SoundCategories1_8.NEUTRAL),
DIG_GLASS("dig.glass", "block.glass.break", SoundCategories1_8.BLOCK),
MOB_ZOMBIE_SAY("mob.zombie.say", "entity.zombie.ambient", SoundCategories1_8.HOSTILE),
MOB_PIG_DEATH("mob.pig.death", "entity.pig.death", SoundCategories1_8.NEUTRAL),
@@ -42,34 +42,34 @@ public enum SoundEffectMappings1_9 {
MOB_ZOMBIEPIG_ZPIGHURT("mob.zombiepig.zpighurt", "entity.zombie_pig.hurt", SoundCategories1_8.HOSTILE),
MOB_WOLF_HOWL("mob.wolf.howl", "entity.wolf.howl", SoundCategories1_8.NEUTRAL),
FIREWORKS_LAUNCH("fireworks.launch", "entity.firework.launch", SoundCategories1_8.AMBIENT),
MOB_COW_HURT("mob.cow.hurt", "entity.cow.death", SoundCategories1_8.NEUTRAL),
MOB_COW_HURT("mob.cow.hurt", "entity.cow.hurt", SoundCategories1_8.NEUTRAL),
FIREWORKS_LARGEBLAST("fireworks.largeBlast", "entity.firework.large_blast", SoundCategories1_8.AMBIENT),
MOB_BLAZE_HIT("mob.blaze.hit", "entity.blaze.hurt", SoundCategories1_8.HOSTILE),
MOB_VILLAGER_DEATH("mob.villager.death", "entity.villager.death", SoundCategories1_8.NEUTRAL),
MOB_BLAZE_DEATH("mob.blaze.death", "entity.blaze.death", SoundCategories1_8.HOSTILE),
MOB_HORSE_ZOMBIE_DEATH("mob.horse.zombie.death", "entity.zombie_horse.death", SoundCategories1_8.NEUTRAL),
MOB_SILVERFISH_KILL("mob.silverfish.kill", "entity.endermite.death", SoundCategories1_8.HOSTILE),
MOB_SILVERFISH_KILL("mob.silverfish.kill", "entity.silverfish.death", SoundCategories1_8.HOSTILE),
MOB_WOLF_PANTING("mob.wolf.panting", "entity.wolf.pant", SoundCategories1_8.NEUTRAL),
NOTE_BASS("note.bass", "block.note.bass", SoundCategories1_8.RECORD),
DIG_STONE("dig.stone", "block.glass.place", SoundCategories1_8.BLOCK),
DIG_STONE("dig.stone", "block.stone.break", SoundCategories1_8.BLOCK),
MOB_ENDERMEN_STARE("mob.endermen.stare", "entity.endermen.stare", SoundCategories1_8.HOSTILE),
GAME_PLAYER_SWIM_SPLASH("game.player.swim.splash", "entity.generic.splash", SoundCategories1_8.BLOCK),
MOB_SLIME_SMALL("mob.slime.small", "block.slime.hit", SoundCategories1_8.HOSTILE),
MOB_SLIME_SMALL("mob.slime.small", "entity.small_slime.hurt", SoundCategories1_8.HOSTILE),
MOB_GHAST_DEATH("mob.ghast.death", "entity.ghast.death", SoundCategories1_8.HOSTILE),
MOB_GUARDIAN_ATTACK("mob.guardian.attack", "entity.guardian.attack", SoundCategories1_8.HOSTILE),
RANDOM_CLICK("random.click", "block.wood_pressureplate.click_on", SoundCategories1_8.BLOCK),
RANDOM_CLICK("random.click", "block.dispenser.dispense", SoundCategories1_8.BLOCK),
MOB_ZOMBIEPIG_ZPIG("mob.zombiepig.zpig", "entity.zombie_pig.ambient", SoundCategories1_8.HOSTILE),
GAME_PLAYER_DIE("game.player.die", "entity.player.death", SoundCategories1_8.PLAYER),
FIREWORKS_TWINKLE_FAR("fireworks.twinkle_far", "entity.firework.twinkle_far", SoundCategories1_8.AMBIENT),
MOB_GUARDIAN_LAND_IDLE("mob.guardian.land.idle", "entity.guardian.ambient_land", SoundCategories1_8.HOSTILE),
DIG_GRASS("dig.grass", "block.grass.place", SoundCategories1_8.BLOCK),
DIG_GRASS("dig.grass", "block.grass.break", SoundCategories1_8.BLOCK),
MOB_SKELETON_STEP("mob.skeleton.step", "entity.skeleton.step", SoundCategories1_8.HOSTILE),
MOB_WITHER_DEATH("mob.wither.death", "entity.wither.death", SoundCategories1_8.HOSTILE),
MOB_WOLF_HURT("mob.wolf.hurt", "entity.wolf.hurt", SoundCategories1_8.NEUTRAL),
MOB_HORSE_LEATHER("mob.horse.leather", "entity.horse.saddle", SoundCategories1_8.NEUTRAL),
MOB_BAT_LOOP("mob.bat.loop", "entity.bat.loop", SoundCategories1_8.NEUTRAL),
MOB_GHAST_SCREAM("mob.ghast.scream", "entity.ghast.hurt", SoundCategories1_8.HOSTILE),
GAME_PLAYER_HURT("game.player.hurt", "entity.player.death", SoundCategories1_8.PLAYER),
GAME_PLAYER_HURT("game.player.hurt", "entity.player.hurt", SoundCategories1_8.PLAYER),
GAME_NEUTRAL_DIE("game.neutral.die", "entity.player.death", SoundCategories1_8.NEUTRAL),
MOB_CREEPER_DEATH("mob.creeper.death", "entity.creeper.death", SoundCategories1_8.HOSTILE),
MOB_HORSE_GALLOP("mob.horse.gallop", "entity.horse.gallop", SoundCategories1_8.NEUTRAL),
@@ -83,7 +83,7 @@ public enum SoundEffectMappings1_9 {
MOB_SHEEP_SHEAR("mob.sheep.shear", "entity.sheep.shear", SoundCategories1_8.NEUTRAL),
RANDOM_POP("random.pop", "entity.item.pickup", SoundCategories1_8.PLAYER),
MOB_BAT_DEATH("mob.bat.death", "entity.bat.death", SoundCategories1_8.NEUTRAL),
DIG_WOOD("dig.wood", "block.ladder.break", SoundCategories1_8.BLOCK),
DIG_WOOD("dig.wood", "block.wood.break", SoundCategories1_8.BLOCK),
MOB_HORSE_DONKEY_DEATH("mob.horse.donkey.death", "entity.donkey.death", SoundCategories1_8.NEUTRAL),
FIREWORKS_BLAST("fireworks.blast", "entity.firework.blast", SoundCategories1_8.AMBIENT),
MOB_ZOMBIEPIG_ZPIGANGRY("mob.zombiepig.zpigangry", "entity.zombie_pig.angry", SoundCategories1_8.HOSTILE),
@@ -98,7 +98,7 @@ public enum SoundEffectMappings1_9 {
MOB_GUARDIAN_ELDER_DEATH("mob.guardian.elder.death", "entity.elder_guardian.death", SoundCategories1_8.HOSTILE),
FIREWORKS_TWINKLE("fireworks.twinkle", "entity.firework.twinkle", SoundCategories1_8.AMBIENT),
MOB_HORSE_SKELETON_DEATH("mob.horse.skeleton.death", "entity.skeleton_horse.death", SoundCategories1_8.NEUTRAL),
AMBIENT_WEATHER_RAIN("ambient.weather.rain", "weather.rain.above", SoundCategories1_8.WEATHER),
AMBIENT_WEATHER_RAIN("ambient.weather.rain", "weather.rain", SoundCategories1_8.WEATHER),
PORTAL_TRIGGER("portal.trigger", "block.portal.trigger", SoundCategories1_8.BLOCK),
RANDOM_CHESTOPEN("random.chestopen", "block.chest.open", SoundCategories1_8.BLOCK),
MOB_HORSE_LAND("mob.horse.land", "entity.horse.land", SoundCategories1_8.NEUTRAL),
@@ -110,23 +110,23 @@ public enum SoundEffectMappings1_9 {
NOTE_HAT("note.hat", "block.note.hat", SoundCategories1_8.RECORD),
MOB_ZOMBIE_METAL("mob.zombie.metal", "entity.zombie.attack_iron_door", SoundCategories1_8.HOSTILE),
MOB_VILLAGER_HAGGLE("mob.villager.haggle", "entity.villager.trading", SoundCategories1_8.NEUTRAL),
MOB_GHAST_FIREBALL("mob.ghast.fireball", "entity.blaze.shoot", SoundCategories1_8.HOSTILE),
MOB_GHAST_FIREBALL("mob.ghast.fireball", "entity.ghast.shoot", SoundCategories1_8.HOSTILE),
MOB_IRONGOLEM_DEATH("mob.irongolem.death", "entity.irongolem.death", SoundCategories1_8.NEUTRAL),
RANDOM_BREAK("random.break", "item.shield.break", SoundCategories1_8.PLAYER),
RANDOM_BREAK("random.break", "entity.item.break", SoundCategories1_8.PLAYER),
MOB_ZOMBIE_REMEDY("mob.zombie.remedy", "entity.zombie_villager.cure", SoundCategories1_8.HOSTILE),
RANDOM_BOW("random.bow", "entity.splash_potion.throw", SoundCategories1_8.NEUTRAL),
RANDOM_BOW("random.bow", "entity.arrow.shoot", SoundCategories1_8.NEUTRAL),
MOB_VILLAGER_IDLE("mob.villager.idle", "entity.villager.ambient", SoundCategories1_8.NEUTRAL),
STEP_CLOTH("step.cloth", "block.cloth.fall", SoundCategories1_8.NEUTRAL),
MOB_SILVERFISH_HIT("mob.silverfish.hit", "entity.endermite.hurt", SoundCategories1_8.HOSTILE),
STEP_CLOTH("step.cloth", "block.cloth.step", SoundCategories1_8.NEUTRAL),
MOB_SILVERFISH_HIT("mob.silverfish.hit", "entity.silverfish.hurt", SoundCategories1_8.HOSTILE),
LIQUID_LAVA("liquid.lava", "block.lava.ambient", SoundCategories1_8.BLOCK),
GAME_NEUTRAL_HURT_FALL_BIG("game.neutral.hurt.fall.big", "entity.hostile.big_fall", SoundCategories1_8.NEUTRAL),
FIRE_FIRE("fire.fire", "block.fire.ambient", SoundCategories1_8.BLOCK),
MOB_ZOMBIE_WOOD("mob.zombie.wood", "entity.zombie.attack_door_wood", SoundCategories1_8.HOSTILE),
MOB_CHICKEN_STEP("mob.chicken.step", "entity.chicken.step", SoundCategories1_8.NEUTRAL),
MOB_GUARDIAN_LAND_HIT("mob.guardian.land.hit", "entity.guardian.hurt_land", SoundCategories1_8.HOSTILE),
MOB_CHICKEN_PLOP("mob.chicken.plop", "entity.donkey.chest", SoundCategories1_8.NEUTRAL),
MOB_CHICKEN_PLOP("mob.chicken.plop", "entity.chicken.egg", SoundCategories1_8.NEUTRAL),
MOB_ENDERDRAGON_WINGS("mob.enderdragon.wings", "entity.enderdragon.flap", SoundCategories1_8.HOSTILE),
STEP_GRASS("step.grass", "block.grass.hit", SoundCategories1_8.NEUTRAL),
STEP_GRASS("step.grass", "block.grass.step", SoundCategories1_8.NEUTRAL),
MOB_HORSE_BREATHE("mob.horse.breathe", "entity.horse.breathe", SoundCategories1_8.NEUTRAL),
GAME_PLAYER_HURT_FALL_BIG("game.player.hurt.fall.big", "entity.hostile.big_fall", SoundCategories1_8.PLAYER),
MOB_HORSE_DONKEY_IDLE("mob.horse.donkey.idle", "entity.donkey.ambient", SoundCategories1_8.NEUTRAL),
@@ -145,12 +145,12 @@ public enum SoundEffectMappings1_9 {
RANDOM_ANVIL_LAND("random.anvil_land", "block.anvil.land", SoundCategories1_8.BLOCK),
GAME_HOSTILE_HURT("game.hostile.hurt", "entity.player.death", SoundCategories1_8.HOSTILE),
MINECART_INSIDE("minecart.inside", "entity.minecart.inside", SoundCategories1_8.PLAYER),
MOB_SLIME_BIG("mob.slime.big", "entity.slime.death", SoundCategories1_8.HOSTILE),
MOB_SLIME_BIG("mob.slime.big", "entity.slime.squish", SoundCategories1_8.HOSTILE),
LIQUID_WATER("liquid.water", "block.water.ambient", SoundCategories1_8.BLOCK),
MOB_PIG_SAY("mob.pig.say", "entity.pig.ambient", SoundCategories1_8.NEUTRAL),
MOB_WITHER_SHOOT("mob.wither.shoot", "entity.wither.shoot", SoundCategories1_8.HOSTILE),
ITEM_FIRECHARGE_USE("item.fireCharge.use", "entity.blaze.shoot", SoundCategories1_8.BLOCK),
STEP_SAND("step.sand", "block.sand.fall", SoundCategories1_8.NEUTRAL),
STEP_SAND("step.sand", "block.sand.step", SoundCategories1_8.NEUTRAL),
MOB_IRONGOLEM_HIT("mob.irongolem.hit", "entity.irongolem.hurt", SoundCategories1_8.NEUTRAL),
MOB_HORSE_DEATH("mob.horse.death", "entity.horse.death", SoundCategories1_8.NEUTRAL),
MOB_BAT_HURT("mob.bat.hurt", "entity.bat.hurt", SoundCategories1_8.NEUTRAL),
@@ -159,7 +159,7 @@ public enum SoundEffectMappings1_9 {
MOB_ZOMBIEPIG_ZPIGDEATH("mob.zombiepig.zpigdeath", "entity.zombie_pig.death", SoundCategories1_8.HOSTILE),
AMBIENT_WEATHER_THUNDER("ambient.weather.thunder", "entity.lightning.thunder", SoundCategories1_8.WEATHER),
MINECART_BASE("minecart.base", "entity.minecart.riding", SoundCategories1_8.NEUTRAL),
STEP_LADDER("step.ladder", "block.ladder.hit", SoundCategories1_8.NEUTRAL),
STEP_LADDER("step.ladder", "block.ladder.step", SoundCategories1_8.NEUTRAL),
MOB_HORSE_DONKEY_ANGRY("mob.horse.donkey.angry", "entity.donkey.angry", SoundCategories1_8.NEUTRAL),
AMBIENT_CAVE_CAVE("ambient.cave.cave", "ambient.cave", SoundCategories1_8.AMBIENT),
FIREWORKS_BLAST_FAR("fireworks.blast_far", "entity.firework.blast_far", SoundCategories1_8.AMBIENT),
@@ -169,8 +169,8 @@ public enum SoundEffectMappings1_9 {
GAME_HOSTILE_DIE("game.hostile.die", "entity.player.death", SoundCategories1_8.HOSTILE),
MOB_CAT_HISS("mob.cat.hiss", "entity.cat.hiss", SoundCategories1_8.NEUTRAL),
NOTE_BD("note.bd", "block.note.basedrum", SoundCategories1_8.RECORD),
MOB_SPIDER_SAY("mob.spider.say", "entity.spider.hurt", SoundCategories1_8.HOSTILE),
STEP_STONE("step.stone", "block.anvil.hit", SoundCategories1_8.NEUTRAL, true), //Is used for glass placement sound
MOB_SPIDER_SAY("mob.spider.say", "entity.spider.ambient", SoundCategories1_8.HOSTILE),
STEP_STONE("step.stone", "block.stone.step", SoundCategories1_8.NEUTRAL, true), //Is used for glass placement sound
RANDOM_LEVELUP("random.levelup", "entity.player.levelup", SoundCategories1_8.PLAYER),
LIQUID_LAVAPOP("liquid.lavapop", "block.lava.pop", SoundCategories1_8.BLOCK),
MOB_SHEEP_SAY("mob.sheep.say", "entity.sheep.ambient", SoundCategories1_8.NEUTRAL),
@@ -182,8 +182,8 @@ public enum SoundEffectMappings1_9 {
GAME_HOSTILE_HURT_FALL_SMALL("game.hostile.hurt.fall.small", "entity.generic.small_fall", SoundCategories1_8.HOSTILE),
MOB_HORSE_ZOMBIE_HIT("mob.horse.zombie.hit", "entity.zombie_horse.hurt", SoundCategories1_8.NEUTRAL),
MOB_IRONGOLEM_THROW("mob.irongolem.throw", "entity.irongolem.attack", SoundCategories1_8.NEUTRAL),
DIG_CLOTH("dig.cloth", "block.cloth.place", SoundCategories1_8.BLOCK),
STEP_GRAVEL("step.gravel", "block.gravel.hit", SoundCategories1_8.NEUTRAL),
DIG_CLOTH("dig.cloth", "block.cloth.break", SoundCategories1_8.BLOCK),
STEP_GRAVEL("step.gravel", "block.gravel.step", SoundCategories1_8.NEUTRAL),
MOB_SILVERFISH_SAY("mob.silverfish.say", "entity.silverfish.ambient", SoundCategories1_8.HOSTILE),
MOB_CAT_PURR("mob.cat.purr", "entity.cat.purr", SoundCategories1_8.NEUTRAL),
MOB_ZOMBIE_INFECT("mob.zombie.infect", "entity.zombie.infect", SoundCategories1_8.HOSTILE),
@@ -196,13 +196,13 @@ public enum SoundEffectMappings1_9 {
MOB_ENDERMEN_PORTAL("mob.endermen.portal", "entity.endermen.teleport", SoundCategories1_8.HOSTILE),
MOB_HORSE_ANGRY("mob.horse.angry", "entity.horse.angry", SoundCategories1_8.NEUTRAL),
MOB_WOLF_GROWL("mob.wolf.growl", "entity.wolf.growl", SoundCategories1_8.NEUTRAL),
DIG_SNOW("dig.snow", "block.snow.place", SoundCategories1_8.BLOCK),
DIG_SNOW("dig.snow", "block.snow.break", SoundCategories1_8.BLOCK),
TILE_PISTON_OUT("tile.piston.out", "block.piston.extend", SoundCategories1_8.BLOCK),
RANDOM_BURP("random.burp", "entity.player.burp", SoundCategories1_8.PLAYER),
MOB_COW_STEP("mob.cow.step", "entity.cow.step", SoundCategories1_8.NEUTRAL),
MOB_WITHER_HURT("mob.wither.hurt", "entity.wither.hurt", SoundCategories1_8.HOSTILE),
MOB_GUARDIAN_LAND_DEATH("mob.guardian.land.death", "entity.elder_guardian.death_land", SoundCategories1_8.HOSTILE),
MOB_CHICKEN_HURT("mob.chicken.hurt", "entity.chicken.death", SoundCategories1_8.NEUTRAL),
MOB_CHICKEN_HURT("mob.chicken.hurt", "entity.chicken.hurt", SoundCategories1_8.NEUTRAL),
MOB_WOLF_STEP("mob.wolf.step", "entity.wolf.step", SoundCategories1_8.NEUTRAL),
MOB_WOLF_DEATH("mob.wolf.death", "entity.wolf.death", SoundCategories1_8.NEUTRAL),
MOB_WOLF_WHINE("mob.wolf.whine", "entity.wolf.whine", SoundCategories1_8.NEUTRAL),
@@ -221,7 +221,7 @@ public enum SoundEffectMappings1_9 {
FIRE_IGNITE("fire.ignite", "item.flintandsteel.use", SoundCategories1_8.BLOCK, true),
MOB_ENDERDRAGON_HIT("mob.enderdragon.hit", "entity.enderdragon.hurt", SoundCategories1_8.HOSTILE),
MOB_ZOMBIE_HURT("mob.zombie.hurt", "entity.zombie.hurt", SoundCategories1_8.HOSTILE),
RANDOM_EXPLODE("random.explode", "block.end_gateway.spawn", SoundCategories1_8.BLOCK),
RANDOM_EXPLODE("random.explode", "entity.generic.explode", SoundCategories1_8.BLOCK),
MOB_SLIME_ATTACK("mob.slime.attack", "entity.slime.attack", SoundCategories1_8.HOSTILE),
MOB_MAGMACUBE_JUMP("mob.magmacube.jump", "entity.magmacube.jump", SoundCategories1_8.HOSTILE),
RANDOM_SPLASH("random.splash", "entity.bobber.splash", SoundCategories1_8.PLAYER),
@@ -230,7 +230,7 @@ public enum SoundEffectMappings1_9 {
MOB_GUARDIAN_CURSE("mob.guardian.curse", "entity.elder_guardian.curse", SoundCategories1_8.HOSTILE),
GAME_POTION_SMASH("game.potion.smash", "block.glass.break", SoundCategories1_8.NEUTRAL),
NOTE_BASSATTACK("note.bassattack", "block.note.bass", SoundCategories1_8.RECORD),
GUI_BUTTON_PRESS("gui.button.press", "block.wood_pressureplate.click_on", SoundCategories1_8.MASTER),
GUI_BUTTON_PRESS("gui.button.press", "ui.button.click", SoundCategories1_8.MASTER),
RANDOM_ORB("random.orb", "entity.experience_orb.pickup", SoundCategories1_8.PLAYER),
MOB_ZOMBIE_WOODBREAK("mob.zombie.woodbreak", "entity.zombie.break_door_wood", SoundCategories1_8.HOSTILE),
MOB_HORSE_ARMOR("mob.horse.armor", "entity.horse.armor", SoundCategories1_8.NEUTRAL),
@@ -36,7 +36,7 @@ import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CommandBlockProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CompressionProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.MainHandProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientChunks;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientWorld1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.MovementTracker;
import com.viaversion.viaversion.util.ComponentUtil;
@@ -203,7 +203,7 @@ public class PlayerPacketRewriter1_9 {
// Track player's dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
int dimensionId = wrapper.get(Types.BYTE, 0);
clientWorld.setEnvironment(dimensionId);
});
@@ -295,27 +295,25 @@ public class PlayerPacketRewriter1_9 {
map(Types.UNSIGNED_BYTE); // 2 - GameMode
map(Types.STRING); // 3 - Level Type
// Track player's dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
handler(wrapper -> {
// Client unloads chunks on respawn
wrapper.user().get(ClientChunks.class).getLoadedChunks().clear();
int gamemode = wrapper.get(Types.UNSIGNED_BYTE, 0);
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
tracker.setGameMode(GameMode.getById(gamemode));
});
// Fake permissions to get Commandblocks working
handler(wrapper -> {
CommandBlockProvider provider = Via.getManager().getProviders().get(CommandBlockProvider.class);
// Fake permissions to get Commandblocks working
provider.sendPermission(wrapper.user());
provider.unloadChunks(wrapper.user());
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class);
int gamemode = wrapper.get(Types.UNSIGNED_BYTE, 0);
tracker.setGameMode(GameMode.getById(gamemode));
ClientWorld1_9 clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
int dimensionId = wrapper.get(Types.INT, 0);
// Track player's dimension
if (clientWorld.setEnvironment(dimensionId)) {
tracker.clearEntities();
clientWorld.getLoadedChunks().clear();
provider.unloadChunks(wrapper.user());
}
});
}
});
@@ -496,4 +494,4 @@ public class PlayerPacketRewriter1_9 {
}
});
}
}
}
@@ -45,7 +45,7 @@ import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ServerboundPackets1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.CommandBlockProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.HandItemProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientChunks;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.ClientWorld1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.EntityTracker1_9;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.Key;
@@ -130,11 +130,10 @@ public class WorldPacketRewriter1_9 {
});
protocol.registerClientbound(ClientboundPackets1_8.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
ClientWorld1_9 clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(clientWorld.getEnvironment()));
long chunkHash = ClientChunks.toLong(chunk.getX(), chunk.getZ());
long chunkHash = ClientWorld1_9.toLong(chunk.getX(), chunk.getZ());
// Check if the chunk should be handled as an unload packet
if (chunk.isFullChunk() && chunk.getBitmask() == 0) {
@@ -146,14 +145,14 @@ public class WorldPacketRewriter1_9 {
CommandBlockProvider provider = Via.getManager().getProviders().get(CommandBlockProvider.class);
provider.unloadChunk(wrapper.user(), chunk.getX(), chunk.getZ());
clientChunks.getLoadedChunks().remove(chunkHash);
clientWorld.getLoadedChunks().remove(chunkHash);
// Unload the empty chunks
if (Via.getConfig().isChunkBorderFix()) {
for (BlockFace face : BlockFace.HORIZONTAL) {
int chunkX = chunk.getX() + face.modX();
int chunkZ = chunk.getZ() + face.modZ();
if (!clientChunks.getLoadedChunks().contains(ClientChunks.toLong(chunkX, chunkZ))) {
if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) {
PacketWrapper unloadChunk = wrapper.create(ClientboundPackets1_9.FORGET_LEVEL_CHUNK);
unloadChunk.write(Types.INT, chunkX);
unloadChunk.write(Types.INT, chunkZ);
@@ -165,14 +164,14 @@ public class WorldPacketRewriter1_9 {
Type<Chunk> chunkType = ChunkType1_9_1.forEnvironment(clientWorld.getEnvironment());
wrapper.write(chunkType, chunk);
clientChunks.getLoadedChunks().add(chunkHash);
clientWorld.getLoadedChunks().add(chunkHash);
// Send empty chunks surrounding the loaded chunk to force 1.9+ clients to render the new chunk
if (Via.getConfig().isChunkBorderFix()) {
for (BlockFace face : BlockFace.HORIZONTAL) {
int chunkX = chunk.getX() + face.modX();
int chunkZ = chunk.getZ() + face.modZ();
if (!clientChunks.getLoadedChunks().contains(ClientChunks.toLong(chunkX, chunkZ))) {
if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) {
PacketWrapper emptyChunk = wrapper.create(ClientboundPackets1_9.LEVEL_CHUNK);
Chunk c = new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], new int[256], new ArrayList<>());
emptyChunk.write(chunkType, c);
@@ -185,8 +184,7 @@ public class WorldPacketRewriter1_9 {
protocol.registerClientbound(ClientboundPackets1_8.MAP_BULK_CHUNK, null, wrapper -> {
wrapper.cancel(); // Cancel the packet from being sent
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientChunks clientChunks = wrapper.user().get(ClientChunks.class);
ClientWorld1_9 clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class);
Chunk[] chunks = wrapper.read(BulkChunkType1_8.TYPE);
Type<Chunk> chunkType = ChunkType1_9_1.forEnvironment(clientWorld.getEnvironment());
@@ -196,14 +194,14 @@ public class WorldPacketRewriter1_9 {
chunkData.write(chunkType, chunk);
chunkData.send(Protocol1_8To1_9.class);
clientChunks.getLoadedChunks().add(ClientChunks.toLong(chunk.getX(), chunk.getZ()));
clientWorld.getLoadedChunks().add(ClientWorld1_9.toLong(chunk.getX(), chunk.getZ()));
// Send empty chunks surrounding the loaded chunk to force 1.9+ clients to render the new chunk
if (Via.getConfig().isChunkBorderFix()) {
for (BlockFace face : BlockFace.HORIZONTAL) {
int chunkX = chunk.getX() + face.modX();
int chunkZ = chunk.getZ() + face.modZ();
if (!clientChunks.getLoadedChunks().contains(ClientChunks.toLong(chunkX, chunkZ))) {
if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) {
PacketWrapper emptyChunk = wrapper.create(ClientboundPackets1_9.LEVEL_CHUNK);
Chunk c = new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], new int[256], new ArrayList<>());
emptyChunk.write(chunkType, c);
@@ -18,10 +18,10 @@
package com.viaversion.viaversion.protocols.v1_8to1_9.storage;
import com.google.common.collect.Sets;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import java.util.Set;
public class ClientChunks implements StorableObject {
public class ClientWorld1_9 extends ClientWorld {
private final Set<Long> loadedChunks = Sets.newConcurrentHashSet();
public static long toLong(int msw, int lsw) {
@@ -23,13 +23,13 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.legacy.bossbar.BossBar;
import com.viaversion.viaversion.api.legacy.bossbar.BossColor;
import com.viaversion.viaversion.api.legacy.bossbar.BossStyle;
import com.viaversion.viaversion.api.minecraft.GameMode;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.GameMode;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9.EntityType;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9;
import com.viaversion.viaversion.api.minecraft.item.DataItem;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
@@ -37,6 +37,7 @@ import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.BossBarProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.EntityIdProvider;
import com.viaversion.viaversion.util.ComponentUtil;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@@ -233,7 +234,11 @@ public class EntityTracker1_9 extends EntityTrackerBase {
if (entityData.id() == 2) {
BossBar bar = bossBarMap.get(entityId);
String title = (String) entityData.getValue();
title = title.isEmpty() ? (type == EntityType.ENDER_DRAGON ? DRAGON_TRANSLATABLE : WITHER_TRANSLATABLE) : title;
if (title.isEmpty()) {
title = type == EntityType.ENDER_DRAGON ? DRAGON_TRANSLATABLE : WITHER_TRANSLATABLE;
} else {
title = ComponentUtil.plainToJson(title).toString();
}
if (bar == null) {
bar = Via.getAPI().legacyAPI().createLegacyBossBar(title, BossColor.PINK, BossStyle.SOLID);
bossBarMap.put(entityId, bar);
@@ -87,7 +87,7 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
});
registerClientbound(ClientboundPackets1_9.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_1To1_9_3.class);
Chunk chunk = wrapper.read(ChunkType1_9_1.forEnvironment(clientWorld.getEnvironment()));
wrapper.write(ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()), chunk);
@@ -120,7 +120,7 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_1To1_9_3.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
});
@@ -132,7 +132,7 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
public void register() {
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_1To1_9_3.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
});
@@ -156,8 +156,6 @@ public class Protocol1_9_1To1_9_3 extends AbstractProtocol<ClientboundPackets1_9
@Override
public void init(UserConnection user) {
if (!user.has(ClientWorld.class)) {
user.put(new ClientWorld());
}
user.addClientWorld(this.getClass(), new ClientWorld());
}
}
@@ -153,7 +153,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
map(Types.INT); // 2 - Dimension
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_3To1_10.class);
int dimensionId = wrapper.get(Types.INT, 1);
clientWorld.setEnvironment(dimensionId);
@@ -168,7 +168,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
map(Types.INT); // 0 - Dimension ID
handler(wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_3To1_10.class);
int dimensionId = wrapper.get(Types.INT, 0);
clientWorld.setEnvironment(dimensionId);
@@ -178,7 +178,7 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
// Chunk Data
registerClientbound(ClientboundPackets1_9_3.LEVEL_CHUNK, wrapper -> {
ClientWorld clientWorld = wrapper.user().get(ClientWorld.class);
ClientWorld clientWorld = wrapper.user().getClientWorld(Protocol1_9_3To1_10.class);
Chunk chunk = wrapper.passthrough(ChunkType1_9_3.forEnvironment(clientWorld.getEnvironment()));
if (Via.getConfig().isReplacePistons()) {
@@ -234,11 +234,9 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
@Override
public void init(UserConnection userConnection) {
userConnection.put(new ResourcePackTracker());
userConnection.addClientWorld(this.getClass(), new ClientWorld());
if (!userConnection.has(ClientWorld.class)) {
userConnection.put(new ClientWorld());
}
userConnection.put(new ResourcePackTracker());
}
@Override
@@ -39,6 +39,7 @@ import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.util.ComponentUtil;
import com.viaversion.viaversion.util.SerializerVersion;
import com.viaversion.viaversion.util.TagUtil;
import java.util.BitSet;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
@@ -139,6 +140,43 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
});
}
public void registerPlayerInfoUpdate1_20_3(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM);
if (!actions.get(5)) { // Update display name
return;
}
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID);
if (actions.get(0)) {
wrapper.passthrough(Types.STRING); // Player Name
final int properties = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Types.STRING); // Name
wrapper.passthrough(Types.STRING); // Value
wrapper.passthrough(Types.OPTIONAL_STRING); // Signature
}
}
if (actions.get(1) && wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.UUID); // Session UUID
wrapper.passthrough(Types.PROFILE_KEY);
}
if (actions.get(2)) {
wrapper.passthrough(Types.VAR_INT); // Gamemode
}
if (actions.get(3)) {
wrapper.passthrough(Types.BOOLEAN); // Listed
}
if (actions.get(4)) {
wrapper.passthrough(Types.VAR_INT); // Latency
}
processTag(wrapper.user(), wrapper.passthrough(Types.OPTIONAL_TAG));
}
});
}
public void registerPlayerCombatKill(final C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
@@ -322,6 +360,10 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
handleShowItem(connection, contentsTag, componentsTag);
if (componentsTag != null) {
handleContainerContents(connection, componentsTag);
if (inputSerializerVersion() != null) {
handleWrittenBookContents(connection, componentsTag);
}
handleItemArrayContents(connection, componentsTag, "bundle_contents");
handleItemArrayContents(connection, componentsTag, "charged_projectiles");
}
@@ -348,6 +390,40 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
}
}
protected void handleWrittenBookContents(final UserConnection connection, final CompoundTag tag) {
final CompoundTag book = TagUtil.getNamespacedCompoundTag(tag, "minecraft:written_book_content");
if (book == null) {
return;
}
final ListTag<CompoundTag> pagesTag = book.getListTag("pages", CompoundTag.class);
if (pagesTag == null) {
return;
}
for (final CompoundTag compoundTag : pagesTag) {
final StringTag raw = compoundTag.getStringTag("raw");
processJsonString(connection, raw);
final StringTag filtered = compoundTag.getStringTag("filtered");
processJsonString(connection, filtered);
}
}
private void processJsonString(final UserConnection connection, final StringTag tag) {
if (tag == null) {
return;
}
final var input = inputSerializerVersion();
final var output = outputSerializerVersion();
final Tag asTag = input.toTag(input.toComponent(tag.getValue()));
processTag(connection, asTag);
tag.setValue(output.toString(output.toComponent(asTag)));
}
protected void handleItemArrayContents(final UserConnection connection, final CompoundTag tag, final String key) {
final ListTag<CompoundTag> container = TagUtil.getNamespacedCompoundTagList(tag, key);
if (container == null) {
Loaded 100 of 118 files, more files were not shown because too many files have changed in this diff. Show more