diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c37caf --- /dev/null +++ b/.gitignore @@ -0,0 +1,118 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..ce363ee --- /dev/null +++ b/build.gradle @@ -0,0 +1,57 @@ +plugins { + id 'java' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +def projectName = 'LampPowerAPI' +group = 'org.finetree' +version = '1.0.0' + +repositories { + mavenCentral() + maven { + name = "spigotmc-repo" + url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" + } + maven { + name = "sonatype" + url = "https://oss.sonatype.org/content/groups/public/" + } + maven { url = uri('https://redempt.dev') } +} + +dependencies { + compileOnly "org.spigotmc:spigot-api:1.20.2-R0.1-SNAPSHOT" + implementation 'com.github.Redempt:RedLib:6.5.8' +} + +def targetJavaVersion = 17 +shadowJar { + archiveFileName = projectName + "-" + version + ".jar" + relocate 'redempt.redlib', 'org.finetree.finedrawbridges.redlib' + destinationDirectory = file('X:/plugins') +} + +java { + def javaVersion = JavaVersion.toVersion(targetJavaVersion) + sourceCompatibility = 1.9 + targetCompatibility = 1.9 + if (JavaVersion.current() < javaVersion) { + toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) + } +} + +tasks.withType(JavaCompile).configureEach { + if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { + options.release = targetJavaVersion + } +} + +processResources { + def props = [version: version] + inputs.properties props + filteringCharset 'UTF-8' + filesMatching('plugin.yml') { + expand props + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..e69de29 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37aef8d --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..6365ef1 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'LampPowerAPI' diff --git a/src/main/java/org/finetree/lamppowerapi/LampPower.java b/src/main/java/org/finetree/lamppowerapi/LampPower.java new file mode 100644 index 0000000..7d8babf --- /dev/null +++ b/src/main/java/org/finetree/lamppowerapi/LampPower.java @@ -0,0 +1,251 @@ +package org.finetree.lamppowerapi; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.AnaloguePowerable; +import org.bukkit.block.data.Directional; +import org.bukkit.block.data.Powerable; +import org.bukkit.block.data.type.RedstoneWallTorch; +import org.bukkit.block.data.type.RedstoneWire; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.BlockRedstoneEvent; +import org.bukkit.material.PressureSensor; +import org.bukkit.material.Redstone; +import redempt.redlib.blockdata.DataBlock; + +import java.util.ArrayList; +import java.util.Arrays; + + +public class LampPower implements Listener { + + public static ArrayList allFaces = new ArrayList<>(Arrays.asList(BlockFace.UP, BlockFace.DOWN, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH)); + static ArrayList redstoneFaces = new ArrayList<>(Arrays.asList(BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH)); + static ArrayList torchFaces = new ArrayList<>(Arrays.asList(BlockFace.UP, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH)); + static ArrayList trappedChestFaces = new ArrayList<>(Arrays.asList(BlockFace.DOWN, BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH)); + + //Returns power if it's a redstone component. else returns -1 + public static int isRedstone(BlockState state){ + + if ( state instanceof PressureSensor ) { + return ( (PressureSensor) state.getBlockData() ).isPressed() ? 15 : 0; + } else if (state instanceof Redstone) { + return ( (Redstone) state.getBlockData() ).isPowered() ? 15 : 0; + } else if (state instanceof Powerable) { + return ( (Powerable) state.getBlockData() ).isPowered() ? 15 : 0; + } else if (state instanceof AnaloguePowerable) { + return ( (AnaloguePowerable) state.getBlockData() ).getPower(); + }else{ + + //These don't have a getPower method as they are always-on + //TODO check faces. + switch (state.getType()) { + case REDSTONE_TORCH: + case REDSTONE_WALL_TORCH: + case REDSTONE_BLOCK: + return 15; + } + + return -1; + } + + } + + public static ArrayList getAdjacentLamps(BlockState state) { + ArrayList lamps = new ArrayList<>(); + + switch(state.getType()) { + case REDSTONE_WIRE: { + RedstoneWire wire = (RedstoneWire) state.getBlockData(); + + for(BlockFace face : redstoneFaces) { // get all 5 sides and loop through them + boolean sideConnected = wire.getFace(face) != RedstoneWire.Connection.NONE; // check if connector != NONE + if(sideConnected){ + addIfLamp(lamps, state, face); + } + } + //Remember to check down direction separately as redstone dust has no down face + addIfLamp(lamps, state, BlockFace.DOWN); + break; + } + case OBSERVER: + case REPEATER: + case COMPARATOR: { + Directional repeater = (Directional) state.getBlockData(); + BlockFace curFace = repeater.getFacing().getOppositeFace(); + addIfLamp(lamps, state, curFace); + break; + } + case LECTERN: + case DETECTOR_RAIL: + case POLISHED_BLACKSTONE_PRESSURE_PLATE: + case ACACIA_PRESSURE_PLATE: + case BIRCH_PRESSURE_PLATE: + case CRIMSON_PRESSURE_PLATE: + case STONE_PRESSURE_PLATE: + case DARK_OAK_PRESSURE_PLATE: + case HEAVY_WEIGHTED_PRESSURE_PLATE: + case JUNGLE_PRESSURE_PLATE: + case LIGHT_WEIGHTED_PRESSURE_PLATE: + case OAK_PRESSURE_PLATE: + case SPRUCE_PRESSURE_PLATE: + case WARPED_PRESSURE_PLATE: + case BIRCH_BUTTON: + case ACACIA_BUTTON: + case CRIMSON_BUTTON: + case DARK_OAK_BUTTON: + case JUNGLE_BUTTON: + case OAK_BUTTON: + case POLISHED_BLACKSTONE_BUTTON: + case SPRUCE_BUTTON: + case STONE_BUTTON: + case WARPED_BUTTON: + case LEVER: + case REDSTONE_LAMP: // also get all lamps adjacent to this lamp + case DAYLIGHT_DETECTOR: + case TARGET: + case REDSTONE_BLOCK: { + for(BlockFace face : allFaces){// get all sides + addIfLamp(lamps, state, face); + } + break; + } + case REDSTONE_TORCH: { + for(BlockFace face : torchFaces){// get all 5 sides + addIfLamp(lamps, state, face); + } + break; + } + case REDSTONE_WALL_TORCH: { + RedstoneWallTorch torch = (RedstoneWallTorch) state.getBlockData(); + BlockFace curFace = torch.getFacing().getOppositeFace(); + for(BlockFace face : allFaces){// get all sides + if(curFace == face){continue;} + addIfLamp(lamps, state, face); + } + break; + } + case TRAPPED_CHEST: { + for(BlockFace face : trappedChestFaces){// get all 5 sides + addIfLamp(lamps, state, face); + } + break; + } + } + + return lamps; + } + + private static void addIfLamp(ArrayList lamps, BlockState state, BlockFace face) { + Block targ = state.getLocation().getBlock().getRelative(face); + if (targ.getType() == Material.REDSTONE_LAMP) { + lamps.add(targ); + } + } + + @EventHandler + public void redstoneEvent(BlockRedstoneEvent e) { + BlockState redstoneBlock = e.getBlock().getState(); + int newPower = e.getNewCurrent(); + int oldPower = e.getOldCurrent(); + + //If nothing changed, do nothing. + if(newPower == oldPower){return;} + + //Get lamps that this component connects to. + ArrayList lamps = getAdjacentLamps(redstoneBlock); + + //Update the lamps found if our redstone is higher power than it. + for(Block lamp : lamps) { + int lampPower = getLampPower(lamp); + + //If we are powering the lamp higher, just set it. + if(newPower > lampPower){ + setLampPower(lamp, newPower); + }else{ //If we are potentially lowering the lamp power, ask the lamp to recalculate. + lampRecalculate(lamp); + } + + } + } + + public static void lampRecalculate(Block lamp){ + //Init our return Variable at 0 incase nothing is found to be powering the lamp + int calculatedPower = 0; + + //Check all sides + for(BlockFace face : allFaces){ + + //Get the block on that side and check if it's a redstone component. + Block component = lamp.getRelative(face); + int componentPower = isRedstone(component.getState()); + + //Found a redstone component as it has power + if(componentPower != -1){ + + //Get the component's connected lamps + ArrayList lamps = getAdjacentLamps(component.getState()); + + //Are we one of the lamps? + for(Block toCheck : lamps){ + //If the locations are the same, it's connected to us. + if( toCheck.getLocation().equals( lamp.getLocation() ) ){ + + //If the connected component power is greater, then that's our new max. + if(componentPower > calculatedPower){ + calculatedPower = componentPower; + } + + //End the for-loop as we found self. + break; + } + } + + } + + }//Check all nearby components + + //Set final calculated power on lamp. + setLampPower(lamp, calculatedPower); + } + + public static void setLampPower(Block lamp, int pwr){ + DataBlock db = LampPowerAPI.getBlockManager().getDataBlock(lamp, true); + db.set("power", pwr); + } + + public static int getLampPower(Block lamp){ + DataBlock db = LampPowerAPI.getBlockManager().getDataBlock(lamp, false); + + //This is a regular lamp with no power set + if(db == null){return 0;} + + //if we have a power var, return it. + return db.contains("power") ? db.getInt("power") : 0; + } + + @EventHandler + public void blockPlaceEvent(BlockPlaceEvent e) { + Block b = e.getBlock(); + Material t = b.getType(); + + //If it's a NC redstone component then we need to manually deal with it. + drawbridgeChangeComponent(b.getState(), t); + } + + public static void drawbridgeChangeComponent(BlockState state, Material t){ + if (t == Material.REDSTONE_TORCH || t == Material.REDSTONE_WALL_TORCH || t == Material.REDSTONE_BLOCK) { + //Recalculate nearby lamps when NC components are placed. + ArrayList lamps = getAdjacentLamps(state); + for (Block lamp : lamps) { + lampRecalculate(lamp); + } + } + } + +} + diff --git a/src/main/java/org/finetree/lamppowerapi/LampPowerAPI.java b/src/main/java/org/finetree/lamppowerapi/LampPowerAPI.java new file mode 100644 index 0000000..7cbf98f --- /dev/null +++ b/src/main/java/org/finetree/lamppowerapi/LampPowerAPI.java @@ -0,0 +1,44 @@ +package org.finetree.lamppowerapi; + +import org.bukkit.plugin.java.JavaPlugin; +import redempt.redlib.blockdata.BlockDataManager; + +public final class LampPowerAPI extends JavaPlugin { + + private static LampPowerAPI plugin; + private static BlockDataManager manager; + + public LampPower lampPower; + + @Override + public void onEnable() { + // Plugin startup logic + + //Initialize plugin getter + plugin = this; + + //Initialize DataBlock Manager from RedLib + manager = BlockDataManager.createAuto(this, this.getDataFolder().toPath().resolve("blocks.db"), true, true); + + //Initialize our API var. + lampPower = new LampPower(); + + //Listen for events + getServer().getPluginManager().registerEvents(new LampPower(), this); + } + + @Override + public void onDisable() { + // Plugin shutdown logic + } + + //Plugin Getter + public static LampPowerAPI getPlugin() { + return plugin; + } + + public static BlockDataManager getBlockManager() { + return manager; + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..2a9d702 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,4 @@ +name: LampPowerAPI +version: '${version}' +main: org.finetree.lamppowerapi.LampPowerAPI +api-version: '1.20'