Compare commits

..

No commits in common. "master" and "1.1-SNAPSHOT" have entirely different histories.

14 changed files with 148 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,55 +1,18 @@
# 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
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).
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
If you would like to contribute to FoliaFlow, feel free to submit a pull request with your changes. All contributions are welcome and appreciated.
If you would like to contribute to EndBlockPorter, feel free to submit a pull request with your changes. All contributions are welcome and appreciated.
## License

View file

@ -2,8 +2,9 @@ plugins {
id 'java'
}
group = 'xyz.hynse'
version = "3.0"
version = '1.1-SNAPSHOT'
repositories {
mavenCentral()
@ -11,10 +12,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,153 @@
package xyz.hynse.foliaflow;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.*;
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.world.ChunkLoadEvent;
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.HashSet;
import java.util.Set;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class FoliaFlow extends JavaPlugin implements Listener {
private final Vector velocity1 = new Vector(0, 0.5, -1);
private final Vector velocity2 = new Vector(-1, 0.5, 0);
private final Vector velocity3 = new Vector(0, 0.5, 1);
private final Vector velocity4 = new Vector(1, 0.5, 0);
private final Vector[] velocities = {velocity1, velocity2, velocity3, velocity4};
private int counter = 0;
//private final Set<Location> movingBlocks = new HashSet<>();
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;
@Override
public void onEnable() {
instance = this;
register();
if (isFirstEnable) {
isFirstEnable = false;
copyDefaultConfig();
setInitialConfigValues();
}
reload();
super.onEnable();
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("");
}
private void copyDefaultConfig() {
File configFile = new File(getDataFolder(), "config.yml");
if (!configFile.exists()) {
saveResource("config.yml", false);
@Override
public void onDisable() {
super.onDisable();
debug("Plugin stopped successfully!");
}
/*
@EventHandler
public void onChunkLoad(ChunkLoadEvent event) {
Block obsidianBlock = obsidianLocation.getBlock();
if (event.getWorld() == endWorld && obsidianBlock.getType() == Material.OBSIDIAN) { // check if the chunk is in the end and the block is obsidian
obsidianBlock.setType(Material.AIR); // set the block to air
}
}
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);
try {
config.save(configFile);
} catch (IOException e) {
e.printStackTrace();
@EventHandler
public void onBlockChange(org.bukkit.event.block.BlockFromToEvent event) {
if (event.getBlock().getLocation().equals(obsidianLocation)) { // check if the block change event is for the obsidian block location
event.setCancelled(true); // cancel the event to prevent the obsidian block from changing
}
}*/
@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);
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(false);
dummy.setHurtEntities(false);
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);
}
}
}
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");
@EventHandler
public void onChunkLoadend(ChunkLoadEvent e) {
Chunk chunk = e.getChunk();
World world = chunk.getWorld();
if (world.getEnvironment() == World.Environment.THE_END) {
// Iterate through all the entities in the chunk
for (Entity entity : chunk.getEntities()) {
if (entity.getType() == EntityType.FALLING_BLOCK) {
Location loc = entity.getLocation();
debug("Falling block spawned at location " + loc);
// Set the initial velocity of the falling block
int index = counter % 4;
counter ++;
Vector velocity = velocities[index];
entity.setVelocity(velocity);
// Remove the block from the movingBlocks set after a delay, to prevent it from being immediately moved again
//getServer().getScheduler().runTaskLater(this, () -> movingBlocks.remove(loc.getBlock().getLocation()), 20L);
}
}
}
}
private void register() {
getCommand("flowreload").setExecutor(new ReloadCommand());
// checkSafeTeleportation = new CheckSafeTeleportation();
// checkSafeTeleportation.updateSafeTeleportation();
getServer().getPluginManager().registerEvents(new PortalWatcher(), this);
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 debug(String message) {
getServer().getConsoleSender().sendMessage(ChatColor.AQUA + "[FoliaFlow] " + message);
}
}

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
folia-supported: true
commands:
flowreload:
description: Reload FoliaFlow
usage: /<command>
permission: foliaflow.reload
api-version: 1.19
folia-supported: true