Compare commits

..

No commits in common. "master" and "Download" have entirely different histories.

14 changed files with 179 additions and 345 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,51 +1,19 @@
# THIS IS NOT MY PLUGIN, I JUST EDITED ONE SINGLE LINE IN PLUGIN.YML, THE ORIGINAL IS AT: https://github.com/MidnightTale/FoliaFlow
# 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 again in Paper and Folia
FoliaFlow is a Minecraft plugin that allows players to using gravity block duplication glitch again in folia (paper soon)
## 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)
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 lost its velocity. To fix this, we added the velocity back when the entity was in the end. Another issue we faced was that the entity would instantly turn into a block upon teleportation because it have block below. To solve this, we made the center block of the spawn platform a slab, ensuring that the entity stays in its falling state.
## 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

@ -3,7 +3,7 @@ plugins {
}
group = 'xyz.hynse'
version = "3.0"
version = "1.7"
repositories {
mavenCentral()
@ -14,7 +14,7 @@ repositories {
}
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,182 @@
package xyz.hynse.foliaflow;
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
import io.papermc.paper.threadedregions.scheduler.RegionScheduler;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.Slab;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.BlockDisplay;
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 xyz.hynse.foliaflow.command.ReloadCommand;
import xyz.hynse.foliaflow.util.CheckSafeTeleportation;
import xyz.hynse.foliaflow.watcher.PortalWatcher;
import org.bukkit.util.Vector;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
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);
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;
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<>();
@Override
public void onEnable() {
instance = this;
register();
if (isFirstEnable) {
isFirstEnable = false;
copyDefaultConfig();
setInitialConfigValues();
super.onEnable();
RegionScheduler schedulerblock = getServer().getRegionScheduler();
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);
GlobalRegionScheduler schedulervelocity = this.getServer().getGlobalRegionScheduler();
schedulervelocity.runAtFixedRate(this, (scheduledTask) -> {
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) {
if (!velocitiesMap.containsKey(entity)) {
int index = counter % 4;
counter++;
Vector velocity = velocities[index];
entity.setVelocity(velocity);
velocitiesMap.put(entity, velocity);
movingBlocks.add(entity.getLocation());
}
}
}
}
}
}, 20L, 1L);
File dataFile = new File(getDataFolder(), "data.yml");
YamlConfiguration config = YamlConfiguration.loadConfiguration(dataFile);
boolean entitySpawned = config.getBoolean("entity_spawned", false);
if (!entitySpawned) {
RegionScheduler schedulerdisplay = getServer().getRegionScheduler();
String tag = "FoliaFlow_Display";
schedulerdisplay.run(this, Objects.requireNonNull(Bukkit.getWorld("world_the_end")), 1, 1, (schedulerTask) -> {
World endWorld = getServer().getWorld("world_the_end");
assert endWorld != null;
Chunk chunk = endWorld.getChunkAt(0, 0);
if (!chunk.isLoaded()) {
chunk.load();
getLogger().info("Loaded Chunk");
}
boolean displayExists = endWorld.getEntitiesByClass(BlockDisplay.class).stream()
.anyMatch(entity -> entity.getScoreboardTags().contains(tag));
getLogger().info("Exist BlockDisplay" + "(" + tag + ")");
if (!displayExists) {
BlockDisplay display = (BlockDisplay) endWorld.spawnEntity(new Location(endWorld, 100.0005, 48, -0.0005), EntityType.BLOCK_DISPLAY);
display.setBlock(Bukkit.createBlockData(Material.OBSIDIAN));
display.addScoreboardTag(tag);
getLogger().info("Setup BlockDisplay" + "(" + tag + ") " + display);
config.set("entity_spawned", true);
try {
config.save(dataFile);
} catch (IOException e) {
getLogger().warning("Failed to save plugin data file");
}
}
});
}
reload();
getServer().getPluginManager().registerEvents(this, this);
}
@Override
public void onDisable() {
super.onDisable();
}
private void copyDefaultConfig() {
File configFile = new File(getDataFolder(), "config.yml");
if (!configFile.exists()) {
saveResource("config.yml", false);
@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 error (likely chunky it not load)");
}
}
}
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();
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));
}
return relative;
}
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");
}
private void register() {
getCommand("flowreload").setExecutor(new ReloadCommand());
// checkSafeTeleportation = new CheckSafeTeleportation();
// checkSafeTeleportation.updateSafeTeleportation();
getServer().getPluginManager().registerEvents(new PortalWatcher(), this);
}
}
}

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

@ -0,0 +1,5 @@
name: FoliaFlow
version: '${version}'
main: xyz.hynse.foliaflow.FoliaFlow
api-version: 1.19
folia-supported: true

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