Compare commits

..

No commits in common. "master" and "1.19.4-1" have entirely different histories.

14 changed files with 168 additions and 349 deletions

View file

@ -1,27 +0,0 @@
name: Build JAR
on:
push:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Get project version
run: echo "version=$(grep '^version' build.gradle | cut -d' ' -f3 | tr -d '\"')" >> $GITHUB_ENV
- name: Build with Gradle
run: ./gradlew build -x test
- name: Publish artifact
uses: actions/upload-artifact@v4
with:
name: FoliaFlow-${{ env.version }}-${{ github.sha }}
path: build/libs/FoliaFlow-${{ env.version }}.jar

1
.gitignore vendored
View file

@ -116,4 +116,3 @@ run/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
niri-rpc/

View file

@ -1 +0,0 @@

View file

@ -1,51 +1,15 @@
# THIS IS NOT MY PLUGIN, I JUST EDITED ONE SINGLE LINE IN PLUGIN.YML, THE ORIGINAL IS AT: https://github.com/MidnightTale/FoliaFlow
FoliaFlow is a Minecraft plugin that allows players to using gravity block duplication glitch again in Paper and Folia
## How is work?
Whenever a falling sand entity comes close to or hits the end portal, a new falling sand entity is summoned with a velocity that shoots it straight into the portal. However, we encountered a problem when the entity got reset by the safe teleport Paper patch - it lose its velocity. To fix this, we added the velocity back when the entity was in the end.
## ⚠️If you using folia
And type of concreate factory collector that use piston full block to stop falling blocks. You should change to slab to prevent block early break follow picture below
### Top View
![topviewff](https://user-images.githubusercontent.com/125941391/234716000-8dfe3f57-b9a4-4340-8d1a-4e63fe2cdb91.png)
### Side View
![sideviewff](https://user-images.githubusercontent.com/125941391/234716115-f793602c-17f9-4689-9740-7ff25013eed4.png)
# FoliaFlow
![sss1](https://user-images.githubusercontent.com/125941391/231678608-9762d384-dc3a-440c-a4eb-3340cb39a3e3.png)
FoliaFlow is a Minecraft plugin that allows players to using gravity block duplication glitch
## Installation
To install FoliaFlow, follow these steps:
1. Download the plugin JAR file from the [Modrinth](https://modrinth.com/plugin/foliaflow).
1. Download the plugin JAR file from the [releases page](https://github.com/Hynse/FoliaFlow/releases).
2. Copy the JAR file to the `plugins` folder of your Minecraft server.
3. Restart your server to load the plugin.
## Config flies (config.yml)
```yml
# Don't touch this file unless you know what you're doing
# Default values seems vanilla.
# If you find values that seems more vanilla please create a PR
# https://github.com/Hynse/FoliaFlow
# Default value for horizontal_coefficient
# - Folia (1.499)
# - Paper (2)
horizontal_coefficient: 1.499
# -----------------------------------------
vertical_coefficient: -1.7
spawn_height: 0.08
# Default value for teleport_offset
# - Folia (0.5)
# - Paper (2.4)
teleport_offset: 0.5
# -----------------------------------------
```
## Permissions
`foliaflow.reload` for using command `/flowreload` to reload config flies
3. Restart your server to enable the plugin.
## Contributing

View file

@ -2,8 +2,10 @@ plugins {
id 'java'
}
def loader = 'folia'
def server = '1.19.4'
group = 'xyz.hynse'
version = "3.0"
version = "1.3-${server}-${loader}"
repositories {
mavenCentral()
@ -11,10 +13,14 @@ repositories {
name = "papermc-repo"
url = "https://repo.papermc.io/repository/maven-public/"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/groups/public/"
}
}
dependencies {
compileOnly "dev.folia:folia-api:1.20.4-R0.1-SNAPSHOT"
compileOnly "dev.folia:folia-api:1.19.4-R0.1-SNAPSHOT"
}
def targetJavaVersion = 17

0
gradlew vendored Executable file → Normal file
View file

View file

@ -1,73 +1,171 @@
package xyz.hynse.foliaflow;
import org.bukkit.configuration.file.YamlConfiguration;
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
import io.papermc.paper.threadedregions.scheduler.RegionScheduler;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.Slab;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.Vector;
import xyz.hynse.foliaflow.command.ReloadCommand;
import xyz.hynse.foliaflow.util.CheckSafeTeleportation;
import xyz.hynse.foliaflow.watcher.PortalWatcher;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import static org.bukkit.Bukkit.getScheduler;
public class FoliaFlow extends JavaPlugin {
private boolean isFirstEnable = true;
//public boolean isUnSafeTeleport = false;
public static FoliaFlow instance;
public static double horizontalCoefficient;
public static double verticalCoefficient;
public static double spawnHeight;
public static double TeleportOffset;
//public static CheckSafeTeleportation checkSafeTeleportation;
public class FoliaFlow extends JavaPlugin implements Listener {
private final double vh = 0.2;
private final double vt = 0.8;
private final Vector velocity1 = new Vector(0, vh, vt);
private final Vector velocity2 = new Vector(vt, vh, 0);
private final Vector velocity3 = new Vector(0, vh, -vt);
private final Vector velocity4 = new Vector(-vt, vh, 0);
private final Vector[] velocities = {velocity1, velocity2, velocity3, velocity4};
private int counter = 0;
private final Set<Location> movingBlocks = new HashSet<>();
private final Map<Entity, Vector> velocitiesMap = new HashMap<>(); // Create a map to store velocities
private ScheduledTask task;
private ScheduledTask blockktask;
@Override
public void onEnable() {
instance = this;
register();
if (isFirstEnable) {
isFirstEnable = false;
copyDefaultConfig();
setInitialConfigValues();
}
reload();
}
super.onEnable();
private void copyDefaultConfig() {
File configFile = new File(getDataFolder(), "config.yml");
if (!configFile.exists()) {
saveResource("config.yml", false);
}
}
private void setInitialConfigValues() {
File configFile = new File(getDataFolder(), "config.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
InputStream defaultConfigStream = getResource("config.yml");
YamlConfiguration defaultConfig = YamlConfiguration.loadConfiguration(new InputStreamReader(defaultConfigStream));
config.options().copyDefaults(true);
config.setDefaults(defaultConfig);
// Get the region scheduler for the server
try {
config.save(configFile);
} catch (IOException e) {
RegionScheduler schedulerblock = getServer().getRegionScheduler();
// Schedule a repeating task to run every tick using runAtFixedRate() method
blockktask = schedulerblock.runAtFixedRate(this, Objects.requireNonNull(Bukkit.getWorld("world_the_end")), 1, 1, (schedulerTask) -> {
Block block = Objects.requireNonNull(Bukkit.getWorld("world_the_end")).getBlockAt(100, 48, 0);
if (block.getType() == Material.OBSIDIAN) {
block.setType(Material.COBBLED_DEEPSLATE_SLAB);
Slab slab = (Slab) block.getBlockData();
slab.setType(Slab.Type.BOTTOM);
block.setBlockData(slab);
}
}, 1L, 1L);
} catch (NullPointerException block) {
getServer().getLogger().info("Region Scheduler erorr (likly chunky it not load)");
}
AsyncScheduler scheduler = getServer().getAsyncScheduler();
task = scheduler.runAtFixedRate(this, (scheduledTask) -> getScheduler().runTask(this, () -> {
for (World world : Bukkit.getWorlds()) {
for (Entity entity : world.getEntities()) {
if (entity.getType() == EntityType.FALLING_BLOCK && entity.getWorld().getEnvironment() == World.Environment.THE_END) {
Location centerLoc = new Location(entity.getWorld(), 100, 48.5, 0);
Location loc = entity.getLocation();
if (loc.distance(centerLoc) <= 1) {
// Set the initial velocity of the falling block only if it doesn't have a velocity stored
if (!velocitiesMap.containsKey(entity)) {
try {
int index = counter % 4;
counter++;
Vector velocity = velocities[index];
entity.setVelocity(velocity);
velocitiesMap.put(entity, velocity); // Store the velocity in the map
movingBlocks.add(entity.getLocation()); // Add the location to the set
} catch (NullPointerException e) {
// Handle the exception here, for example:
e.printStackTrace();
getServer().getLogger().info("An error occurred: " + e.getMessage());
}
}
}
}
}
}
}), 0L, 1L, TimeUnit.MILLISECONDS);
getServer().getPluginManager().registerEvents(this, this);
getServer().getConsoleSender().sendMessage("");
getServer().getConsoleSender().sendMessage(ChatColor.GREEN + " ______________ ");
getServer().getConsoleSender().sendMessage(ChatColor.GREEN + " / ____/ ____/ /___ _ __");
getServer().getConsoleSender().sendMessage(ChatColor.GREEN + " / /_ / /_ / / __ \\ | /| / /");
getServer().getConsoleSender().sendMessage(ChatColor.GREEN + " / __/ / __/ / / /_/ / |/ |/ / ");
getServer().getConsoleSender().sendMessage(ChatColor.GREEN + "/_/ /_/ /_/\\____/|__/|__/ ");
getServer().getConsoleSender().sendMessage("");
getServer().getConsoleSender().sendMessage(ChatColor.YELLOW + "Plugin started successfully!");
getServer().getConsoleSender().sendMessage("");
}
@Override
public void onDisable() {
task.cancel();
blockktask.cancel();
super.onDisable();
debug();
}
@EventHandler
public void onFallingBlockToBlock(EntityChangeBlockEvent e){
if(e.getEntityType() == EntityType.FALLING_BLOCK){
Entity entity = e.getEntity();
Location loc = entity.getLocation();
Vector vel = entity.getVelocity();
Block movingTo = getBlockMovingTo(loc, vel);
try {
if(movingTo != null && movingTo.getType() == Material.END_PORTAL){
Location spawnLoc = movingTo.getLocation();
spawnLoc.setX(spawnLoc.getX()+0.5);
spawnLoc.setY(spawnLoc.getY()-0.25);
spawnLoc.setZ(spawnLoc.getZ()+0.5);
FallingBlock dummy = loc.getWorld().spawnFallingBlock(spawnLoc, ((FallingBlock) entity).getBlockData());
dummy.setDropItem(true);
dummy.setHurtEntities(true);
dummy.setGravity(true);
Vector dummyVel = vel.clone();
dummyVel.setY(-dummyVel.getY());
dummyVel.multiply(new Vector(2, 1, 2));
dummyVel.add(new Vector(0, 1, 0));
dummy.setVelocity(dummyVel);
}
} catch (NullPointerException dummy) {
getServer().getLogger().info("onFallingBlockToBlock erorr (likly chunky it not load)");
}
}
}
public void reload() {
saveDefaultConfig();
reloadConfig();
horizontalCoefficient = getConfig().getDouble("horizontal_coefficient");
verticalCoefficient = getConfig().getDouble("vertical_coefficient");
spawnHeight = getConfig().getDouble("spawn_height");
TeleportOffset = getConfig().getDouble("teleport_offset");
Block getBlockMovingTo(Location loc, Vector vel) {
double absMax = 0, max = 0;
char dir = ' ';
Block relative = null;
if (Math.abs(vel.getX()) > absMax) {
max = vel.getX();
absMax = Math.abs(vel.getX());
dir = 'x';
}
if (Math.abs(vel.getY()) > absMax) {
max = vel.getY();
absMax = Math.abs(vel.getY());
dir = 'y';
}
if (Math.abs(vel.getZ()) > absMax) {
max = vel.getZ();
dir = 'z';
}
switch (dir) {
case 'x' -> relative = loc.getBlock().getRelative((int) Math.signum(max), 0, 0);
case 'y' -> relative = loc.getBlock().getRelative(0, (int) Math.signum(max), 0);
case 'z' -> relative = loc.getBlock().getRelative(0, 0, (int) Math.signum(max));
}
//debug("Moving falling block from location " + loc.toString() + " to location " + dir);
return relative;
}
private void register() {
getCommand("flowreload").setExecutor(new ReloadCommand());
// checkSafeTeleportation = new CheckSafeTeleportation();
// checkSafeTeleportation.updateSafeTeleportation();
getServer().getPluginManager().registerEvents(new PortalWatcher(), this);
private void debug() {
getServer().getConsoleSender().sendMessage(ChatColor.AQUA + "[FoliaFlow] " + "Plugin stopped successfully!");
}
}

View file

@ -1,23 +0,0 @@
package xyz.hynse.foliaflow.command;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import xyz.hynse.foliaflow.FoliaFlow;
public class ReloadCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("foliaflow.reload")) return true;
try {
FoliaFlow.instance.reload();
sender.sendMessage(ChatColor.YELLOW + "FoliaFlow reloaded.");
} catch (Exception e) {
sender.sendMessage(ChatColor.RED + "Something went wrong reloading FoliaFlow, see the console for more.");
e.printStackTrace();
}
return true;
}
}

View file

@ -1,49 +0,0 @@
package xyz.hynse.foliaflow.util;
import org.yaml.snakeyaml.Yaml;
import xyz.hynse.foliaflow.FoliaFlow;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
import static org.bukkit.Bukkit.getServer;
public class CheckSafeTeleportation {
public boolean checkUnsafeEndPortalTeleportation() {
File configFile = new File(getServer().getWorldContainer(), "config/paper-global.yml");
if (!configFile.exists()) {
FoliaFlow.instance.getLogger().warning("paper-global.yml not found!");
return false;
}
try (FileInputStream fis = new FileInputStream(configFile)) {
Yaml yaml = new Yaml();
Map<String, Object> config = yaml.load(fis);
Map<String, Object> unsupportedSettings = (Map<String, Object>) config.get("unsupported-settings");
if (unsupportedSettings != null) {
Boolean setting = (Boolean) unsupportedSettings.get("allow-unsafe-end-portal-teleportation");
return setting != null && setting;
}
} catch (IOException e) {
FoliaFlow.instance.getLogger().severe("Failed to read paper-global.yml: " + e.getMessage());
}
return false;
}
// public void updateSafeTeleportation() {
// boolean safeTeleportation = checkUnsafeEndPortalTeleportation();
// if (safeTeleportation) {
// FoliaFlow.instance.isUnSafeTeleport = true;
// FoliaFlow.instance.getLogger().info("Unsafe End Portal Teleportation is true.");
// } else {
// FoliaFlow.instance.isUnSafeTeleport = false;
// FoliaFlow.instance.getLogger().info("Unsafe End Portal Teleportation is false.");
// }
// }
}

View file

@ -1,32 +0,0 @@
package xyz.hynse.foliaflow.util;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.plugin.Plugin;
public class SchedulerUtil {
private static Boolean IS_FOLIA = null;
private static boolean tryFolia() {
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
public static Boolean isFolia() {
if (IS_FOLIA == null) IS_FOLIA = tryFolia();
return IS_FOLIA;
}
public static void runLaterEntity(Entity entity, Plugin plugin, Runnable runnable, int ticks) {
if (isFolia()) {
entity.getScheduler().runDelayed(plugin, (task) -> runnable.run(), null, ticks);
} else {
Bukkit.getScheduler().runTaskLater(plugin, runnable, ticks);
}
}
}

View file

@ -1,19 +0,0 @@
package xyz.hynse.foliaflow.util;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.util.Vector;
public class VelocityUtil {
public static Block getBlockMovingTo(Location loc, Vector vel) {
double absX = Math.abs(vel.getX());
double absY = Math.abs(vel.getY());
double absZ = Math.abs(vel.getZ());
if (absX > absY && absX > absZ) {
return loc.getBlock().getRelative((int) Math.signum(vel.getX()), 0, 0);
} else if (absY > absZ) {
return loc.getBlock().getRelative(0, (int) Math.signum(vel.getY()), 0);
}
return loc.getBlock().getRelative(0, 0, (int) Math.signum(vel.getZ()));
}
}

View file

@ -1,73 +0,0 @@
package xyz.hynse.foliaflow.watcher;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FallingBlock;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityPortalEnterEvent;
import org.bukkit.util.Vector;
import xyz.hynse.foliaflow.FoliaFlow;
import xyz.hynse.foliaflow.util.SchedulerUtil;
import static xyz.hynse.foliaflow.util.VelocityUtil.getBlockMovingTo;
public class PortalWatcher implements Listener {
private static final String DUPE_TAG = "foliaflow_dupe";
@EventHandler
public void onFallingBlockToBlock(EntityChangeBlockEvent e){
if(e.getEntityType() != EntityType.FALLING_BLOCK) return;
Entity entity = e.getEntity();
if(entity.getScoreboardTags().contains(DUPE_TAG)) return;
Location loc = entity.getLocation();
Vector vel = entity.getVelocity();
Block movingTo = getBlockMovingTo(loc, vel);
if(movingTo.getType() == Material.END_PORTAL){
spawnDupe(entity, movingTo, false);
}
}
@EventHandler
public void onPortalEnter(EntityPortalEnterEvent e){
if(e.getEntityType() != EntityType.FALLING_BLOCK) return;
Entity entity = e.getEntity();
if(entity.getScoreboardTags().contains(DUPE_TAG)) return;
Block portal = e.getLocation().getBlock();
if(portal.getType() == Material.END_PORTAL && portal.getRelative(0, -1, 0).getType().name().endsWith("_FENCE")){
spawnDupe(entity, portal, true);
}
}
private void spawnDupe(Entity entity, Block portal, boolean passThrough){
Location spawnLoc = portal.getLocation();
spawnLoc.add(0.5, FoliaFlow.spawnHeight, 0.5);
FallingBlock dummy = entity.getWorld().spawnFallingBlock(spawnLoc, ((FallingBlock) entity).getBlockData());
dummy.addScoreboardTag(DUPE_TAG);
Vector dummyVel = entity.getVelocity().clone();
dummyVel.multiply(FoliaFlow.horizontalCoefficient);
if(passThrough){
dummyVel.setY(entity.getVelocity().getY());
} else {
dummyVel.setY(entity.getVelocity().getY() * FoliaFlow.verticalCoefficient);
}
dummy.setVelocity(dummyVel);
SchedulerUtil.runLaterEntity(dummy, FoliaFlow.instance, () -> {
// Portal teleportation is a bit below vanilla, so we teleport it above
dummy.teleportAsync(dummy.getLocation().add(0, FoliaFlow.TeleportOffset, 0));
dummy.setVelocity(dummyVel);
},
2
);
}
}

View file

@ -1,19 +0,0 @@
# Don't touch this file unless you know what you're doing
# Default values seems vanilla.
# If you find values that seems more vanilla please create a PR
# https://github.com/Hynse/FoliaFlow
# Default value for horizontal_coefficient
# - Folia (1.499)
# - Paper (2)
horizontal_coefficient: 1.499
# -----------------------------------------
vertical_coefficient: -1.7
spawn_height: 0.08
# Default value for teleport_offset
# - Folia (0.5)
# - Paper (2.4)
teleport_offset: 0.5
# -----------------------------------------

View file

@ -1,10 +1,5 @@
name: FoliaFlow
version: '${version}'
main: xyz.hynse.foliaflow.FoliaFlow
api-version: 26.1.2
api-version: 1.19
folia-supported: true
commands:
flowreload:
description: Reload FoliaFlow
usage: /<command>
permission: foliaflow.reload