Compare commits

...

71 Commits

Author SHA1 Message Date
Ruakij
c1dbe281a6 Preserve pitch and yaw from player 2021-05-11 12:55:01 +02:00
Ruakij
8485e34756 Added config-option beacon 2021-05-11 12:50:16 +02:00
Ruakij
7e6601d56d Implemented config-option id 2021-05-11 12:46:03 +02:00
Ruakij
982190b730 Implemented config-option locationCheck 2021-05-11 12:42:42 +02:00
Ruakij
4626646292 Implemented config-option autosave 2021-05-11 12:41:09 +02:00
Ruakij
e82de277ef Added config-options 2021-05-11 12:39:34 +02:00
Ruakij
28658329a8 Save on shutdown added 2021-05-11 12:08:00 +02:00
Ruakij
ac810349ac Fixed saving not working 2021-05-11 11:48:39 +02:00
Ruakij
2a713d269e Delete list when empty 2021-05-11 11:45:06 +02:00
Ruakij
b20e0a03fd Added Autosave 2021-05-11 11:42:46 +02:00
Ruakij
5a1c809d89 Changed save-system 2021-05-11 11:42:05 +02:00
Ruakij
ef9643c2ae Fixed loading not writing blocks to list 2021-05-11 11:30:01 +02:00
Ruakij
c732aa31b1 Set player to ignore-list if teleport didnt succeed 2021-05-11 11:10:24 +02:00
Ruakij
51c9ee0716 Fix first placed block having a different list leading to new linked-blocks being out-of-sync
(teleport not working and breaking leading to unexpected and undesired states)
2021-05-11 11:03:44 +02:00
Ruakij
e10eaf9b66 Fix system trying to gather non-existent data to display message 2021-05-11 11:02:30 +02:00
Ruakij
686ad312c5 Removed upcasting, check is done on reference-layer anyways 2021-05-11 09:53:57 +02:00
Ruakij
973897cc3e Notify player when teleport could not succeed 2021-05-11 09:53:30 +02:00
Ruakij
1eb472b576 Added check when no safe-location could be found 2021-05-11 09:52:22 +02:00
Ruakij
c41ab95baf Added comments 2021-05-11 09:45:50 +02:00
Ruakij
5e22456f61 Fixed empty-space search not working, because of missing ignore 2021-05-11 09:45:25 +02:00
Ruakij
2bda948c8f Fixed CustomMoveEvent firing all the time instead of only on Block-change 2021-05-11 09:37:10 +02:00
Ruakij
6c2e06afaf Changed data.yml format and added save-method 2021-05-10 16:15:56 +02:00
Ruakij
b54af93d4b Made Manager static 2021-05-10 16:15:07 +02:00
Ruakij
1168b8859a Changed data-yml format 2021-05-10 15:45:48 +02:00
Ruakij
b8ed619b1c Implemented search for safe-location on target-beacon 2021-05-10 15:42:44 +02:00
Ruakij
1ab17c1ab6 Added overloaded-alternative-method searchForMaterial 2021-05-10 15:42:22 +02:00
Ruakij
fdc17aad0f Fixed logic 2021-05-10 15:29:37 +02:00
Ruakij
bf18c82d6d Fixed broken if-statements 2021-05-10 15:27:29 +02:00
Ruakij
2f64eb5ed0 Added player-messages 2021-05-10 15:23:29 +02:00
Ruakij
cf061f9d75 Migrated logic to objects 2021-05-10 15:15:25 +02:00
Ruakij
b593a22568 Moved code to objects 2021-05-10 14:51:14 +02:00
Ruakij
884184006c Added player to ignoreList even on unsuccessful teleport 2021-05-10 14:30:49 +02:00
Ruakij
41a15103b3 Fixed List having wrong Type 2021-05-10 14:24:29 +02:00
Ruakij
b010280111 Fixed player being removed from ignoreList directly after teleport. 2021-05-10 14:23:53 +02:00
Ruakij
63bab8ae2e Fixed misplaced FIXME comment 2021-05-10 14:19:27 +02:00
Ruakij
3d602c526d Implemented partner-list saved on LinkedBeaconTeleporter 2021-05-10 14:18:11 +02:00
Ruakij
f03a80cf99 Implemented teleporting 2021-05-10 14:02:20 +02:00
Ruakij
51e22f2f9e Moved code to normal listeners 2021-05-10 14:01:38 +02:00
Ruakij
3695315d42 Added searchForMaterial Function and List of transparentMaterials 2021-05-10 14:00:55 +02:00
Ruakij
b819fcb9f5 Added proper api-version-tag 2021-05-10 14:00:16 +02:00
Ruakij
ddb6525c40 Implemented CustomPlayerMoveEvent that only fires on certain conditions and only checks every 10ticks 2021-05-10 13:36:52 +02:00
Ruakij
c0917a1ab6 Switched to proper Crafting-mechanics 2021-05-10 11:58:37 +02:00
Ruakij
3d757a6ccf LinkedBeaconTeleporterItem generates own ItemStack 2021-05-10 10:36:26 +02:00
Ruakij
a296a190c6 Added Gamemode-check 2021-05-10 10:21:16 +02:00
Ruakij
800032f530 Fixed list not getting written to HashMap 2021-05-10 10:21:06 +02:00
Ruakij
3df5c9d4ac Implemented placing of LinkedBeaconTeleporterItem 2021-05-10 09:58:56 +02:00
Ruakij
d9c95a5e53 Implemented breaking of LinkedBeaconTeleporterBlock and dropping LinkedBeaconTeleporterItem 2021-05-10 09:58:24 +02:00
Ruakij
3f73d15a5a Commended search for existing LinkedBeaconTeleporterItem
(this will lead to more than only 2 linked items)
2021-05-10 00:10:47 +02:00
Ruakij
de1c2816a2 Added missing import 2021-05-10 00:10:01 +02:00
Ruakij
4efa26fe0e Added null-check for lore 2021-05-10 00:09:28 +02:00
Ruakij
8889a16bdc Fixed regex-generation 2021-05-10 00:09:12 +02:00
Ruakij
f8c7672cfa Fixed not using ItemMeta 2021-05-10 00:08:45 +02:00
Ruakij
cb4adc3bc1 Fixed missing ItemMeta assignment 2021-05-10 00:08:25 +02:00
Ruakij
6a4369c527 Fixed Wrong Method-Arguments 2021-05-10 00:07:52 +02:00
Ruakij
a7a8a4b037 Implemented linking of beacons in crafting 2021-05-09 23:24:04 +02:00
Ruakij
b1169f48db Ability to create new LinkedBeaconTeleporterItem 2021-05-09 23:15:25 +02:00
Ruakij
efb18aa711 Fixed spelling :/ 2021-05-09 23:06:01 +02:00
Ruakij
0b538db2a4 Implemented check to detect attempt to place LinkedBeaconTeleporterItem 2021-05-09 23:01:27 +02:00
Ruakij
90443d51f7 Fixed Item returning wrong class 2021-05-09 22:59:46 +02:00
Ruakij
69fcab7bbc Implemented check to detect attempt to break LinkedBeaconTeleporterBlock 2021-05-09 22:55:40 +02:00
Ruakij
376695b466 Implemented check to detect attempt to link 2 beacons 2021-05-09 22:50:54 +02:00
Ruakij
da05087876 Implemented Block-Location de/serialisation 2021-05-09 22:47:10 +02:00
Ruakij
2f621d7a9b Implemented getter for LinkedBeaconTeleporterBlock from Location and teleportId 2021-05-09 22:46:18 +02:00
Ruakij
59e8768ddb Implemented conversion between ItemStack and LinkedBeaconTeleporterItem 2021-05-09 22:40:18 +02:00
Ruakij
48f961fc9c Added Manager for storing Data related to id and location 2021-05-09 22:36:25 +02:00
Ruakij
16a46a6a35 Implemented Objects to work with 2021-05-09 22:00:12 +02:00
Ruakij
abde30e2e1 Implement first Listeners 2021-05-09 21:38:33 +02:00
Ruakij
87d6d4bd70 Created first config with fields 2021-05-09 21:35:24 +02:00
Ruakij
bcd147052c Added static variable for logger-access 2021-05-09 21:07:23 +02:00
Ruakij
92718de5a9 Initialising project 2021-05-09 19:10:10 +02:00
Ruakij
a850972224 Added Maven with papermc 2021-05-09 18:43:05 +02:00
16 changed files with 1139 additions and 0 deletions

45
pom.xml Normal file
View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>eu.ruekov.ruakij</groupId>
<artifactId>LinkedBeaconTeleporters</artifactId>
<version>1.0</version>
<properties>
<author>Ruakij</author>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>papermc</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.destroystokyo.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.16.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>

View File

@@ -0,0 +1,155 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.util.Vector;
import java.util.*;
public class Function {
public static String serialiseBlockLocation(Location loc){
return loc.getWorld().getName()+";"+loc.getBlockX()+";"+loc.getBlockY()+";"+loc.getBlockZ();
}
public static Location deserializeBlockLocation(String serialisedLoc) throws InvalidPropertiesFormatException {
try{
String[] locData = serialisedLoc.split(";");
World world = Bukkit.getWorld(locData[0]);
int x = Integer.parseInt(locData[1]);
int y = Integer.parseInt(locData[2]);
int z = Integer.parseInt(locData[3]);
return new Location(world, x, y, z);
}catch(Exception ex){
throw new InvalidPropertiesFormatException("Could not deserialize BlockLocation '"+ serialisedLoc +"'");
}
}
public static String randomString(String alphabet, int length){
char[] alphabetChars = alphabet.toCharArray();
String str = "";
Random random = new Random();
for(int i=0; i<length; i++){
str += alphabetChars[random.nextInt(alphabet.length())];
}
return str;
}
public static List<Material> transparentMaterials = Arrays.asList(
Material.AIR,
Material.GLASS,
Material.GLASS_PANE,
Material.BLACK_STAINED_GLASS,
Material.BLACK_STAINED_GLASS_PANE,
Material.BLUE_STAINED_GLASS,
Material.BLUE_STAINED_GLASS_PANE,
Material.BROWN_STAINED_GLASS,
Material.BROWN_STAINED_GLASS_PANE,
Material.CYAN_STAINED_GLASS,
Material.CYAN_STAINED_GLASS_PANE,
Material.GRAY_STAINED_GLASS,
Material.GRAY_STAINED_GLASS_PANE,
Material.GREEN_STAINED_GLASS,
Material.GREEN_STAINED_GLASS_PANE,
Material.LIGHT_BLUE_STAINED_GLASS,
Material.LIGHT_BLUE_STAINED_GLASS_PANE,
Material.LIGHT_GRAY_STAINED_GLASS,
Material.LIGHT_GRAY_STAINED_GLASS_PANE,
Material.LIME_STAINED_GLASS,
Material.LIME_STAINED_GLASS_PANE,
Material.MAGENTA_STAINED_GLASS,
Material.MAGENTA_STAINED_GLASS_PANE,
Material.ORANGE_STAINED_GLASS,
Material.ORANGE_STAINED_GLASS_PANE,
Material.PINK_STAINED_GLASS,
Material.PINK_STAINED_GLASS_PANE,
Material.PURPLE_STAINED_GLASS,
Material.PURPLE_STAINED_GLASS_PANE,
Material.RED_STAINED_GLASS,
Material.RED_STAINED_GLASS_PANE,
Material.WHITE_STAINED_GLASS,
Material.WHITE_STAINED_GLASS_PANE,
Material.YELLOW_STAINED_GLASS,
Material.YELLOW_STAINED_GLASS_PANE,
Material.PISTON,
Material.PISTON_HEAD,
Material.MOVING_PISTON,
Material.STICKY_PISTON,
Material.ACACIA_LEAVES,
Material.BIRCH_LEAVES,
Material.DARK_OAK_LEAVES,
Material.JUNGLE_LEAVES,
Material.OAK_LEAVES,
Material.SPRUCE_LEAVES,
Material.ACACIA_SLAB,
Material.ANDESITE_SLAB,
Material.BIRCH_SLAB,
Material.BLACKSTONE_SLAB,
Material.BRICK_SLAB,
Material.COBBLESTONE_SLAB,
Material.CRIMSON_SLAB,
Material.CUT_RED_SANDSTONE_SLAB,
Material.CUT_SANDSTONE_SLAB,
Material.DARK_OAK_SLAB,
Material.DARK_PRISMARINE_SLAB,
Material.DIORITE_SLAB,
Material.END_STONE_BRICK_SLAB,
Material.GRANITE_SLAB,
Material.JUNGLE_SLAB,
Material.MOSSY_COBBLESTONE_SLAB,
Material.MOSSY_STONE_BRICK_SLAB,
Material.NETHER_BRICK_SLAB,
Material.OAK_SLAB,
Material.PETRIFIED_OAK_SLAB,
Material.POLISHED_ANDESITE_SLAB,
Material.POLISHED_BLACKSTONE_BRICK_SLAB,
Material.POLISHED_BLACKSTONE_SLAB,
Material.POLISHED_DIORITE_SLAB,
Material.POLISHED_GRANITE_SLAB,
Material.PRISMARINE_BRICK_SLAB,
Material.PRISMARINE_SLAB,
Material.PURPUR_SLAB,
Material.QUARTZ_SLAB,
Material.RED_NETHER_BRICK_SLAB,
Material.RED_SANDSTONE_SLAB,
Material.SANDSTONE_SLAB,
Material.SMOOTH_QUARTZ_SLAB,
Material.SMOOTH_RED_SANDSTONE_SLAB,
Material.SMOOTH_SANDSTONE_SLAB,
Material.SMOOTH_STONE_SLAB,
Material.SPRUCE_SLAB,
Material.STONE_BRICK_SLAB,
Material.STONE_SLAB,
Material.WARPED_SLAB
);
public static Block searchForMaterial(Location startLoc, Vector searchDirection, Material searchMaterial){
return searchForMaterial(startLoc, searchDirection, searchMaterial, new ArrayList<>());
}
public static Block searchForMaterial(Location startLoc, Vector searchDirection, Material searchMaterial, List<Material> ignoreMaterials){
Location loc = new Location(startLoc.getWorld(), startLoc.getBlockX(), startLoc.getBlockY(), startLoc.getBlockZ());
for(int i=0; loc.getBlockY()>=0 && loc.getBlockY()<=255; loc.add(searchDirection)){
Block block = loc.getBlock();
// Check for correct material
if(block.getType() == searchMaterial) return block;
// Check for non-ignore-block
boolean found = false;
for(Material ignoreMaterial : ignoreMaterials){
if(block.getType() == ignoreMaterial){
found = true;
break;
}
}
// If not found, searchMaterial not found
if(!found) return null;
}
// Reached 0 or 255, searchMaterial not found
return null;
}
}

View File

@@ -0,0 +1,101 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.customPlayerMoveEvent.CustomPlayerMoveEventHandler;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterManager;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.listener.OnBlockBreak;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.listener.OnBlockPlace;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.listener.OnCraftItemEvent;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.listener.OnCustomPlayerMove;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.logging.Logger;
public class Main extends JavaPlugin {
public static Plugin plugin;
public static FileConfiguration config;
public static FileConfiguration data;
public static Logger log;
public void onEnable() {
log = getLogger();
plugin = this;
PluginManager pluginManager = Bukkit.getPluginManager();
pluginManager.registerEvents(new OnBlockBreak(), this);
pluginManager.registerEvents(new OnBlockPlace(), this);
pluginManager.registerEvents(new OnCraftItemEvent(), this);
loadConfigs();
CustomPlayerMoveEventHandler cpmHandler = new CustomPlayerMoveEventHandler(this, config.getInt("locationCheck.interval"), true);
cpmHandler.registerListener(new OnCustomPlayerMove());
LinkedBeaconTeleporterManager.init();
initAutoSave();
log.info("Plugin activated");
}
public void onDisable() {
saveData();
log.info("Plugin deactivated");
}
public void loadConfigs() {
// config.yml
this.saveDefaultConfig();
config = this.getConfig();
// data.yml
try{
File dataFile = new File("plugins/"+ plugin.getName() +"/data.yml");
dataFile.createNewFile();
data = YamlConfiguration.loadConfiguration(
dataFile
);
}catch (Exception ex){
log.severe("Could not load/create data.yml!");
ex.printStackTrace();
Bukkit.getPluginManager().disablePlugin(this);
}
}
public static void saveData(){
boolean lbtDataChanged = LinkedBeaconTeleporterManager.writeData();
// Only run save, when data changed
if(lbtDataChanged)
saveFiles();
}
public static void saveFiles() {
// data.yml
try{
File dataFile = new File("plugins/"+ plugin.getName() +"/data.yml");
data.save(dataFile);
}catch (Exception ex){
log.severe("Could not save data.yml!");
ex.printStackTrace();
}
}
static void initAutoSave(){
int autosaveInterval = config.getInt("config.interval")*20;
Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () -> {
saveData();
}, autosaveInterval, autosaveInterval);
}
}

View File

@@ -0,0 +1,33 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.customPlayerMoveEvent;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class CustomPlayerMoveEvent {
Player p;
Location loc;
Location oldLoc;
protected double distance;
public CustomPlayerMoveEvent(Player p, Location loc, Location oldLoc){
this.p = p;
this.loc = loc;
this.oldLoc = oldLoc;
}
public Player player(){
return p;
}
public Location location(){
return loc;
}
public Location oldLocation(){
return oldLoc;
}
public double distance(){
return distance;
}
}

View File

@@ -0,0 +1,91 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.customPlayerMoveEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
public class CustomPlayerMoveEventHandler {
List<CustomPlayerMoveEventListener> listeners = new ArrayList<>();
HashMap<UUID, Location> oldPlayerLoc = new HashMap<>();
boolean locationChangeOnBlockChange;
public CustomPlayerMoveEventHandler(Plugin plugin, int interval, boolean locationChangeOnBlockChange){
this.locationChangeOnBlockChange = locationChangeOnBlockChange;
startRunnable(plugin, interval);
}
public CustomPlayerMoveEventHandler(Plugin plugin){
this(plugin, 5, false);
}
void startRunnable(Plugin plugin, int interval){
Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () -> {
// Dont do anything without listeners
if(listeners.size() == 0) return;
// Check all players
for(Player p : Bukkit.getOnlinePlayers()){
UUID uuid = p.getUniqueId();
Location loc = p.getLocation();
// Get old-location
Location oldLoc = oldPlayerLoc.get(uuid);
// Create data-obj
CustomPlayerMoveEvent e = new CustomPlayerMoveEvent(p, loc, oldLoc);
// When player has an old-location
if(oldLoc != null){
if(!locationChangeOnBlockChange){
double distance = loc.distance(oldLoc);
e.distance = distance;
if(distance > 0)
locationChangeListeners(e);
}
else if(loc.getBlockX() != oldLoc.getBlockX() ||
loc.getBlockY() != oldLoc.getBlockY() ||
loc.getBlockZ() != oldLoc.getBlockZ())
locationChangeListeners(e);
}
tickListeners(e);
// Save old location
oldPlayerLoc.put(uuid, loc);
}
}, interval, interval);
}
boolean blockLocationChanged(Location loc, Location oldLoc){
return loc.getBlockX() != oldLoc.getBlockX() ||
loc.getBlockY() != oldLoc.getBlockY() ||
loc.getBlockZ() != oldLoc.getBlockZ();
}
void tickListeners(CustomPlayerMoveEvent e){
for(CustomPlayerMoveEventListener listener : listeners){
listener.tick(e);
}
}
void locationChangeListeners(CustomPlayerMoveEvent e){
for(CustomPlayerMoveEventListener listener : listeners){
listener.locationChange(e);
}
}
public void registerListener(CustomPlayerMoveEventListener listener){
listeners.add(listener);
}
}

View File

@@ -0,0 +1,10 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.customPlayerMoveEvent;
import org.bukkit.entity.Player;
public interface CustomPlayerMoveEventListener {
void tick(CustomPlayerMoveEvent e);
void locationChange(CustomPlayerMoveEvent e);
}

View File

@@ -0,0 +1,46 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Function;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import org.bukkit.Location;
import java.util.ArrayList;
import java.util.List;
/**
* Describes a placed-beacon-teleporter in the world
*/
public abstract class LinkedBeaconTeleporter {
static String id_alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
static int id_length = 10;
// Persistent id for linked-beacons
public String teleporterId;
// List of all linkedBeaconTeleporters with same teleporterId (real Type is usually ..Block, because linked Items are temporary constructs are useless)
protected List<LinkedBeaconTeleporter> linkedBeaconTeleporters = new ArrayList<>();
LinkedBeaconTeleporter(){
this.teleporterId = Function.randomString(id_alphabet, id_length);
linkedBeaconTeleporters = new ArrayList<>();
}
public LinkedBeaconTeleporter(String teleporterId){
this.teleporterId = teleporterId;
// Check if id exists
linkedBeaconTeleporters = LinkedBeaconTeleporterManager.placedLBTsById.get(this.teleporterId());
if(linkedBeaconTeleporters == null){
// Create empty if not found
linkedBeaconTeleporters = new ArrayList<>();
}
}
public String teleporterId(){
return teleporterId;
}
public List<LinkedBeaconTeleporter> linkedBeaconTeleporters(){
return linkedBeaconTeleporters;
}
}

View File

@@ -0,0 +1,79 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Function;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockBreakEvent;
import java.util.List;
public class LinkedBeaconTeleporterBlock extends LinkedBeaconTeleporter {
// FIXME: Storing the block like this will block the world from unloading and might be dangerous
Block block;
public LinkedBeaconTeleporterBlock(String teleporterId, Block block) {
super(teleporterId);
this.block = block;
}
public Block block(){
return block;
}
public LinkedBeaconTeleporterItem break_(BlockBreakEvent e){
Location loc = this.block().getLocation();
// Dont drop anything
e.setDropItems(false);
e.setExpToDrop(0);
// Notify Player when link was destroyed
if(this.linkedBeaconTeleporters.size() == 2){
e.getPlayer().sendMessage("§cConnection to Teleporter with id §7"+ this.teleporterId +" §e("+
(int)((LinkedBeaconTeleporterBlock)this.linkedBeaconTeleporters.get(0)).block.getLocation().distance(
((LinkedBeaconTeleporterBlock)this.linkedBeaconTeleporters.get(1)).block().getLocation()
)
+" Blocks away) §cdestroyed");
}
// Remove from list
this.linkedBeaconTeleporters.remove(this);
if(this.linkedBeaconTeleporters.size() == 0){
// List empty, delete from placedLBTsById
LinkedBeaconTeleporterManager.placedLBTsById.remove(
this.teleporterId
);
}
// Remove from loc
LinkedBeaconTeleporterManager.placedLBTByLoc.remove(
Function.serialiseBlockLocation(loc)
);
// Item from block
LinkedBeaconTeleporterItem lbtItem = new LinkedBeaconTeleporterItem(this.teleporterId());
// Drop custom-item
if(e.getPlayer().getGameMode() != GameMode.CREATIVE)
loc.getWorld().dropItemNaturally(
loc.add(0.5, 0, 0.5),
lbtItem.item()
);
return lbtItem;
}
// Conversion methods
public static LinkedBeaconTeleporterBlock getFromLocation(Location loc){
return LinkedBeaconTeleporterManager.getLbtBlockFromLocation(loc);
}
public static List<LinkedBeaconTeleporter> getListFromTeleportId(String teleportId){
return LinkedBeaconTeleporterManager.getLbtBlocksFromTeleportId(teleportId);
}
}

View File

@@ -0,0 +1,97 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Function;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LinkedBeaconTeleporterItem extends LinkedBeaconTeleporter {
// INFO: Safe to store as its always cloned by bukkit
ItemStack item;
public LinkedBeaconTeleporterItem(){
// Create a new LinkedBeaconTeleporter
super();
this.item = LinkedBeaconTeleporterManager.getItemStackFromData(this.teleporterId);
}
public LinkedBeaconTeleporterItem(String teleporterId, ItemStack item) {
super(teleporterId);
this.item = item;
}
public LinkedBeaconTeleporterItem(String teleporterId){
super(teleporterId);
this.item = LinkedBeaconTeleporterManager.getItemStackFromData(teleporterId);
}
public ItemStack item(){
return item;
}
public LinkedBeaconTeleporterBlock place(BlockPlaceEvent e){
// Deny placing when 2 LinkedBeaconTeleporter's are already placed
if(this.linkedBeaconTeleporters.size() == 2){
e.getPlayer().sendMessage("§cMaximum-Amount §7(2) §cof §6LinkedBeaconTeleporters §cwith id §7"+ this.teleporterId +" §care already placed");
e.setCancelled(true);
return null;
}
Block block = e.getBlock();
Location loc = block.getLocation();
// Block from item
LinkedBeaconTeleporterBlock lbtBlock = new LinkedBeaconTeleporterBlock(this.teleporterId(), block);
// Both objects have different lists (as both are new), overwrite block-list with item-list
// FIXME: This seems like a bad design.. maybe only create the list when necessary? (e.g. keep null if no linked objects found)
lbtBlock.linkedBeaconTeleporters = this.linkedBeaconTeleporters;
// Add to list
this.linkedBeaconTeleporters.add(lbtBlock);
// Add to id if not exists
if(!LinkedBeaconTeleporterManager.placedLBTsById.containsKey(this.teleporterId))
LinkedBeaconTeleporterManager.placedLBTsById.put(this.teleporterId, this.linkedBeaconTeleporters);
// Add to location
LinkedBeaconTeleporterManager.placedLBTByLoc.put(
Function.serialiseBlockLocation(loc),
lbtBlock
);
// Notify Player when no other teleporter was found (yet?)
if(this.linkedBeaconTeleporters.size() == 1){
e.getPlayer().sendMessage("§6No other Teleporter found with with id §7"+ this.teleporterId);
}
// Notify Player when we have a full link
else if(this.linkedBeaconTeleporters.size() == 2){
e.getPlayer().sendMessage("§aConnected to Teleporter with id §7"+ this.teleporterId +" §e("+
(int)((LinkedBeaconTeleporterBlock)this.linkedBeaconTeleporters.get(0)).block.getLocation().distance(
((LinkedBeaconTeleporterBlock)this.linkedBeaconTeleporters.get(1)).block().getLocation()
)
+" Blocks away)");
}
return lbtBlock;
}
// Conversion methods
public static LinkedBeaconTeleporterItem getFromItemStack(ItemStack itemStack){
return LinkedBeaconTeleporterManager.getLbtItemFromItemStack(itemStack);
}
}

View File

@@ -0,0 +1,226 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Function;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapelessRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LinkedBeaconTeleporterManager {
// Stores all placed Beacon-Teleporters for fast access
// TODO: Evaluate necessity of 2 HashMaps with main reason of performance
public static HashMap<String, List<LinkedBeaconTeleporter>> placedLBTsById = new HashMap();
public static HashMap<String, LinkedBeaconTeleporterBlock> placedLBTByLoc = new HashMap();
// Regex to match item-name&lore and extract id (group 1)
static String regex;
public static void init(){
Main.log.info("Loading LinkedBeaconTeleporter from config..");
// Construct search item-regex
regex = constructRegex(
Main.config.getString("item.name"),
Main.config.getStringList("item.lore")
);
// Load settings
LinkedBeaconTeleporter.id_alphabet = Main.config.getString("id.alphabet");
LinkedBeaconTeleporter.id_length = Main.config.getInt("id.length");
// Construct & add crafting-receipes
constructAndAddRecipes();
// Load teleporters
for(String teleporterId : Main.data.getKeys(false)){
List<String> serialisedLocs = Main.data.getStringList(teleporterId);
// New list for this id
List<LinkedBeaconTeleporter> linkedBeaconTeleporters = new ArrayList();
for(String serializedLoc : serialisedLocs) {
// Load location
Location loc;
try {
loc = Function.deserializeBlockLocation(serializedLoc);
} catch (InvalidPropertiesFormatException e) {
Main.log.severe("Could not load location='"+ serializedLoc +"' from "+ teleporterId);
continue;
}
// Check if block is of type Beacon (in case the world was changed without the plugin running)
Block block = loc.getBlock();
if(block.getType() != Material.BEACON){
// Data out of sync! Skipping
Main.log.warning(teleporterId +" at location "+ serializedLoc +" changed and is no longer LinkedBlockTeleporter! (Changed without the plugin running?)");
continue;
}
// Construct block
LinkedBeaconTeleporterBlock lbtBlock = new LinkedBeaconTeleporterBlock(teleporterId, block);
// Write reference of list
lbtBlock.linkedBeaconTeleporters = linkedBeaconTeleporters;
// Write block to list
linkedBeaconTeleporters.add(lbtBlock);
// Save to loc-list
placedLBTByLoc.put(serializedLoc, lbtBlock);
}
// Save list to id-list
placedLBTsById.put(teleporterId, linkedBeaconTeleporters);
}
Main.saveData();
Main.log.info("All done!");
}
static int oldDataHashCode;
public static boolean writeData(){
// Check if data changed
int dataHashCode = placedLBTsById.hashCode();
if(oldDataHashCode != dataHashCode){
// Changed
oldDataHashCode = dataHashCode;
}
else // Did not change
return false;
Main.data = new YamlConfiguration();
for(String teleporterId : placedLBTsById.keySet()){
List<LinkedBeaconTeleporter> LBTs = placedLBTsById.get(teleporterId);
// Generate clean array with data we want
List<String> dataList = new ArrayList<>();
for(LinkedBeaconTeleporter lbt : LBTs){
dataList.add(
Function.serialiseBlockLocation(
((LinkedBeaconTeleporterBlock)lbt).block().getLocation()
)
);
}
Main.data.set(teleporterId, dataList);
}
return true;
}
static void constructAndAddRecipes(){
// Create result-item
ItemStack item = getItemStackFromData("-");
item.setAmount(2);
// Create recipe
ShapelessRecipe recipe = new ShapelessRecipe(
new NamespacedKey(Main.plugin, "linked_beacon_teleporter")
, item);
recipe.addIngredient(2, Material.BEACON);
Bukkit.addRecipe(recipe);
// Empty recipe to reset beacon
ShapelessRecipe recipe2 = new ShapelessRecipe(
new NamespacedKey(Main.plugin, "linked_beacon_teleporter_reset"),
new ItemStack(Material.BEACON)
);
recipe2.addIngredient(1, Material.BEACON);
Bukkit.addRecipe(recipe2);
}
// Conversion-methods
public static ItemStack getItemStackFromData(String teleporterId){
ItemStack item = new ItemStack(Material.BEACON);
ItemMeta itemMeta = item.getItemMeta();
// Get config-values
String name = Main.config.getString("item.name");
List<String> lore = Main.config.getStringList("item.lore");
// Replace parameters
name = name.replace("%id%", teleporterId);
for(int i=0; i<lore.size(); i++){
lore.set(i,
lore.get(i).replace("%id%", teleporterId)
);
}
// Set meta
itemMeta.setDisplayName(name);
itemMeta.setLore(lore);
item.setItemMeta(itemMeta);
return item;
}
public static LinkedBeaconTeleporterItem getLbtItemFromItemStack(ItemStack itemStack){
ItemMeta itemMeta = itemStack.getItemMeta();
// Serialize
String nameAndLore = serialiseBeaconItem(
itemMeta.getDisplayName(),
itemMeta.getLore()
);
// Regex match
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(nameAndLore);
if(!matcher.find())
// No data
return null;
LinkedBeaconTeleporterItem lbtItem = new LinkedBeaconTeleporterItem(
matcher.group(1),
itemStack
);
return lbtItem;
}
public static LinkedBeaconTeleporterBlock getLbtBlockFromLocation(Location loc){
// Serialize
String serializedLoc = Function.serialiseBlockLocation(loc);
return placedLBTByLoc.get(serializedLoc);
}
public static List<LinkedBeaconTeleporter> getLbtBlocksFromTeleportId(String teleportId){
return placedLBTsById.get(teleportId);
}
static String constructRegex(String name, List<String> lore){
// Serialize
String regex = serialiseBeaconItem(name, lore);
// Wrap in regex-quotes
regex = "^\\Q"+ regex +"\\E$";
// Exclude id from regex-quotes and create group
regex = regex.replace("%id%", "\\E(.*)\\Q");
// Remove empty regex-quotes
regex = regex.replace("\\E\\Q", "");
return regex;
}
static String serialiseBeaconItem(String name, List<String> lore){
// get name and remove control-chars
String str = name.replace("\\", "\\\\");
if(lore != null){
for (String loreLine : lore) {
// get lore-lines and remove control-chars
str += "\n"+ loreLine.replace("\\", "\\\\");
}
}
return str;
}
}

View File

@@ -0,0 +1,32 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.listener;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterBlock;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterItem;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
public class OnBlockBreak implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onBlockBreakEvent(BlockBreakEvent e){
Block block = e.getBlock();
Location loc = block.getLocation();
if(block.getType() == Material.BEACON){
// Check if this beacon is a LinkedBeaconTeleporter
LinkedBeaconTeleporterBlock lbtBlock = LinkedBeaconTeleporterBlock.getFromLocation(loc);
// Ignore if not found
if(lbtBlock == null) return;
LinkedBeaconTeleporterItem lbtItem = lbtBlock.break_(e);
}
}
}

View File

@@ -0,0 +1,31 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.listener;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterBlock;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterItem;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack;
public class OnBlockPlace implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onBlockPlaceEvent(BlockPlaceEvent e){
ItemStack item = e.getItemInHand();
if(item.getType() == Material.BEACON){
// Check if this beacon is a LinkedBeaconTeleporter
LinkedBeaconTeleporterItem lbtItem = LinkedBeaconTeleporterItem.getFromItemStack(item);
// Ignore if not found
if(lbtItem == null) return;
LinkedBeaconTeleporterBlock lbtBlock = lbtItem.place(e);
}
}
}

View File

@@ -0,0 +1,41 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.listener;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterItem;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterManager;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
public class OnCraftItemEvent implements Listener {
@EventHandler(priority = EventPriority.LOW)
public void onCraftItemEvent(CraftItemEvent e){
Recipe recipe = e.getRecipe();
ItemStack itemResult = recipe.getResult();
// Check if it has LinkedBeaconTeleporter-Data
LinkedBeaconTeleporterItem lbtItem = LinkedBeaconTeleporterManager.getLbtItemFromItemStack(itemResult);
// Ignore if not found
if(lbtItem == null) return;
// Create new LinkedBeaconTeleporterItem
lbtItem = new LinkedBeaconTeleporterItem();
ItemStack item = lbtItem.item();
// Exactly 2
item.setAmount(2);
// FIXME: Changing the just-crafted-item only works for a single item, bulk-crafting (e.g. Shift-Click) will result in default-items getting crafted!
e.setCurrentItem(item);
}
}

View File

@@ -0,0 +1,119 @@
package eu.ruekov.ruakij.LinkedBeaconTeleporters.listener;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Function;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.Main;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.customPlayerMoveEvent.CustomPlayerMoveEvent;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.customPlayerMoveEvent.CustomPlayerMoveEventListener;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporter;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterBlock;
import eu.ruekov.ruakij.LinkedBeaconTeleporters.linkedBeaconTeleporter.LinkedBeaconTeleporterManager;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
public class OnCustomPlayerMove implements CustomPlayerMoveEventListener {
static HashMap<UUID, LinkedBeaconTeleporterBlock> playerBeaconLocation = new HashMap<>();
@Override
public void tick(CustomPlayerMoveEvent e) {
}
@Override
public void locationChange(CustomPlayerMoveEvent e) {
Player p = e.player();
UUID uuid = p.getUniqueId();
// If player found in ignoreList, check if he stepped out of the Beacon-light
if(playerBeaconLocation.containsKey(uuid)) {
LinkedBeaconTeleporterBlock lbtBlock = playerBeaconLocation.get(uuid);
Location lbtBlockLoc = lbtBlock.block().getLocation();
Location pLoc = p.getLocation();
if(lbtBlockLoc.getBlockX() != pLoc.getBlockX() || lbtBlockLoc.getBlockZ() != pLoc.getBlockZ()){
playerBeaconLocation.remove(uuid);
}
else
// Player still on beacon, ignore
return;
}
// Check if player is on-top of a beacon
Block block = Function.searchForMaterial(
p.getLocation().add(0, -1, 0),
new Vector(0, -1, 0),
Material.BEACON,
Function.transparentMaterials
);
// Skip if not found
if(block == null) return;
// TODO: Check if beacon is active
// Check if beacon is a LinkedBeaconTeleporter
LinkedBeaconTeleporterBlock lbtBlock = LinkedBeaconTeleporterManager.getLbtBlockFromLocation(block.getLocation());
// Ignore if not found
if(lbtBlock == null) return;
// Check if player should be ignored on this LinkedBeaconTeleporter
if(playerBeaconLocation.get(uuid) != null && playerBeaconLocation.get(uuid) == lbtBlock) return;
// Get first partner thats not our current-block
LinkedBeaconTeleporterBlock lbtBlockPartner = null;
for(LinkedBeaconTeleporter lbtBlockTmp: lbtBlock.linkedBeaconTeleporters()){
if(lbtBlockTmp != lbtBlock){
lbtBlockPartner = (LinkedBeaconTeleporterBlock)lbtBlockTmp;
break;
}
}
if(lbtBlockPartner == null){
// No other partner
p.sendMessage("§cNo linked beacon found with id §7"+ lbtBlock.teleporterId());
// Set player as ignored on this LinkedBeaconTeleporter (so he wont trigger the checks again)
playerBeaconLocation.put(uuid, lbtBlock);
}
else{
// TODO: Check if beacon is active
// Get safe-location on top of other beacon
Block safeBlock = Function.searchForMaterial(
lbtBlockPartner.block().getLocation().add(0, 1, 0),
new Vector(0, 1, 0),
Material.AIR,
Function.transparentMaterials
);
if(safeBlock == null){
// No safe location found
p.sendMessage("§cNo safe-location found at target teleporter");
playerBeaconLocation.put(uuid, lbtBlock);
return;
}
// TODO: Check if there is enough space for a player
// Set player as ignored on target-LinkedBeaconTeleporter (so he wont trigger the teleport again)
playerBeaconLocation.put(uuid, lbtBlockPartner);
// Teleport
Location loc = safeBlock.getLocation();
// Middle of block
loc.add(0.5, 0, 0.5);
// Preserve pitch and yaw from player
loc.setPitch(p.getLocation().getPitch());
loc.setYaw(p.getLocation().getYaw());
e.player().teleport(
loc
);
}
}
}

View File

@@ -0,0 +1,28 @@
item:
# Name & Lore for linked-beacon-blocks
# - Has to include %id% somewhere for identification!
name: '§9BeaconTeleporter'
lore:
- '§8§o%id%'
beacon:
# Checks that have to succeed for a teleporter to be active (source and target)
checks: # TODO
active: true
id:
# Alphabet to use for random-generation
alphabet: 'abcdefghijklmnopqrstuvwxyz0123456789'
# Length of id
# If its too short, ids will "collide" more often (e.g. 2 players generating same linked-teleporters independently), but maybe thats a gameplay-feature for you :)
length: 10
locationCheck:
# Interval [in ticks] to check if a player is on a beacon
# 5 (= 4 times/s) is usually responsive enough for most interactions
interval: 5
autosave:
# Interval [in seconds] for autosave
interval: 600

View File

@@ -0,0 +1,5 @@
name: ${artifactId}
version: ${version}
author: ${author}
main: ${groupId}.${artifactId}.Main
api-version: 1.16