Release ViaPotions-OG

This commit is contained in:
NotAlexNoyle committed 2026-03-25 06:31:47 -04:00
1 parent b9a976d3d3
commit e473f50b79
11 files changed
+303 -109

No files matched your search

+17 -5
View File
@@ -1,8 +1,20 @@
# ViaPotions
Translates thrown potions for ViaRewind
# ViaPotions-OG
## To Build:
Translates thrown and lingering potion visuals for legacy ViaVersion stacks on Purpur 1.19.4.
```./mvnw clean package```
## Compatibility
*The jar file will be in target/*
- Server: Purpur 1.19.4
- Clients: 1.8 through 1.21.11, where the connected ViaVersion stack exposes those protocol translations
- Required: ProtocolLib, ViaVersion
- Optional: ViaRewind for 1.8 support
- Optional: ViaBackwards for 1.9-1.10 support
- Optional: ViaRewind-Legacy-Support if you already provide its area effect cloud particle fallback
## Build
```bash
./gradlew build
```
The shaded jar is written to `build/libs/`.
+2 -2
View File
@@ -7,7 +7,7 @@ plugins {
id("java") // Import Java plugin.
id("java-library") // Import Java Library plugin.
id("com.diffplug.spotless") version "7.0.4" // Import Spotless plugin.
id("com.gradleup.shadow") version "8.3.8" // Import Shadow plugin.
id("com.gradleup.shadow") version "8.3.9" // Import Shadow plugin.
id("checkstyle") // Import Checkstyle plugin.
eclipse // Import Eclipse plugin.
kotlin("jvm") version "2.1.21" // Import Kotlin JVM plugin.
@@ -31,7 +31,7 @@ kotlin { jvmToolchain(17) }
/* ----------------------------- Metadata ------------------------------ */
group = "dev._2lstudios" // Declare bundle identifier.
version = "0.0.4" // Declare plugin version (will be in .jar).
version = "0.0.5" // Declare plugin version (will be in .jar).
val apiVersion = "1.19" // Declare minecraft server target version.
+1 -1
View File
@@ -1 +1 @@
rootProject.name = "ViaPotions"
rootProject.name = "ViaPotions-OG"
+33 -15
View File
@@ -14,40 +14,58 @@ import dev._2lstudios.viapotions.utils.VersionUtil;
public class ViaPotions extends JavaPlugin {
@Override
public void onEnable() {
final ConfigurationUtil configurationUtil = new ConfigurationUtil(this);
final VersionUtil versionUtil = new VersionUtil(this);
final PluginManager pluginManager = getServer().getPluginManager();
final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
final boolean hasViaVersion = versionUtil.isViaVersionAvailable();
final boolean hasViaBackwards = pluginManager.isPluginEnabled("ViaBackwards");
final boolean hasViaRewind = pluginManager.isPluginEnabled("ViaRewind");
if (pluginManager.isPluginEnabled("ViaRewind")) {
if (!hasViaVersion) {
getLogger().info("ViaRewind detected, enabling integration.");
} else if (pluginManager.isPluginEnabled("ViaBackwards")) {
getLogger().warning(
"ViaBackwards detected. In order to make ViaPotions work correctly, it is required that you have ViaRewind installed.");
} else {
getLogger().severe("No compatible plugins have been detected, disabling the plugin.");
getLogger().severe("In order to make ViaPotions functional, ViaRewind must be installed.");
getLogger().severe("ViaVersion was not found, disabling the plugin.");
pluginManager.disablePlugin(this);
return;
}
if (pluginManager.getPlugin("ViaRewind-Legacy-Support") == null
if (!hasViaBackwards && !hasViaRewind) {
getLogger().warning("Neither ViaBackwards nor ViaRewind was found, disabling the plugin.");
pluginManager.disablePlugin(this);
return;
}
if (hasViaRewind) {
getLogger().info("ViaRewind detected, enabling legacy 1.8 potion support.");
} else {
getLogger().info("ViaBackwards detected, enabling 1.9-1.10 splash event translation.");
}
if (hasViaRewind && (pluginManager.getPlugin("ViaRewind-Legacy-Support") == null
|| !configurationUtil.getConfiguration("%datafolder%/ViaRewind-Legacy-Support/config.yml")
.getBoolean("area-effect-cloud-particles"))
.getBoolean("area-effect-cloud-particles")))
{
pluginManager.registerEvents(new AreaEffectCloudListener(this, versionUtil), this);
}
protocolManager.addPacketListener(new SpawnEntityListener(this, versionUtil));
if (hasViaRewind) {
protocolManager.addPacketListener(new SpawnEntityListener(this, versionUtil));
}
protocolManager.addPacketListener(new WorldEventAdapter(this, versionUtil));
}
@@ -11,7 +11,6 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import dev._2lstudios.viapotions.utils.SplashTranslator;
import dev._2lstudios.viapotions.utils.TranslationData;
import dev._2lstudios.viapotions.utils.VersionUtil;
public class WorldEventAdapter extends PacketAdapter {
@@ -27,7 +26,7 @@ public class WorldEventAdapter extends PacketAdapter {
}
@Override
public void onPacketSending(PacketEvent event) {
public void onPacketSending(final PacketEvent event) {
if (event.isPlayerTemporary()) {
@@ -35,54 +34,69 @@ public class WorldEventAdapter extends PacketAdapter {
}
final Player player = event.getPlayer();
final int version = versionUtil.getVersion(player);
if (!versionUtil.needsSplashPotionTranslation(version)) {
return;
}
final PacketContainer packet = event.getPacket();
final int effectId = packet.getIntegers().read(0);
final StructureModifier<Integer> integers = packet.getIntegers();
if (effectId == 2002 || effectId == 2007) {
if (integers.size() < 2) {
final Player player = event.getPlayer();
final int version = versionUtil.getVersion(player);
final PacketContainer edited = packet.deepClone();
final StructureModifier<Integer> editedIntegers = edited.getIntegers();
return;
if (version <= 210) {
}
editedIntegers.write(0, 2002);
final int effectId = integers.read(0);
}
if (effectId != 2002 && effectId != 2007) {
for (final SplashTranslator translator : SplashTranslator.values()) {
return;
if (editedIntegers.read(1) == translator.getRGB()) {
}
for (final TranslationData data : translator.getDatas()) {
final PacketContainer edited = packet.deepClone();
final StructureModifier<Integer> editedIntegers = edited.getIntegers();
boolean changed = false;
if (data.getLowestVersion() <= version && data.getHighestVersion() >= version) {
if (effectId == 2007) {
editedIntegers.write(1, data.getRemap());
editedIntegers.write(0, 2002);
changed = true;
}
}
}
final Integer remap = SplashTranslator.findRemap(editedIntegers.read(1), version);
}
if (remap != null && editedIntegers.read(1) != remap.intValue()) {
}
editedIntegers.write(1, remap);
changed = true;
try {
}
ProtocolLibrary.getProtocolManager().sendServerPacket(player, edited, false);
if (!changed) {
} catch (Exception e) {
return;
e.printStackTrace();
}
}
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(player, edited, false);
event.setCancelled(true);
} catch (final Exception exception) {
exception.printStackTrace();
}
}
}
}
@@ -1,6 +1,13 @@
package dev._2lstudios.viapotions.listeners;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -10,16 +17,15 @@ import org.bukkit.plugin.Plugin;
import dev._2lstudios.viapotions.utils.VersionUtil;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class AreaEffectCloudListener implements Listener {
final private List<AreaEffectCloud> effectClouds;
private static final Particle LEGACY_PARTICLE = Particle.SPELL_MOB;
private final Set<AreaEffectCloud> effectClouds;
public AreaEffectCloudListener(final Plugin plugin, final VersionUtil versionUtil) {
effectClouds = new CopyOnWriteArrayList<>();
effectClouds = ConcurrentHashMap.newKeySet();
plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, () -> {
@@ -28,35 +34,45 @@ public class AreaEffectCloudListener implements Listener {
if (cloud == null || cloud.isDead() || !cloud.isValid()) {
effectClouds.remove(cloud);
continue;
} else {
}
final Location location = cloud.getLocation();
final float radius = cloud.getRadius();
final float area = (float) Math.PI * radius * radius;
final List<Player> legacyPlayers = getLegacyPlayers(cloud, versionUtil);
final int color = cloud.getColor().asRGB();
final int red = color >> 16 & 255;
final int green = color >> 8 & 255;
final int blue = color & 255;
if (legacyPlayers.isEmpty()) {
for (int i = 0; i < area; i++) {
continue;
float f1 = (float) Math.random() * 6.2831855F;
float f2 = (float) Math.sqrt(Math.random()) * radius;
float f3 = (float) Math.cos(f1) * f2;
float f4 = (float) Math.sin(f1) * f2;
}
for (final Player player : cloud.getWorld().getPlayers()) {
final Color color = cloud.getColor();
if (versionUtil.getVersion(player) <= 106) {
if (color == null) {
player.spawnParticle(cloud.getParticle(), location.getX() + f3, location.getY(),
location.getZ() + f4, 0, red / 255f, green / 255f, blue / 255f);
continue;
}
}
}
final Location location = cloud.getLocation();
final float radius = cloud.getRadius();
final int samples = Math.max(1, Math.round(radius * radius * 2.0F));
final int rgb = color.asRGB();
final float red = (rgb >> 16 & 255) / 255f;
final float green = (rgb >> 8 & 255) / 255f;
final float blue = (rgb & 255) / 255f;
for (int i = 0; i < samples; i++) {
final float angle = (float) (Math.random() * Math.PI * 2.0D);
final float distance = (float) Math.sqrt(Math.random()) * radius;
final double offsetX = Math.cos(angle) * distance;
final double offsetZ = Math.sin(angle) * distance;
for (final Player player : legacyPlayers) {
player.spawnParticle(LEGACY_PARTICLE, location.getX() + offsetX, location.getY(),
location.getZ() + offsetZ, 0, red, green, blue);
}
@@ -75,4 +91,22 @@ public class AreaEffectCloudListener implements Listener {
}
private List<Player> getLegacyPlayers(final AreaEffectCloud cloud, final VersionUtil versionUtil) {
final List<Player> legacyPlayers = new ArrayList<>();
for (final Player player : cloud.getWorld().getPlayers()) {
if (versionUtil.needsAreaEffectCloudFallback(versionUtil.getVersion(player))) {
legacyPlayers.add(player);
}
}
return legacyPlayers;
}
}
@@ -5,6 +5,7 @@ import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.StructureModifier;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@@ -13,7 +14,6 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect;
import dev._2lstudios.viapotions.utils.PotionTranslator;
import dev._2lstudios.viapotions.utils.TranslationData;
import dev._2lstudios.viapotions.utils.VersionUtil;
public class SpawnEntityListener extends PacketAdapter {
@@ -31,52 +31,93 @@ public class SpawnEntityListener extends PacketAdapter {
@Override
public void onPacketSending(final PacketEvent event) {
if (event.isPlayerTemporary()) {
return;
}
final Player player = event.getPlayer();
final int version = versionUtil.getVersion(player);
if (!versionUtil.needsPotionDataTranslation(version)) {
return;
}
final PacketContainer packet = event.getPacket();
final Entity entity = packet.getEntityModifier(event).read(0);
final Entity entity = packet.getEntityModifier(event).readSafely(0);
if (packet.getIntegers().read(6) == 73 && entity instanceof ThrownPotion) {
if (!(entity instanceof ThrownPotion)) {
final Player player = event.getPlayer();
final int version = versionUtil.getVersion(player);
final PacketContainer edited = packet.deepClone();
final ThrownPotion potion = (ThrownPotion) entity;
return;
for (final PotionEffect effect : potion.getEffects()) {
}
for (final PotionTranslator translator : PotionTranslator.values()) {
final Integer dataIndex = getPotionDataIndex(packet);
if (effect.getType().equals(translator.getPotionEffectType())) {
if (dataIndex == null) {
for (TranslationData data : translator.getDatas()) {
return;
if (data.getLowestVersion() <= version && data.getHighestVersion() >= version) {
}
edited.getIntegers().write(7, data.getRemap());
final Integer remap = getPotionRemap((ThrownPotion) entity, version);
}
if (remap == null) {
}
return;
}
}
}
final PacketContainer edited = packet.deepClone();
edited.getIntegers().write(dataIndex.intValue(), remap);
}
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(player, edited, false);
} catch (Exception e) {
e.printStackTrace();
}
try {
ProtocolLibrary.getProtocolManager().sendServerPacket(player, edited, false);
event.setCancelled(true);
} catch (final Exception exception) {
exception.printStackTrace();
}
}
private Integer getPotionDataIndex(final PacketContainer packet) {
final StructureModifier<Integer> integers = packet.getIntegers();
final int size = integers.size();
if (size < 2) {
return null;
}
return Integer.valueOf(size - 1);
}
private Integer getPotionRemap(final ThrownPotion potion, final int version) {
for (final PotionEffect effect : potion.getEffects()) {
final Integer remap = PotionTranslator.findRemap(effect.getType(), version);
if (remap != null) {
return remap;
}
}
return null;
}
}
@@ -44,4 +44,30 @@ public enum PotionTranslator {
}
public static Integer findRemap(final PotionEffectType effectType, final int version) {
for (final PotionTranslator translator : values()) {
if (translator.getPotionEffectType().equals(effectType)) {
for (final TranslationData data : translator.getDatas()) {
if (data.getLowestVersion() <= version && data.getHighestVersion() >= version) {
return data.getRemap();
}
}
return null;
}
}
return null;
}
}
@@ -42,4 +42,30 @@ public enum SplashTranslator {
}
public static Integer findRemap(final int rgb, final int version) {
for (final SplashTranslator translator : values()) {
if (translator.getRGB() == rgb) {
for (final TranslationData data : translator.getDatas()) {
if (data.getLowestVersion() <= version && data.getHighestVersion() >= version) {
return data.getRemap();
}
}
return null;
}
}
return null;
}
}
@@ -7,6 +7,9 @@ import com.viaversion.viaversion.api.Via;
public class VersionUtil {
public static final int LEGACY_POTION_DATA_MAX_PROTOCOL = 106;
public static final int LEGACY_SPLASH_EVENT_MAX_PROTOCOL = 210;
private final Plugin viaVersion;
public VersionUtil(final Plugin plugin) {
@@ -17,11 +20,11 @@ public class VersionUtil {
}
public int getVersion(Player player) {
public int getVersion(final Player player) {
if (viaVersion != null) {
return getViaVersionVersion(player);
return Via.getAPI().getPlayerVersion(player.getUniqueId());
}
@@ -29,9 +32,27 @@ public class VersionUtil {
}
private int getViaVersionVersion(Player player) {
public boolean isViaVersionAvailable() {
return Via.getAPI().getPlayerVersion(player.getUniqueId());
return viaVersion != null;
}
public boolean needsPotionDataTranslation(final int version) {
return version >= 0 && version <= LEGACY_POTION_DATA_MAX_PROTOCOL;
}
public boolean needsSplashPotionTranslation(final int version) {
return version >= 0 && version <= LEGACY_SPLASH_EVENT_MAX_PROTOCOL;
}
public boolean needsAreaEffectCloudFallback(final int version) {
return needsPotionDataTranslation(version);
}
+6 -4
View File
@@ -1,9 +1,11 @@
name: ViaPotions
version: 0.0.5
description: Translates thrown potions for ViaRewind
name: ViaPotions-OG
version: ${version}
description: Translates potion visuals for legacy ViaVersion clients
depend: [ProtocolLib]
api-version: 1.13
api-version: ${apiVersion}
softdepend:
- "ViaVersion"
- "ViaBackwards"
- "ViaRewind"
- "ViaRewind-Legacy-Support"
main: dev._2lstudios.viapotions.ViaPotions