mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2026-11-04 08:52:10 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a3ef1e0b7 | ||
|
|
5be41ed3e9 | ||
|
|
83e44641d0 | ||
|
|
50084c112d | ||
|
|
81682f4921 | ||
|
|
1c339e8b54 | ||
|
|
1a9cda0579 | ||
|
|
6ad9a71907 | ||
|
|
9f24576ba7 | ||
|
|
8661bbc1fc | ||
|
|
0b5fa37f96 | ||
|
|
dab32bafa1 | ||
|
|
9e5c541f79 | ||
|
|
9674c617ca | ||
|
|
9df1704357 | ||
|
|
c0821de2e2 | ||
|
|
c358c39027 | ||
|
|
451b3a2637 | ||
|
|
619eecacf8 | ||
|
|
6bae039d52 | ||
|
|
b321029886 | ||
|
|
5287d4fb4f | ||
|
|
a0a2794291 | ||
|
|
9e354e956e | ||
|
|
27033e9096 | ||
|
|
e436bbe375 | ||
|
|
050a1dbacb | ||
|
|
ae1838d78a | ||
|
|
7235485802 | ||
|
|
fcb472347e | ||
|
|
e0ce8cc715 | ||
|
|
ebc0e61be8 | ||
|
|
95581a6fa5 | ||
|
|
d0b49009e5 | ||
|
|
369b076cad | ||
|
|
6555bcda74 | ||
|
|
e537dbb024 | ||
|
|
f92dbb655d | ||
|
|
0b2dac9056 | ||
|
|
7cd5514b90 | ||
|
|
5017d4bbb3 | ||
|
|
32e51b52aa | ||
|
|
4f66fd793b | ||
|
|
2a71612aea | ||
|
|
a993a08b8d | ||
|
|
a9c947517c | ||
|
|
2841bf3040 | ||
|
|
7edddda36e | ||
|
|
33de12ceb1 | ||
|
|
f8eb57cdbb | ||
|
|
b2d523f5c0 | ||
|
|
b586b0d361 | ||
|
|
c6381e7f4d | ||
|
|
10ee7e1930 | ||
|
|
78abf8be00 | ||
|
|
1dde24bb68 | ||
|
|
bc57512ca2 | ||
|
|
6ad3beca76 | ||
|
|
9d75125e41 | ||
|
|
8ce4112e86 | ||
|
|
7d542d5667 | ||
|
|
7d6599b90e | ||
|
|
1b03e24160 | ||
|
|
fcd91bb855 | ||
|
|
bda4ea9fd0 | ||
|
|
cbd26ce9d9 | ||
|
|
8d53f4aa5a | ||
|
|
1438f1f68d | ||
|
|
61fcf6f895 | ||
|
|
736834441d | ||
|
|
3f5417be97 | ||
|
|
cc1c88001f | ||
|
|
274f98c24e | ||
|
|
f39b466ac0 | ||
|
|
aa22ca1d56 | ||
|
|
802e868b2e | ||
|
|
02442a9775 | ||
|
|
5349de91c5 | ||
|
|
a8ef3c890a | ||
|
|
b556e6528a | ||
|
|
434b32cad8 | ||
|
|
60b3ba6bb7 | ||
|
|
864beef341 | ||
|
|
7b21df2c12 | ||
|
|
462a10363c | ||
|
|
040f85659d | ||
|
|
48d5aaf8fa | ||
|
|
41b0d95d70 | ||
|
|
b599399c48 | ||
|
|
721e27eb39 | ||
|
|
c9d6fbfcd0 | ||
|
|
b1f64fd081 | ||
|
|
2b508567db | ||
|
|
24d0ae7607 | ||
|
|
40a44d5dc5 | ||
|
|
b5a06181d4 | ||
|
|
35fa7e78a0 | ||
|
|
7f4faab4ab | ||
|
|
3906b47654 | ||
|
|
1476adb281 | ||
|
|
6fb072120b | ||
|
|
f2f0be0581 | ||
|
|
5ec30ef18a | ||
|
|
0915afe43b | ||
|
|
87b041bf3a | ||
|
|
275b09bdbb | ||
|
|
cc87c02020 | ||
|
|
a45985ed58 | ||
|
|
92dedfb950 | ||
|
|
6bbcf7d784 | ||
|
|
465a2354c0 | ||
|
|
c59c15d6f3 | ||
|
|
20f7738f08 | ||
|
|
323f0fa087 | ||
|
|
3138d667a6 | ||
|
|
365040f59d | ||
|
|
303d9ecf51 | ||
|
|
463381b84e | ||
|
|
7fef96d77e | ||
|
|
17358120cd | ||
|
|
e6da77cf47 | ||
|
|
dc503cd613 | ||
|
|
8aa2f4be46 | ||
|
|
c5dc5b2bf8 | ||
|
|
f4d6659760 | ||
|
|
bfbb80f708 | ||
|
|
248da118a9 | ||
|
|
a987882132 | ||
|
|
bca25d4744 | ||
|
|
2417ffe483 | ||
|
|
8606e5d663 | ||
|
|
5a0ca55b97 | ||
|
|
ceb1cffb00 | ||
|
|
1ff3035bc0 | ||
|
|
1f221ea828 | ||
|
|
dd1fad2dd7 | ||
|
|
245f7e24e4 | ||
|
|
9d3db4cf97 | ||
|
|
b67ebecce8 | ||
|
|
d03207289e | ||
|
|
64497b305a | ||
|
|
f5b3799db9 | ||
|
|
00fedc7656 | ||
|
|
05aa05c5b4 | ||
|
|
5243c1800e | ||
|
|
77d702bc9b | ||
|
|
c098e24c4f | ||
|
|
3d083cf463 | ||
|
|
2ab62a8f4f | ||
|
|
296f42086f | ||
|
|
e9f547f7ba | ||
|
|
b7f388b9ee | ||
|
|
824ff375d4 | ||
|
|
8bec05ed38 | ||
|
|
b367caa4b2 | ||
|
|
1c281abf65 |
No files matched your search
+2
-2
@@ -2,7 +2,7 @@
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
insert_final_newline = true
|
||||
tab_width = 4
|
||||
|
||||
[*.java]
|
||||
@@ -13,4 +13,4 @@ ij_java_generate_final_locals = true
|
||||
ij_java_generate_final_parameters = true
|
||||
|
||||
[{*.json,*.yml}]
|
||||
indent_size = 2
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -7,13 +7,13 @@ jobs:
|
||||
# Only run on PRs if the source branch is on a different repo. We do not need to run everything twice.
|
||||
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v3
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
@@ -8,12 +8,12 @@ on:
|
||||
jobs:
|
||||
publish:
|
||||
if: github.repository_owner == 'ViaVersion'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v3
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
|
||||
@@ -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
|
||||
@@ -1,7 +1,7 @@
|
||||
# ViaVersion
|
||||
|
||||
[](https://viaversion.com)
|
||||
[](https://github.com/ViaVersion/ViaVersion/actions)
|
||||
[](https://github.com/ViaVersion/ViaVersion/actions)
|
||||
[](https://viaversion.com/discord)
|
||||
|
||||
**Allows the connection of higher client versions to lower server versions -
|
||||
@@ -9,11 +9,14 @@ 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 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:
|
||||
|
||||

|
||||

|
||||
|
||||
**User Docs:** https://docs.viaversion.com/display/VIAVERSION/
|
||||
|
||||
@@ -67,6 +70,8 @@ dependencies {
|
||||
If you need access to the existing protocol or platform implementations, use the parent artifact `viaversion`.
|
||||
Please note the [differences in licensing](#license).
|
||||
|
||||
Note: If you want to make your own platform implementation of ViaVersion (and additional addons),
|
||||
you can use the [ViaLoader](https://github.com/ViaVersion/ViaLoader) project.
|
||||
|
||||
Building
|
||||
--------
|
||||
@@ -78,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
|
||||
@@ -91,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.
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ dependencies {
|
||||
exclude("com.google.code.gson", "gson")
|
||||
exclude("com.viaversion", "nbt")
|
||||
}
|
||||
api(libs.snakeYaml)
|
||||
|
||||
compileOnlyApi(libs.snakeYaml)
|
||||
compileOnlyApi(libs.netty)
|
||||
compileOnlyApi(libs.guava)
|
||||
compileOnlyApi(libs.checkerQual)
|
||||
|
||||
@@ -140,6 +140,13 @@ public interface ViaManager {
|
||||
*/
|
||||
void addEnableListener(Runnable runnable);
|
||||
|
||||
/**
|
||||
* Adds a runnable to be executed when ViaVersion has finished its init after the full server load.
|
||||
*
|
||||
* @param runnable runnable to be executed
|
||||
*/
|
||||
void addPostEnableListener(Runnable runnable);
|
||||
|
||||
/**
|
||||
* Returns whether the manager has been initialized (and protocols have been loaded).
|
||||
*
|
||||
|
||||
+23
-9
@@ -67,9 +67,9 @@ public interface ViaVersionConfig extends Config {
|
||||
boolean isShowNewDeathMessages();
|
||||
|
||||
/**
|
||||
* Get if metadata errors will be suppressed
|
||||
* Get if entity data errors will be suppressed
|
||||
*
|
||||
* @return true if metadata errors suppression is enabled
|
||||
* @return true if entity data errors suppression is enabled
|
||||
*/
|
||||
boolean isSuppressMetadataErrors();
|
||||
|
||||
@@ -292,13 +292,6 @@ public interface ViaVersionConfig extends Config {
|
||||
*/
|
||||
boolean isDisable1_13AutoComplete();
|
||||
|
||||
/**
|
||||
* Tries to minimize cooldown animation.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isMinimizeCooldown();
|
||||
|
||||
/**
|
||||
* Enable the serverside blockconnections for 1.13+ clients
|
||||
*
|
||||
@@ -464,4 +457,25 @@ public interface ViaVersionConfig extends Config {
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean handleInvalidItemCount();
|
||||
|
||||
/**
|
||||
* Tries to cancel block break/place sounds sent by 1.8 servers to 1.9+ clients to prevent them from playing twice
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
|
||||
@@ -46,6 +46,7 @@ public class MappingDataBase implements MappingData {
|
||||
protected ParticleMappings particleMappings;
|
||||
protected BiMappings itemMappings;
|
||||
protected BiMappings blockMappings;
|
||||
protected BiMappings attributeMappings;
|
||||
protected Mappings blockStateMappings;
|
||||
protected Mappings blockEntityMappings;
|
||||
protected Mappings soundMappings;
|
||||
@@ -53,7 +54,6 @@ public class MappingDataBase implements MappingData {
|
||||
protected Mappings enchantmentMappings;
|
||||
protected Mappings paintingMappings;
|
||||
protected Mappings menuMappings;
|
||||
protected Mappings attributeMappings;
|
||||
protected Map<RegistryType, List<TagData>> tags;
|
||||
|
||||
public MappingDataBase(final String unmappedVersion, final String mappedVersion) {
|
||||
@@ -76,7 +76,7 @@ public class MappingDataBase implements MappingData {
|
||||
menuMappings = loadMappings(data, "menus");
|
||||
enchantmentMappings = loadMappings(data, "enchantments");
|
||||
paintingMappings = loadMappings(data, "paintings");
|
||||
attributeMappings = loadMappings(data, "attributes");
|
||||
attributeMappings = loadBiMappings(data, "attributes");
|
||||
|
||||
|
||||
final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt");
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.minecraft;
|
||||
|
||||
public enum GameMode {
|
||||
|
||||
NOT_SET(""),
|
||||
SURVIVAL("Survival Mode"),
|
||||
CREATIVE("Creative Mode"),
|
||||
ADVENTURE("Adventure Mode"),
|
||||
@@ -41,11 +42,11 @@ public enum GameMode {
|
||||
|
||||
public static GameMode getById(int id) {
|
||||
return switch (id) {
|
||||
case 0 -> SURVIVAL;
|
||||
case -1 -> NOT_SET;
|
||||
case 1 -> CREATIVE;
|
||||
case 2 -> ADVENTURE;
|
||||
case 3 -> SPECTATOR;
|
||||
default -> throw new IllegalArgumentException("Unknown gamemode id: " + id);
|
||||
default /*0*/ -> SURVIVAL;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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{" +
|
||||
|
||||
@@ -25,6 +25,12 @@ package com.viaversion.viaversion.api.minecraft;
|
||||
import com.viaversion.nbt.tag.Tag;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an entry in a registry.
|
||||
*
|
||||
* @param key key of the registry entry
|
||||
* @param tag data of the registry entry, or null if the client should use its default
|
||||
*/
|
||||
public record RegistryEntry(String key, @Nullable Tag tag) {
|
||||
|
||||
public RegistryEntry withKey(final String key) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
+129
-72
@@ -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.
|
||||
*
|
||||
@@ -212,6 +267,8 @@ public final class StructuredDataContainer {
|
||||
public String toString() {
|
||||
return "StructuredDataContainer{" +
|
||||
"data=" + data +
|
||||
", lookup=" + lookup +
|
||||
", mappedNames=" + mappedNames +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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),
|
||||
|
||||
+5
-4
@@ -51,11 +51,12 @@ public enum EntityTypes1_14 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+5
-4
@@ -51,11 +51,12 @@ public enum EntityTypes1_15 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+6
-5
@@ -51,11 +51,12 @@ public enum EntityTypes1_16 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+6
-5
@@ -51,11 +51,12 @@ public enum EntityTypes1_16_2 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+6
-5
@@ -53,11 +53,12 @@ public enum EntityTypes1_17 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+6
-5
@@ -53,11 +53,12 @@ public enum EntityTypes1_19 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+6
-5
@@ -53,11 +53,12 @@ public enum EntityTypes1_19_3 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+6
-5
@@ -59,11 +59,12 @@ public enum EntityTypes1_19_4 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+6
-5
@@ -59,11 +59,12 @@ public enum EntityTypes1_20_3 implements EntityType {
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+7
-6
@@ -59,12 +59,13 @@ public enum EntityTypes1_20_5 implements EntityType {
|
||||
GLOW_ITEM_FRAME(ITEM_FRAME),
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE(ENTITY, null), // Not actually its own abstract type, but useful for categorizing
|
||||
SNOWBALL(PROJECTILE),
|
||||
ENDER_PEARL(PROJECTILE),
|
||||
EGG(PROJECTILE),
|
||||
POTION(PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(PROJECTILE),
|
||||
PROJECTILE(ENTITY, null),
|
||||
ITEM_PROJECTILE(PROJECTILE, null),
|
||||
SNOWBALL(ITEM_PROJECTILE),
|
||||
ENDER_PEARL(ITEM_PROJECTILE),
|
||||
EGG(ITEM_PROJECTILE),
|
||||
POTION(ITEM_PROJECTILE),
|
||||
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
|
||||
FIREWORK_ROCKET(PROJECTILE),
|
||||
LLAMA_SPIT(PROJECTILE),
|
||||
SHULKER_BULLET(PROJECTILE),
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ public class EntityTypes1_8 {
|
||||
|
||||
LIVING_ENTITY_BASE(ENTITY),
|
||||
ARMOR_STAND(30, LIVING_ENTITY_BASE),
|
||||
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking and metadata indexing
|
||||
PLAYER(LIVING_ENTITY_BASE), // Needed for entity (un)tracking and entity data indexing
|
||||
|
||||
// Living entities as a larger subclass
|
||||
LIVING_ENTITY(48, LIVING_ENTITY_BASE),
|
||||
|
||||
+1
-1
@@ -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),
|
||||
|
||||
+36
-36
@@ -28,21 +28,21 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public final class EntityData {
|
||||
private int id;
|
||||
private EntityDataType metaType;
|
||||
private EntityDataType dataType;
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Creates a new metadata instance.
|
||||
* Creates a new entity data instance.
|
||||
*
|
||||
* @param id metadata index
|
||||
* @param metaType metadata type
|
||||
* @param id data index
|
||||
* @param dataType data type
|
||||
* @param value value if present
|
||||
* @throws IllegalArgumentException if the value and metaType are incompatible
|
||||
* @throws IllegalArgumentException if the value and dataType are incompatible
|
||||
*/
|
||||
public EntityData(int id, EntityDataType metaType, @Nullable Object value) {
|
||||
public EntityData(int id, EntityDataType dataType, @Nullable Object value) {
|
||||
this.id = id;
|
||||
this.metaType = metaType;
|
||||
this.value = checkValue(metaType, value);
|
||||
this.dataType = dataType;
|
||||
this.value = checkValue(dataType, value);
|
||||
}
|
||||
|
||||
public int id() {
|
||||
@@ -54,19 +54,19 @@ public final class EntityData {
|
||||
}
|
||||
|
||||
public EntityDataType dataType() {
|
||||
return metaType;
|
||||
return dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the metadata type if compatible with the current value.
|
||||
* Sets the entity data type if compatible with the current value.
|
||||
*
|
||||
* @param metaType metadata type
|
||||
* @throws IllegalArgumentException if the metadata type and current value are incompatible
|
||||
* @param dataType entity data type
|
||||
* @throws IllegalArgumentException if the entity data type and current value are incompatible
|
||||
* @see #setTypeAndValue(EntityDataType, Object)
|
||||
*/
|
||||
public void setDataType(EntityDataType metaType) {
|
||||
checkValue(metaType, this.value);
|
||||
this.metaType = metaType;
|
||||
public void setDataType(EntityDataType dataType) {
|
||||
checkValue(dataType, this.value);
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
||||
public @Nullable <T> T value() {
|
||||
@@ -78,32 +78,32 @@ public final class EntityData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the metadata value if compatible with the current meta type.
|
||||
* Sets the entity data value if compatible with the current data type.
|
||||
*
|
||||
* @param value value
|
||||
* @throws IllegalArgumentException if the value and current metaType are incompatible
|
||||
* @throws IllegalArgumentException if the value and current dataType are incompatible
|
||||
* @see #setTypeAndValue(EntityDataType, Object)
|
||||
*/
|
||||
public void setValue(@Nullable Object value) {
|
||||
this.value = checkValue(this.metaType, value);
|
||||
this.value = checkValue(this.dataType, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets metadata type and value.
|
||||
* Sets entity data type and value.
|
||||
*
|
||||
* @param metaType metadata type
|
||||
* @param dataType entity data type
|
||||
* @param value value
|
||||
* @throws IllegalArgumentException if the value and metaType are incompatible
|
||||
* @throws IllegalArgumentException if the value and dataType are incompatible
|
||||
*/
|
||||
public void setTypeAndValue(EntityDataType metaType, @Nullable Object value) {
|
||||
this.value = checkValue(metaType, value);
|
||||
this.metaType = metaType;
|
||||
public void setTypeAndValue(EntityDataType dataType, @Nullable Object value) {
|
||||
this.value = checkValue(dataType, value);
|
||||
this.dataType = dataType;
|
||||
}
|
||||
|
||||
private Object checkValue(EntityDataType metaType, @Nullable Object value) {
|
||||
Preconditions.checkNotNull(metaType);
|
||||
if (value != null && !metaType.type().getOutputClass().isAssignableFrom(value.getClass())) {
|
||||
throw new IllegalArgumentException("Metadata value and metaType are incompatible. Type=" + metaType
|
||||
private Object checkValue(EntityDataType dataType, @Nullable Object value) {
|
||||
Preconditions.checkNotNull(dataType);
|
||||
if (value != null && !dataType.type().getOutputClass().isAssignableFrom(value.getClass())) {
|
||||
throw new IllegalArgumentException("Entity data value and dataType are incompatible. Type=" + dataType
|
||||
+ ", value=" + value + " (" + value.getClass().getSimpleName() + ")");
|
||||
}
|
||||
return value;
|
||||
@@ -111,32 +111,32 @@ public final class EntityData {
|
||||
|
||||
@Deprecated
|
||||
public void setDataTypeUnsafe(EntityDataType type) {
|
||||
this.metaType = type;
|
||||
this.dataType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
EntityData metadata = (EntityData) o;
|
||||
if (id != metadata.id) return false;
|
||||
if (metaType != metadata.metaType) return false;
|
||||
return Objects.equals(value, metadata.value);
|
||||
EntityData entityData = (EntityData) o;
|
||||
if (id != entityData.id) return false;
|
||||
if (dataType != entityData.dataType) return false;
|
||||
return Objects.equals(value, entityData.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id;
|
||||
result = 31 * result + metaType.hashCode();
|
||||
result = 31 * result + dataType.hashCode();
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Metadata{" +
|
||||
return "EntityData{" +
|
||||
"id=" + id +
|
||||
", metaType=" + metaType +
|
||||
", dataType=" + dataType +
|
||||
", value=" + value +
|
||||
'}';
|
||||
}
|
||||
|
||||
+5
-5
@@ -35,7 +35,7 @@ public interface EntityDataType {
|
||||
Type type();
|
||||
|
||||
/**
|
||||
* Get type id from the specific MetaDataType
|
||||
* Get type id from the specific EntityDataType
|
||||
*
|
||||
* @return Type id as an integer
|
||||
*/
|
||||
@@ -67,7 +67,7 @@ public interface EntityDataType {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityDataType{" +
|
||||
return "EntityDataTypeImpl{" +
|
||||
"typeId=" + typeId +
|
||||
", type=" + type +
|
||||
'}';
|
||||
@@ -77,9 +77,9 @@ public interface EntityDataType {
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final EntityDataTypeImpl metaType = (EntityDataTypeImpl) o;
|
||||
if (typeId != metaType.typeId) return false;
|
||||
return type.equals(metaType.type);
|
||||
final EntityDataTypeImpl dataType = (EntityDataTypeImpl) o;
|
||||
if (typeId != dataType.typeId) return false;
|
||||
return type.equals(dataType.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -44,8 +44,8 @@ public abstract class AbstractEntityDataTypes implements EntityDataTypes {
|
||||
}
|
||||
|
||||
protected EntityDataType add(final int typeId, final Type<?> type) {
|
||||
final EntityDataType metaType = EntityDataType.create(typeId, type);
|
||||
values[typeId] = metaType;
|
||||
return metaType;
|
||||
final EntityDataType dataType = EntityDataType.create(typeId, type);
|
||||
values[typeId] = dataType;
|
||||
return dataType;
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -27,18 +27,18 @@ import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
|
||||
public interface EntityDataTypes {
|
||||
|
||||
/**
|
||||
* Returns the meta type by the given id.
|
||||
* Returns the data type by the given id.
|
||||
*
|
||||
* @param id type id
|
||||
* @return meta type by id
|
||||
* @return data type by id
|
||||
* @throws IndexOutOfBoundsException if id is out of bounds
|
||||
*/
|
||||
EntityDataType byId(int id);
|
||||
|
||||
/**
|
||||
* Returns an array of meta types.
|
||||
* Returns an array of data types.
|
||||
*
|
||||
* @return array of meta types
|
||||
* @return array of data types
|
||||
*/
|
||||
EntityDataType[] values();
|
||||
}
|
||||
@@ -124,11 +124,11 @@ public class DataItem implements Item {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Item{" +
|
||||
return "DataItem{" +
|
||||
"identifier=" + identifier +
|
||||
", amount=" + amount +
|
||||
", data=" + data +
|
||||
", tag=" + tag +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,8 +46,8 @@ public class StructuredItem implements Item {
|
||||
return new StructuredItem(0, 0);
|
||||
}
|
||||
|
||||
public static StructuredItem[] emptyArray(final int size) {
|
||||
final StructuredItem[] items = new StructuredItem[size];
|
||||
public static Item[] emptyArray(final int size) {
|
||||
final Item[] items = new Item[size];
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
items[i] = empty();
|
||||
}
|
||||
|
||||
+10
@@ -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);
|
||||
}
|
||||
}
|
||||
+20
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-56
@@ -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());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -215,4 +215,13 @@ public interface ViaPlatform<T> {
|
||||
* @return whether the platform has a plugin/mod with the given name
|
||||
*/
|
||||
boolean hasPlugin(String name);
|
||||
|
||||
/**
|
||||
* Returns whether the platform might be reloading.
|
||||
*
|
||||
* @return whether the platform might be reloading
|
||||
*/
|
||||
default boolean couldBeReloading() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -30,4 +30,9 @@ public interface ViaServerProxyPlatform<T> extends ViaPlatform<T> {
|
||||
* @return protocol detector service
|
||||
*/
|
||||
ProtocolDetectorService protocolDetectorService();
|
||||
|
||||
@Override
|
||||
default boolean couldBeReloading() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
+3
-3
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+4
-1
@@ -104,7 +104,10 @@ public class ProtocolVersionRange {
|
||||
*/
|
||||
public boolean contains(final ProtocolVersion version) {
|
||||
if (this.ranges == null) return true;
|
||||
return this.ranges.stream().anyMatch(range -> range.contains(version));
|
||||
for (Range<ProtocolVersion> range : this.ranges) {
|
||||
if (range.contains(version)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,31 @@ import com.viaversion.viaversion.api.platform.providers.Provider;
|
||||
@FunctionalInterface
|
||||
public interface VersionProvider extends Provider {
|
||||
|
||||
/**
|
||||
* Optionally allows platforms to specify the client version of a user. This is needed when the platform supports
|
||||
* connecting other version types then {@link VersionType#RELEASE} to the server.
|
||||
*
|
||||
* @param connection connection
|
||||
* @return client protocol version, or null if handshake packet should be used
|
||||
*/
|
||||
default ProtocolVersion getClientProtocol(UserConnection connection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #getClosestServerProtocol(UserConnection)} and catches any exceptions by returning null.
|
||||
*
|
||||
* @param connection connection
|
||||
* @return closest server protocol version to the user's protocol version
|
||||
*/
|
||||
default ProtocolVersion getServerProtocol(UserConnection connection) {
|
||||
try {
|
||||
return getClosestServerProtocol(connection);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest server protocol version to the user's protocol version.
|
||||
* On non-proxy servers, this returns the actual server version.
|
||||
|
||||
@@ -59,13 +59,13 @@ public interface EntityRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter
|
||||
int newEntityId(int id);
|
||||
|
||||
/**
|
||||
* Handles and transforms metadata of an entity.
|
||||
* Handles and transforms entity data of an entity.
|
||||
*
|
||||
* @param entityId entity id
|
||||
* @param metadataList full, mutable list of metadata
|
||||
* @param dataList full, mutable list of entity data
|
||||
* @param connection user connection
|
||||
*/
|
||||
void handleEntityData(int entityId, List<EntityData> metadataList, UserConnection connection);
|
||||
void handleEntityData(int entityId, List<EntityData> dataList, UserConnection connection);
|
||||
|
||||
/**
|
||||
* Returns the entity tracker for the current protocol.
|
||||
|
||||
@@ -44,7 +44,9 @@ public class ComponentType extends Type<JsonElement> {
|
||||
try {
|
||||
return JsonParser.parseString(s);
|
||||
} catch (JsonSyntaxException e) {
|
||||
Via.getPlatform().getLogger().severe("Error when trying to parse json: " + s);
|
||||
if (Via.getManager().isDebug()) {
|
||||
Via.getPlatform().getLogger().severe("Error when trying to parse json: " + s);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -40,20 +40,20 @@ public final class EntityDataListType extends EntityDataListTypeTemplate {
|
||||
@Override
|
||||
public List<EntityData> read(final ByteBuf buffer) {
|
||||
final List<EntityData> list = new ArrayList<>();
|
||||
EntityData meta;
|
||||
EntityData data;
|
||||
do {
|
||||
meta = this.type.read(buffer);
|
||||
if (meta != null) {
|
||||
list.add(meta);
|
||||
data = this.type.read(buffer);
|
||||
if (data != null) {
|
||||
list.add(data);
|
||||
}
|
||||
} while (meta != null);
|
||||
} while (data != null);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final ByteBuf buffer, final List<EntityData> object) {
|
||||
for (final EntityData metadata : object) {
|
||||
this.type.write(buffer, metadata);
|
||||
for (final EntityData data : object) {
|
||||
this.type.write(buffer, data);
|
||||
}
|
||||
this.type.write(buffer, null);
|
||||
}
|
||||
|
||||
+4
-4
@@ -26,14 +26,14 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes;
|
||||
|
||||
public final class EntityDataType extends ModernEntityDataType {
|
||||
|
||||
private final EntityDataTypes metaTypes;
|
||||
private final EntityDataTypes dataTypes;
|
||||
|
||||
public EntityDataType(final EntityDataTypes metaTypes) {
|
||||
this.metaTypes = metaTypes;
|
||||
public EntityDataType(final EntityDataTypes dataTypes) {
|
||||
this.dataTypes = dataTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType getType(final int index) {
|
||||
return metaTypes.byId(index);
|
||||
return dataTypes.byId(index);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -33,7 +33,7 @@ public abstract class ModernEntityDataType extends EntityDataTypeTemplate {
|
||||
@Override
|
||||
public EntityData read(final ByteBuf buffer) {
|
||||
final short index = buffer.readUnsignedByte();
|
||||
if (index == END) return null; // End of metadata
|
||||
if (index == END) return null; // End of data
|
||||
final EntityDataType type = this.getType(Types.VAR_INT.readPrimitive(buffer));
|
||||
return new EntityData(index, type, type.type().read(buffer));
|
||||
}
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ public abstract class OldEntityDataType extends EntityDataTypeTemplate {
|
||||
@Override
|
||||
public EntityData read(final ByteBuf buffer) {
|
||||
final byte index = buffer.readByte();
|
||||
if (index == END) return null; // End of metadata
|
||||
if (index == END) return null; // End of data
|
||||
final EntityDataType type = this.getType((index & 224) >> 5);
|
||||
return new EntityData(index & 31, type, type.type().read(buffer));
|
||||
}
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class StructuredDataType extends Type<StructuredData<?>> {
|
||||
public StructuredData<?> read(final ByteBuf buffer) {
|
||||
Preconditions.checkNotNull(types, "StructuredDataType has not been initialized");
|
||||
final int id = Types.VAR_INT.readPrimitive(buffer);
|
||||
final StructuredDataKey<?> key = this.types[id];
|
||||
final StructuredDataKey<?> key = key(id);
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("No data component serializer found for id " + id);
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ import java.util.List;
|
||||
public final class Types1_12 {
|
||||
|
||||
/**
|
||||
* Metadata type for 1.12
|
||||
* Entity data type for 1.12
|
||||
*/
|
||||
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_12();
|
||||
/**
|
||||
* Metadata list type for 1.12
|
||||
* Entity data list type for 1.12
|
||||
*/
|
||||
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
|
||||
}
|
||||
@@ -33,11 +33,11 @@ import java.util.List;
|
||||
public final class Types1_8 {
|
||||
|
||||
/**
|
||||
* Metadata type for 1.8
|
||||
* Entity data type for 1.8
|
||||
*/
|
||||
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_8();
|
||||
/**
|
||||
* Metadata list type for 1.8
|
||||
* Entity data list type for 1.8
|
||||
*/
|
||||
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
|
||||
|
||||
|
||||
@@ -32,11 +32,11 @@ import java.util.List;
|
||||
|
||||
public final class Types1_9 {
|
||||
/**
|
||||
* Metadata type for 1.9
|
||||
* Entity data type for 1.9
|
||||
*/
|
||||
public static final Type<EntityData> ENTITY_DATA = new EntityDataType1_9();
|
||||
/**
|
||||
* Metadata list type for 1.9
|
||||
* Entity data list type for 1.9
|
||||
*/
|
||||
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
@@ -45,6 +45,7 @@ fun ShadowJar.configureRelocations() {
|
||||
relocate("com.google.gson", "com.viaversion.viaversion.libs.gson")
|
||||
relocate("it.unimi.dsi.fastutil", "com.viaversion.viaversion.libs.fastutil")
|
||||
relocate("net.lenni0451.mcstructs", "com.viaversion.viaversion.libs.mcstructs")
|
||||
relocate("org.yaml.snakeyaml", "com.viaversion.viaversion.libs.snakeyaml")
|
||||
}
|
||||
|
||||
fun ShadowJar.configureExcludes() {
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ plugins {
|
||||
allprojects {
|
||||
group = "com.viaversion"
|
||||
version = property("projectVersion") as String // from gradle.properties
|
||||
description = "Allow newer clients to join older server versions."
|
||||
description = "Allows the connection of newer clients to older server versions for Minecraft servers."
|
||||
}
|
||||
|
||||
val main = setOf(
|
||||
|
||||
+2
-2
@@ -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.bukkit.listeners.protocol1_9to1_8;
|
||||
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
@@ -117,4 +117,4 @@ public class ArmorListener extends ViaBukkitListener {
|
||||
if (!isOnPipe(player)) return; // Don't start a task if the player is not on the pipe
|
||||
Via.getPlatform().runSync(() -> sendArmorUpdate(player));
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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.bukkit.listeners.protocol1_9to1_8;
|
||||
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.BlockPosition;
|
||||
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
|
||||
+1
-1
@@ -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.bukkit.listeners.protocol1_9to1_8;
|
||||
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
+1
-1
@@ -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.bukkit.listeners.protocol1_9to1_8;
|
||||
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
|
||||
|
||||
import com.viaversion.viaversion.api.minecraft.item.DataItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
+1
-1
@@ -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.bukkit.listeners.protocol1_9to1_8;
|
||||
package com.viaversion.viaversion.bukkit.listeners.v1_8to1_9;
|
||||
|
||||
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
|
||||
import com.viaversion.viaversion.bukkit.util.CollisionChecker;
|
||||
@@ -268,6 +268,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
|
||||
return getServer().getPluginManager().getPlugin(name) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean couldBeReloading() {
|
||||
return !(PaperViaInjector.PAPER_IS_STOPPING_METHOD && Bukkit.isStopping());
|
||||
}
|
||||
|
||||
public boolean isLateBind() {
|
||||
return lateBind;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+2
-2
@@ -51,13 +51,13 @@ public class EntityToggleGlideListener extends ViaBukkitListener {
|
||||
|
||||
if (!isOnPipe(player)) return;
|
||||
|
||||
// Cancelling can only be done by updating the player's metadata
|
||||
// Cancelling can only be done by updating the player's entity data
|
||||
if (event.isGliding() && event.isCancelled()) {
|
||||
PacketWrapper packet = PacketWrapper.create(ClientboundPackets1_15.SET_ENTITY_DATA, null, getUserConnection(player));
|
||||
packet.write(Types.VAR_INT, player.getEntityId());
|
||||
|
||||
byte bitmask = 0;
|
||||
// Collect other metadata for the mitmask
|
||||
// Collect other entity data for the mitmask
|
||||
if (player.getFireTicks() > 0) {
|
||||
bitmask |= 0x01;
|
||||
}
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.bukkit.listeners.v1_20_5to1_21;
|
||||
|
||||
import com.viaversion.viaversion.ViaVersionPlugin;
|
||||
import io.papermc.paper.event.player.PlayerInventorySlotChangeEvent;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
public final class PaperPlayerChangeItemListener extends PlayerChangeItemListener {
|
||||
|
||||
public PaperPlayerChangeItemListener(final ViaVersionPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerInventorySlotChangedEvent(final PlayerInventorySlotChangeEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final ItemStack item = event.getNewItemStack();
|
||||
final PlayerInventory inventory = player.getInventory();
|
||||
final int slot = event.getSlot();
|
||||
if (slot == inventory.getHeldItemSlot()) {
|
||||
sendAttributeUpdate(player, item, Slot.HAND);
|
||||
} else if (slot == 36) {
|
||||
sendAttributeUpdate(player, item, Slot.BOOTS);
|
||||
} else if (slot == 37) {
|
||||
sendAttributeUpdate(player, item, Slot.LEGGINGS);
|
||||
} else if (slot == 39) {
|
||||
sendAttributeUpdate(player, item, Slot.HELMET);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+39
-17
@@ -23,8 +23,6 @@ import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener;
|
||||
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
|
||||
import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.EfficiencyAttributeStorage;
|
||||
import io.papermc.paper.event.player.PlayerInventorySlotChangeEvent;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -37,31 +35,27 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
* For some reason, mining efficiency is not calculated by the client anymore, but by the server,
|
||||
* then sending the current value to the client every time the item changes. This roughly emulates that behavior.
|
||||
*/
|
||||
public final class PlayerChangeItemListener extends ViaBukkitListener {
|
||||
public class PlayerChangeItemListener extends ViaBukkitListener {
|
||||
|
||||
private final Enchantment efficiency = Enchantment.getByKey(NamespacedKey.minecraft("efficiency"));
|
||||
// Use legacy function and names here to support all versions
|
||||
private final Enchantment efficiency = getByName("efficiency", "DIG_SPEED");
|
||||
private final Enchantment aquaAffinity = getByName("aqua_affinity", "WATER_WORKER");
|
||||
private final Enchantment depthStrider = getByName("depth_strider", "DEPTH_STRIDER");
|
||||
private final Enchantment soulSpeed = getByName("soul_speed", "SOUL_SPEED");
|
||||
private final Enchantment swiftSneak = getByName("swift_sneak", "SWIFT_SNEAK");
|
||||
|
||||
public PlayerChangeItemListener(final ViaVersionPlugin plugin) {
|
||||
super(plugin, Protocol1_20_5To1_21.class);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerInventorySlotChangedEvent(final PlayerInventorySlotChangeEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final ItemStack item = event.getNewItemStack();
|
||||
if (event.getSlot() == player.getInventory().getHeldItemSlot()) {
|
||||
sendAttributeUpdate(player, item);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onPlayerItemHeld(final PlayerItemHeldEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final ItemStack item = player.getInventory().getItem(event.getNewSlot());
|
||||
sendAttributeUpdate(player, item);
|
||||
sendAttributeUpdate(player, item, Slot.HAND);
|
||||
}
|
||||
|
||||
private void sendAttributeUpdate(final Player player, @Nullable final ItemStack item) {
|
||||
void sendAttributeUpdate(final Player player, @Nullable final ItemStack item, final Slot slot) {
|
||||
final UserConnection connection = Via.getAPI().getConnection(player.getUniqueId());
|
||||
if (connection == null || !isOnPipe(player)) {
|
||||
return;
|
||||
@@ -72,7 +66,35 @@ public final class PlayerChangeItemListener extends ViaBukkitListener {
|
||||
return;
|
||||
}
|
||||
|
||||
final int efficiencyLevel = item != null ? item.getEnchantmentLevel(efficiency) : 0;
|
||||
storage.setEfficiencyLevel(new EfficiencyAttributeStorage.StoredEfficiency(player.getEntityId(), efficiencyLevel), connection);
|
||||
final EfficiencyAttributeStorage.ActiveEnchants activeEnchants = storage.activeEnchants();
|
||||
int efficiencyLevel = activeEnchants.efficiency().level();
|
||||
int aquaAffinityLevel = activeEnchants.aquaAffinity().level();
|
||||
int soulSpeedLevel = activeEnchants.soulSpeed().level();
|
||||
int swiftSneakLevel = activeEnchants.swiftSneak().level();
|
||||
int depthStriderLevel = activeEnchants.depthStrider().level();
|
||||
switch (slot) {
|
||||
case HAND -> efficiencyLevel = item != null ? item.getEnchantmentLevel(efficiency) : 0;
|
||||
case HELMET -> aquaAffinityLevel = item != null ? item.getEnchantmentLevel(aquaAffinity) : 0;
|
||||
case LEGGINGS -> swiftSneakLevel = item != null && swiftSneak != null ? item.getEnchantmentLevel(swiftSneak) : 0;
|
||||
case BOOTS -> {
|
||||
depthStriderLevel = item != null && depthStrider != null ? item.getEnchantmentLevel(depthStrider) : 0;
|
||||
// TODO This needs continuous ticking for the supporting block as a conditional effect
|
||||
// and is even more prone to desync from high ping than the other attributes
|
||||
//soulSpeedLevel = item != null && soulSpeed != null ? item.getEnchantmentLevel(soulSpeed) : 0;
|
||||
}
|
||||
}
|
||||
storage.setEnchants(player.getEntityId(), connection, efficiencyLevel, soulSpeedLevel, swiftSneakLevel, aquaAffinityLevel, depthStriderLevel);
|
||||
}
|
||||
|
||||
enum Slot {
|
||||
HAND, BOOTS, LEGGINGS, HELMET
|
||||
}
|
||||
|
||||
private Enchantment getByName(final String newName, final String oldName) {
|
||||
final Enchantment enchantment = Enchantment.getByName(newName);
|
||||
if (enchantment == null) {
|
||||
return Enchantment.getByName(oldName);
|
||||
}
|
||||
return enchantment;
|
||||
}
|
||||
}
|
||||
+22
-3
@@ -19,19 +19,20 @@ package com.viaversion.viaversion.bukkit.platform;
|
||||
|
||||
import com.viaversion.viaversion.configuration.AbstractViaConfig;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class BukkitViaConfig extends AbstractViaConfig {
|
||||
private static final List<String> UNSUPPORTED = Arrays.asList("velocity-ping-interval", "velocity-ping-save", "velocity-servers");
|
||||
private boolean quickMoveActionFix;
|
||||
private boolean hitboxFix1_9;
|
||||
private boolean hitboxFix1_14;
|
||||
private String blockConnectionMethod;
|
||||
private boolean armorToggleFix;
|
||||
private boolean registerUserConnectionOnJoin;
|
||||
private boolean useNewDeathMessages;
|
||||
private boolean itemCache;
|
||||
private boolean nmsPlayerTicking;
|
||||
|
||||
public BukkitViaConfig(final File folder, final Logger logger) {
|
||||
super(new File(folder, "config.yml"), logger);
|
||||
@@ -46,6 +47,9 @@ public class BukkitViaConfig extends AbstractViaConfig {
|
||||
hitboxFix1_14 = getBoolean("change-1_14-hitbox", false);
|
||||
blockConnectionMethod = getString("blockconnection-method", "packet");
|
||||
armorToggleFix = getBoolean("armor-toggle-fix", true);
|
||||
useNewDeathMessages = getBoolean("use-new-deathmessages", true);
|
||||
itemCache = getBoolean("item-cache", true);
|
||||
nmsPlayerTicking = getBoolean("nms-player-ticking", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,8 +86,23 @@ public class BukkitViaConfig extends AbstractViaConfig {
|
||||
return armorToggleFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowNewDeathMessages() {
|
||||
return useNewDeathMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemCache() {
|
||||
return itemCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNMSPlayerTicking() {
|
||||
return nmsPlayerTicking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUnsupportedOptions() {
|
||||
return UNSUPPORTED;
|
||||
return VELOCITY_ONLY_OPTIONS;
|
||||
}
|
||||
}
|
||||
+15
-8
@@ -28,11 +28,12 @@ import com.viaversion.viaversion.bukkit.listeners.multiversion.PlayerSneakListen
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_14_4to1_15.EntityToggleGlideListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_19_3to1_19_4.ArmorToggleListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_18_2to1_19.BlockBreakListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.ArmorListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.BlockListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.DeathListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.HandItemCache;
|
||||
import com.viaversion.viaversion.bukkit.listeners.protocol1_9to1_8.PaperPatch;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.ArmorListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.BlockListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.DeathListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.HandItemCache;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.PaperPatch;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PaperPlayerChangeItemListener;
|
||||
import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PlayerChangeItemListener;
|
||||
import com.viaversion.viaversion.bukkit.providers.BukkitAckSequenceProvider;
|
||||
import com.viaversion.viaversion.bukkit.providers.BukkitBlockConnectionProvider;
|
||||
@@ -87,7 +88,9 @@ public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_9)) {
|
||||
new ArmorListener(plugin).register();
|
||||
new DeathListener(plugin).register();
|
||||
new BlockListener(plugin).register();
|
||||
if (plugin.getConf().cancelBlockSounds()) {
|
||||
new BlockListener(plugin).register();
|
||||
}
|
||||
|
||||
if (plugin.getConf().isItemCache()) {
|
||||
handItemCache = new HandItemCache();
|
||||
@@ -177,8 +180,12 @@ public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
Via.getManager().getProviders().use(AckSequenceProvider.class, new BukkitAckSequenceProvider(plugin));
|
||||
new BlockBreakListener(plugin).register();
|
||||
}
|
||||
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21) && PaperViaInjector.hasClass("io.papermc.paper.event.player.PlayerInventorySlotChangeEvent")) {
|
||||
new PlayerChangeItemListener(plugin).register();
|
||||
if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21)) {
|
||||
if (PaperViaInjector.hasClass("io.papermc.paper.event.player.PlayerInventorySlotChangeEvent")) {
|
||||
new PaperPlayerChangeItemListener(plugin).register();
|
||||
} else {
|
||||
new PlayerChangeItemListener(plugin).register();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ public final class PaperViaInjector {
|
||||
public static final boolean PAPER_INJECTION_METHOD = hasPaperInjectionMethod();
|
||||
public static final boolean PAPER_PROTOCOL_METHOD = hasServerProtocolMethod();
|
||||
public static final boolean PAPER_PACKET_LIMITER = hasPacketLimiter();
|
||||
public static final boolean PAPER_IS_STOPPING_METHOD = hasIsStoppingMethod();
|
||||
|
||||
private PaperViaInjector() {
|
||||
}
|
||||
@@ -76,6 +77,15 @@ public final class PaperViaInjector {
|
||||
return hasClass("io.papermc.paper.network.ChannelInitializeListener");
|
||||
}
|
||||
|
||||
private static boolean hasIsStoppingMethod() {
|
||||
try {
|
||||
Bukkit.class.getDeclaredMethod("isStopping");
|
||||
return true;
|
||||
} catch (final NoSuchMethodException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasPacketLimiter() {
|
||||
return hasClass("com.destroystokyo.paper.PaperConfig$PacketLimit") || hasClass("io.papermc.paper.configuration.GlobalConfiguration$PacketLimiter");
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ package com.viaversion.viaversion.bukkit.providers;
|
||||
import com.viaversion.viaversion.ViaVersionPlugin;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.bukkit.tasks.protocol1_19to1_18_2.AckSequenceTask;
|
||||
import com.viaversion.viaversion.bukkit.tasks.v1_18_2to1_19.AckSequenceTask;
|
||||
import com.viaversion.viaversion.protocols.v1_18_2to1_19.provider.AckSequenceProvider;
|
||||
import com.viaversion.viaversion.protocols.v1_18_2to1_19.storage.SequenceStorage;
|
||||
|
||||
@@ -45,4 +45,4 @@ public final class BukkitAckSequenceProvider extends AckSequenceProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -21,7 +21,7 @@ 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.version.ProtocolVersion;
|
||||
import com.viaversion.viaversion.bukkit.tasks.protocol1_12to1_11_1.BukkitInventoryUpdateTask;
|
||||
import com.viaversion.viaversion.bukkit.tasks.v1_11_1to1_12.BukkitInventoryUpdateTask;
|
||||
import com.viaversion.viaversion.bukkit.util.NMSUtil;
|
||||
import com.viaversion.viaversion.protocols.v1_11_1to1_12.provider.InventoryQuickMoveProvider;
|
||||
import com.viaversion.viaversion.protocols.v1_11_1to1_12.storage.ItemTransactionStorage;
|
||||
@@ -201,4 +201,4 @@ public class BukkitInventoryQuickMoveProvider extends InventoryQuickMoveProvider
|
||||
final ProtocolVersion protocol = Via.getAPI().getServerVersion().lowestSupportedProtocolVersion();
|
||||
return protocol.newerThanOrEqualTo(ProtocolVersion.v1_8) && protocol.olderThanOrEqualTo(ProtocolVersion.v1_11_1);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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.bukkit.tasks.protocol1_12to1_11_1;
|
||||
package com.viaversion.viaversion.bukkit.tasks.v1_11_1to1_12;
|
||||
|
||||
import com.viaversion.viaversion.bukkit.providers.BukkitInventoryQuickMoveProvider;
|
||||
import com.viaversion.viaversion.protocols.v1_11_1to1_12.storage.ItemTransactionStorage;
|
||||
@@ -65,4 +65,4 @@ public class BukkitInventoryUpdateTask implements Runnable {
|
||||
provider.onTaskExecuted(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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.bukkit.tasks.protocol1_19to1_18_2;
|
||||
package com.viaversion.viaversion.bukkit.tasks.v1_18_2to1_19;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
@@ -3,13 +3,11 @@ dependencies {
|
||||
api(rootProject.libs.text) {
|
||||
exclude("com.google.code.gson", "gson")
|
||||
}
|
||||
implementation(projects.compat.snakeyaml2Compat)
|
||||
implementation(projects.compat.snakeyaml1Compat)
|
||||
|
||||
// Note: If manually starting tests doesn't work for you in IJ, change 'Gradle -> Run Tests Using' to 'IntelliJ IDEA'
|
||||
testImplementation(rootProject.libs.netty)
|
||||
testImplementation(rootProject.libs.guava)
|
||||
testImplementation(rootProject.libs.snakeYaml2)
|
||||
testImplementation(rootProject.libs.snakeYaml)
|
||||
testImplementation(rootProject.libs.bundles.junit)
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ public class ViaManagerImpl implements ViaManager {
|
||||
private final ViaPlatformLoader loader;
|
||||
private final Set<String> subPlatforms = new HashSet<>();
|
||||
private List<Runnable> enableListeners = new ArrayList<>();
|
||||
private List<Runnable> postEnableListeners = new ArrayList<>();
|
||||
private PlatformTask<?> mappingLoadingTask;
|
||||
private boolean initialized;
|
||||
|
||||
@@ -150,7 +151,7 @@ public class ViaManagerImpl implements ViaManager {
|
||||
platform.getLogger().warning("and if you're still unsure, feel free to join our Discord-Server for further assistance.");
|
||||
} else if (protocolVersion.highestSupportedProtocolVersion().olderThan(ProtocolVersion.v1_13)) {
|
||||
platform.getLogger().warning("This version of Minecraft is extremely outdated and support for it has reached its end of life. "
|
||||
+ "You will still be able to run Via on this Minecraft version, but we are unlikely to provide any further fixes or help with problems specific to legacy Minecraft versions. "
|
||||
+ "You will still be able to run Via on this Minecraft version, but we will prioritize issues with legacy Minecraft versions less. "
|
||||
+ "Please consider updating to give your players a better experience and to avoid issues that have long been fixed.");
|
||||
}
|
||||
}
|
||||
@@ -184,6 +185,11 @@ public class ViaManagerImpl implements ViaManager {
|
||||
|
||||
// Refresh Versions
|
||||
protocolManager.refreshVersions();
|
||||
|
||||
for (final Runnable listener : postEnableListeners) {
|
||||
listener.run();
|
||||
}
|
||||
postEnableListeners = null;
|
||||
}
|
||||
|
||||
private void loadServerProtocol() {
|
||||
@@ -204,8 +210,10 @@ public class ViaManagerImpl implements ViaManager {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// Uninject
|
||||
platform.getLogger().info("ViaVersion is disabling, if this is a reload and you experience issues consider rebooting.");
|
||||
if (platform.couldBeReloading()) {
|
||||
platform.getLogger().info("ViaVersion is disabling. If this is a reload and you experience issues, please reboot instead.");
|
||||
}
|
||||
|
||||
try {
|
||||
injector.uninject();
|
||||
} catch (Exception e) {
|
||||
@@ -214,6 +222,8 @@ public class ViaManagerImpl implements ViaManager {
|
||||
|
||||
loader.unload();
|
||||
scheduler.shutdown();
|
||||
|
||||
platform.getLogger().info("ViaVersion has been disabled; uninjected the platform and shut down the scheduler.");
|
||||
}
|
||||
|
||||
private void checkJavaVersion() { // Stolen from Paper
|
||||
@@ -235,7 +245,8 @@ public class ViaManagerImpl implements ViaManager {
|
||||
|
||||
if (version < 17) {
|
||||
platform.getLogger().warning("You are running an outdated Java version, please update it to at least Java 17 (your version is " + javaVersion + ").");
|
||||
platform.getLogger().warning("Starting with Minecraft 1.21, ViaVersion will no longer officially be compatible with this version of Java, only offering unsupported compatibility builds.");
|
||||
platform.getLogger().warning("ViaVersion no longer officially supports this version of Java, only offering unsupported compatibility builds.");
|
||||
platform.getLogger().warning("See https://github.com/ViaVersion/ViaVersion/releases/tag/5.0.0 for more information.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,25 +327,21 @@ public class ViaManagerImpl implements ViaManager {
|
||||
return configurationProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable set of self-added subplatform version strings.
|
||||
* This set is expanded by the subplatform itself (e.g. ViaBackwards), and may not contain all running ones.
|
||||
*
|
||||
* @return mutable set of subplatform versions
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getSubPlatforms() {
|
||||
return subPlatforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a runnable to be executed when ViaVersion has finished its init before the full server load.
|
||||
*
|
||||
* @param runnable runnable to be executed
|
||||
*/
|
||||
@Override
|
||||
public void addEnableListener(Runnable runnable) {
|
||||
enableListeners.add(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPostEnableListener(final Runnable runnable) {
|
||||
postEnableListeners.add(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
|
||||
@@ -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
|
||||
|
||||
+32
-18
@@ -25,21 +25,26 @@ 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 {
|
||||
public static final List<String> BUKKIT_ONLY_OPTIONS = Arrays.asList("register-userconnections-on-join", "quick-move-action-fix",
|
||||
"change-1_9-hitbox", "change-1_14-hitbox", "blockconnection-method", "armor-toggle-fix", "use-new-deathmessages",
|
||||
"item-cache", "nms-player-ticking");
|
||||
|
||||
public static final List<String> VELOCITY_ONLY_OPTIONS = Arrays.asList("velocity-ping-interval", "velocity-ping-save", "velocity-servers");
|
||||
|
||||
private boolean checkForUpdates;
|
||||
private boolean preventCollision;
|
||||
private boolean useNewEffectIndicator;
|
||||
private boolean useNewDeathmessages;
|
||||
private boolean suppressMetadataErrors;
|
||||
private boolean shieldBlocking;
|
||||
private boolean noDelayShieldBlocking;
|
||||
@@ -57,8 +62,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
private String maxPPSWarningsKickMessage;
|
||||
private boolean sendSupportedVersions;
|
||||
private boolean simulatePlayerTick;
|
||||
private boolean itemCache;
|
||||
private boolean nmsPlayerTicking;
|
||||
private boolean replacePistons;
|
||||
private int pistonReplacementId;
|
||||
private boolean chunkBorderFix;
|
||||
@@ -69,7 +72,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
private String reloadDisconnectMessage;
|
||||
private boolean suppressConversionWarnings;
|
||||
private boolean disable1_13TabComplete;
|
||||
private boolean minimizeCooldown;
|
||||
private boolean teamColourFix;
|
||||
private boolean serversideBlockConnections;
|
||||
private boolean reduceBlockStorageMemory;
|
||||
@@ -91,6 +93,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
private boolean translateOcelotToCat;
|
||||
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);
|
||||
@@ -106,7 +111,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
checkForUpdates = getBoolean("check-for-updates", true);
|
||||
preventCollision = getBoolean("prevent-collision", true);
|
||||
useNewEffectIndicator = getBoolean("use-new-effect-indicator", true);
|
||||
useNewDeathmessages = getBoolean("use-new-deathmessages", true);
|
||||
suppressMetadataErrors = getBoolean("suppress-metadata-errors", false);
|
||||
shieldBlocking = getBoolean("shield-blocking", true);
|
||||
noDelayShieldBlocking = getBoolean("no-delay-shield-blocking", false);
|
||||
@@ -124,8 +128,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
maxPPSWarningsKickMessage = getString("tracking-max-kick-msg", "You are sending too many packets, :(");
|
||||
sendSupportedVersions = getBoolean("send-supported-versions", false);
|
||||
simulatePlayerTick = getBoolean("simulate-pt", true);
|
||||
itemCache = getBoolean("item-cache", true);
|
||||
nmsPlayerTicking = getBoolean("nms-player-ticking", true);
|
||||
replacePistons = getBoolean("replace-pistons", false);
|
||||
pistonReplacementId = getInt("replacement-piston-id", 0);
|
||||
chunkBorderFix = getBoolean("chunk-border-fix", false);
|
||||
@@ -134,7 +136,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
blockedProtocolVersions = loadBlockedProtocolVersions();
|
||||
blockedDisconnectMessage = getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
|
||||
reloadDisconnectMessage = getString("reload-disconnect-msg", "Server reload, please rejoin!");
|
||||
minimizeCooldown = getBoolean("minimize-cooldown", true);
|
||||
teamColourFix = getBoolean("team-colour-fix", true);
|
||||
suppressConversionWarnings = getBoolean("suppress-conversion-warnings", false);
|
||||
disable1_13TabComplete = getBoolean("disable-1_13-auto-complete", false);
|
||||
@@ -161,6 +162,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
translateOcelotToCat = getBoolean("translate-ocelot-to-cat", true);
|
||||
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() {
|
||||
@@ -254,7 +258,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
|
||||
@Override
|
||||
public boolean isShowNewDeathMessages() {
|
||||
return useNewDeathmessages;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -344,12 +348,12 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
|
||||
@Override
|
||||
public boolean isItemCache() {
|
||||
return itemCache;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNMSPlayerTicking() {
|
||||
return nmsPlayerTicking;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -403,11 +407,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
return reloadDisconnectMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimizeCooldown() {
|
||||
return minimizeCooldown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_13TeamColourFix() {
|
||||
return teamColourFix;
|
||||
@@ -542,4 +541,19 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
|
||||
public boolean handleInvalidItemCount() {
|
||||
return handleInvalidItemCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,14 @@ public final class DimensionDataImpl implements DimensionData {
|
||||
this.minY = minY.asInt();
|
||||
}
|
||||
|
||||
public static DimensionData withDefaultsFor(final String key, final int id) {
|
||||
return switch (key) {
|
||||
case "overworld", "overworld_caves" -> new DimensionDataImpl(id, -64, 384);
|
||||
case "the_nether", "the_end" -> new DimensionDataImpl(id, 0, 256);
|
||||
default -> throw new IllegalArgumentException("Missing registry data for unknown dimension: " + key);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int id() {
|
||||
return id;
|
||||
@@ -65,8 +73,9 @@ public final class DimensionDataImpl implements DimensionData {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DimensionData{" +
|
||||
"minY=" + minY +
|
||||
return "DimensionDataImpl{" +
|
||||
"id=" + id +
|
||||
", minY=" + minY +
|
||||
", height=" + height +
|
||||
'}';
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.dump;
|
||||
|
||||
import com.viaversion.viaversion.api.protocol.version.VersionType;
|
||||
import java.util.Set;
|
||||
|
||||
public record VersionInfo(String javaVersion, String operatingSystem, VersionType versionType,
|
||||
public record VersionInfo(String javaVersion, String operatingSystem,
|
||||
int serverProtocol, String serverVersion,
|
||||
Set<String> enabledProtocols, String platformName,
|
||||
String platformVersion, String pluginVersion,
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.legacy.bossbar;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.legacy.bossbar.BossBar;
|
||||
@@ -26,7 +27,6 @@ import com.viaversion.viaversion.api.legacy.bossbar.BossColor;
|
||||
import com.viaversion.viaversion.api.legacy.bossbar.BossFlag;
|
||||
import com.viaversion.viaversion.api.legacy.bossbar.BossStyle;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
import com.viaversion.viaversion.api.type.Types;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
|
||||
import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9;
|
||||
@@ -246,28 +246,32 @@ public class CommonBoss implements BossBar {
|
||||
wrapper.write(Types.UUID, uuid);
|
||||
wrapper.write(Types.VAR_INT, action.getId());
|
||||
switch (action) {
|
||||
case ADD:
|
||||
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(title));
|
||||
case ADD -> {
|
||||
try {
|
||||
wrapper.write(Types.COMPONENT, JsonParser.parseString(this.title));
|
||||
} catch (Exception e) {
|
||||
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(this.title));
|
||||
}
|
||||
wrapper.write(Types.FLOAT, health);
|
||||
wrapper.write(Types.VAR_INT, color.getId());
|
||||
wrapper.write(Types.VAR_INT, style.getId());
|
||||
wrapper.write(Types.BYTE, (byte) flagToBytes());
|
||||
break;
|
||||
case REMOVE:
|
||||
break;
|
||||
case UPDATE_HEALTH:
|
||||
wrapper.write(Types.FLOAT, health);
|
||||
break;
|
||||
case UPDATE_TITLE:
|
||||
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(title));
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
}
|
||||
case REMOVE -> {
|
||||
}
|
||||
case UPDATE_HEALTH -> wrapper.write(Types.FLOAT, health);
|
||||
case UPDATE_TITLE -> {
|
||||
try {
|
||||
wrapper.write(Types.COMPONENT, JsonParser.parseString(this.title));
|
||||
} catch (Exception e) {
|
||||
wrapper.write(Types.COMPONENT, ComponentUtil.plainToJson(this.title));
|
||||
}
|
||||
}
|
||||
case UPDATE_STYLE -> {
|
||||
wrapper.write(Types.VAR_INT, color.getId());
|
||||
wrapper.write(Types.VAR_INT, style.getId());
|
||||
break;
|
||||
case UPDATE_FLAGS:
|
||||
wrapper.write(Types.BYTE, (byte) flagToBytes());
|
||||
break;
|
||||
}
|
||||
case UPDATE_FLAGS -> wrapper.write(Types.BYTE, (byte) flagToBytes());
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+14
-2
@@ -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 {
|
||||
|
||||
@@ -52,4 +54,14 @@ 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;
|
||||
}
|
||||
}
|
||||
+60
-19
@@ -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());
|
||||
|
||||
+43
-14
@@ -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,34 +43,45 @@ 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
|
||||
wrapper.passthrough(Types.UNSIGNED_SHORT); // Server Port
|
||||
int state = wrapper.passthrough(Types.VAR_INT);
|
||||
|
||||
ProtocolInfo info = wrapper.user().getProtocolInfo();
|
||||
info.setProtocolVersion(ProtocolVersion.getProtocol(protocolVersion));
|
||||
// Ensure the server has a version provider
|
||||
VersionProvider versionProvider = Via.getManager().getProviders().get(VersionProvider.class);
|
||||
// Ensure the server has a version provider
|
||||
if (versionProvider == null) {
|
||||
wrapper.user().setActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ProtocolInfo info = wrapper.user().getProtocolInfo();
|
||||
info.setProtocolVersion(ProtocolVersion.getProtocol(protocolVersion));
|
||||
|
||||
ProtocolVersion clientVersion = versionProvider.getClientProtocol(wrapper.user());
|
||||
if (clientVersion != null) {
|
||||
info.setProtocolVersion(clientVersion);
|
||||
}
|
||||
|
||||
// Choose the pipe
|
||||
ProtocolVersion serverProtocol;
|
||||
try {
|
||||
@@ -83,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
|
||||
@@ -112,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) {
|
||||
@@ -156,4 +185,4 @@ public class BaseProtocol extends AbstractProtocol<BaseClientboundPacket, BaseCl
|
||||
protected PacketTypesProvider<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> createPacketTypesProvider() {
|
||||
return BasePacketTypesProvider.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-65
@@ -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
|
||||
Loaded 100 of 228 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user