Skip to content

Commit

Permalink
Merge pull request #111 from BTEUK/Fix-for-new-WorldEdit-mechanism-bug
Browse files Browse the repository at this point in the history
Redoing the WorldEdit calculation mechanism, moving to FAWE
  • Loading branch information
george112n authored Aug 8, 2024
2 parents 16a9c4a + 406bb5d commit b366b4c
Show file tree
Hide file tree
Showing 8 changed files with 546 additions and 153 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>me.bteuk</groupId>
<artifactId>TeachingTutorials</artifactId>
<version>1.1.0-Beta8.1</version>
<version>1.1.0-Beta8.1.2</version>
<packaging>jar</packaging>

<name>TeachingTutorials</name>
Expand Down
48 changes: 48 additions & 0 deletions src/main/java/teachingtutorials/TeachingTutorials.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import teachingtutorials.newlocation.NewLocation;
import teachingtutorials.tutorials.*;
import teachingtutorials.utils.*;
import teachingtutorials.utils.plugins.WorldEditImplementation;

import java.io.BufferedReader;
import java.io.File;
Expand Down Expand Up @@ -54,6 +55,9 @@ public class TeachingTutorials extends JavaPlugin
//A list of all virtual blocks
public HashMap<VirtualBlockLocation, BlockData> virtualBlocks;

//Identifies which world edit is being used
public WorldEditImplementation worldEditImplementation;

@Override
public void onEnable()
{
Expand All @@ -80,6 +84,29 @@ public void onEnable()
return;
}

if (Bukkit.getPluginManager().isPluginEnabled("FastAsyncWorldEdit"))
{
worldEditImplementation = WorldEditImplementation.FAWE;
getLogger().info("WorldEdit implementation detected as FAWE");
}
else if (Bukkit.getPluginManager().isPluginEnabled("WorldEdit"))
{
worldEditImplementation = WorldEditImplementation.WorldEdit;
getLogger().severe("WorldEdit implementation detected as WorldEdit (not FAWE). Please change to FAWE to continue.");
getLogger().severe("Contact the authors of the plugin for support");
getLogger().severe("*** This plugin will be disabled. ***");
this.setEnabled(false);
return;
}
else
{
worldEditImplementation = WorldEditImplementation.NONE;
getLogger().severe("*** No type of WorldEdit is loaded on the server. ***");
getLogger().severe("*** This plugin will be disabled. ***");
this.setEnabled(false);
return;
}

// Plugin startup logic
TeachingTutorials.instance = this;
TeachingTutorials.config = this.getConfig();
Expand Down Expand Up @@ -247,6 +274,27 @@ public void run()
}, 0, 10);


//-----------------------------------------
//------ Performs calculation events ------
//-----------------------------------------
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, () ->
{
if (!WorldEdit.isCurrentCalculationOngoing())
{
WorldEditCalculation worldEditCalculation = WorldEdit.pendingCalculations.peek();
if (worldEditCalculation !=null)
{
Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW +"[TeachingTutorials] Calculation not already in progress, a new one has been detected");
WorldEdit.setCalculationInProgress();
worldEditCalculation.runCalculation();
}
}
else
{
Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW +"[TeachingTutorials] Calculation ongoing, not initiating a new one");
}
}, 0, 4);

//---------------------------------------
//---------------Listeners---------------
//---------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/teachingtutorials/fundamentalTasks/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,9 @@ else if (!(tasks.get(this.iOrder - 2) instanceof Selection))
RegionSelector regionSelector = new CuboidRegionSelector(BukkitAdapter.adapt(world), selectionPoint1, selectionPoint2);

//Calculates the virtual blocks
WorldEdit.BlocksCalculator(iTaskID, virtualBlocks, regionSelector, szTargetCommand, szTargetCommandArgs.split(" "), world, player, parentGroup.parentStep.parentStage.tutorialPlaythrough);
}
WorldEdit.BlocksCalculator(iTaskID, virtualBlocks, regionSelector, szTargetCommand, szTargetCommandArgs.split(" "), parentGroup.parentStep.parentStage.tutorialPlaythrough);

Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] All virtual blocks for this task: "+virtualBlocks.size());
//It will create a new calculation object and add this to the queue. The plugin will calculate the blocks when available
}
}
}
12 changes: 6 additions & 6 deletions src/main/java/teachingtutorials/tutorials/Step.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,14 @@ public void run() {
for (i = 0; i < iGroups; i++)
{
final int I = i;
//Registers each group 0.2 seconds apart from each other - this is to allow all world edit block calculations to complete
//WE block calculations involves running the WE command over the console and detecting and recording changes, before
// then removing those changes from the actual world. This involves delicate use of listeners, hence this 0.1 second control
Bukkit.getScheduler().runTaskLater(TeachingTutorials.getInstance(), () ->
{
// //Registers each group GroupRegistrationTimeGapTicks/20 seconds apart from each other - this is to allow all world edit block calculations to complete
// //WE block calculations involves running the WE command over the console and detecting and recording changes, before
// // then removing those changes from the actual world. This involves delicate use of listeners, hence this 0.1 second control
// Bukkit.getScheduler().runTaskLater(TeachingTutorials.getInstance(), () ->
// {
groups.get(I).initialRegister();
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Registered group "+(I+1));
}, i*4L);
// }, i*plugin.getConfig().getLong("GroupRegistrationTimeGapTicks"));
}

//TP to start location, and store this location for later use
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/teachingtutorials/utils/VirtualBlock.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package teachingtutorials.utils;

import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
Expand Down Expand Up @@ -40,10 +39,10 @@ public VirtualBlock(TutorialPlaythrough tutorialPlaythrough, Player player, Worl

/**
* Constructs the virtual block. Use this if the bukkit location object for this block has already been created and initialised
* @param tutorialPlaythrough
* @param player
* @param location
* @param blockData
* @param tutorialPlaythrough The tutorial playthrough instance that this virtual block belongs to
* @param player The player to display the virtual block for
* @param location The location of the virtual block
* @param blockData The block data for the virtual block
*/
public VirtualBlock(TutorialPlaythrough tutorialPlaythrough, Player player, Location location, BlockData blockData)
{
Expand Down
168 changes: 30 additions & 138 deletions src/main/java/teachingtutorials/utils/WorldEdit.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
package teachingtutorials.utils;

import com.google.common.base.Joiner;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import teachingtutorials.TeachingTutorials;
import teachingtutorials.TutorialPlaythrough;

import java.util.HashSet;
import java.util.LinkedList;

public class WorldEdit
{
private static Object worldEditEditEvent;
/**
* A queue of pending calculations to be performed
*/
public static LinkedList<WorldEditCalculation> pendingCalculations = new LinkedList<>();
private static boolean bCurrentCalculationOngoing = false;

public static boolean isCurrentCalculationOngoing()
{
return bCurrentCalculationOngoing;
}

public static void setCalculationInProgress()
{
bCurrentCalculationOngoing = true;
Bukkit.getConsoleSender().sendMessage(ChatColor.RED +"[TeachingTutorials] The calculations queue has been blocked - calculation in progress");
}

public static void setCalculationFinished()
{
bCurrentCalculationOngoing = false;
Bukkit.getConsoleSender().sendMessage(ChatColor.GREEN +"[TeachingTutorials] The calculations queue has been unblocked!");
}

/**
* Creates a world edit event listener which catches the block changes arising from world edit commands owned by the given player
Expand All @@ -34,143 +41,28 @@ public class WorldEdit
* @param virtualBlocks The list of virtual blocks for the calling task
* @param szCommandLabel The command label (first word) of the command
* @param szCommandArgs The command args
* @param bukkitWorld The bukkit world for this set of blocks
* @param player The player doing the task
* @param tutorialPlaythrough The tutorial playthrough which this task belongs to
* @return
*/
public static void BlocksCalculator(int iTaskID, final HashSet<VirtualBlock> virtualBlocks, RegionSelector correctSelectionRegion, String szCommandLabel, String[] szCommandArgs, World bukkitWorld, Player player, TutorialPlaythrough tutorialPlaythrough)
public static void BlocksCalculator(int iTaskID, final HashSet<VirtualBlock> virtualBlocks, RegionSelector correctSelectionRegion, String szCommandLabel, String[] szCommandArgs, TutorialPlaythrough tutorialPlaythrough)
{
//Get instance
com.sk89q.worldedit.WorldEdit worldEdit = com.sk89q.worldedit.WorldEdit.getInstance();

//Get the console actor
Actor consoleActor = BukkitAdapter.adapt(Bukkit.getConsoleSender());

//Modifies the command
//1. Modifies the command
//This code is taken from WorldEdit - See https://enginehub.org/
int plSep = szCommandLabel.indexOf(':');
if (plSep >= 0 && plSep < szCommandLabel.length() +1)
{
szCommandLabel = szCommandLabel.substring(plSep + 1);
}
// StringBuilder sb = new StringBuilder("/").append(szCommandLabel);
StringBuilder sb = new StringBuilder(szCommandLabel);
// if (szCommandArgs.length > 0)
// sb.append(" ");
String szWorldEditCommand = Joiner.on(" ").appendTo(sb, szCommandArgs).toString();

//The command is now fully formatted correctly
// Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorial] Command being run via the API: "+szWorldEditCommand);
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorial] Command being run via the console: "+szWorldEditCommand);

//Create the new event listener
worldEditEditEvent = new Object()
{
// The following code is extracted from LogBlock under creative commons.
// http://creativecommons.org/licenses/by-nc-sa/3.0/

@Subscribe
public void onEditSessionEvent(EditSessionEvent event)
{
final Actor actor = event.getActor();

if (actor.getName().equals(consoleActor.getName()))
{
System.out.println("Edit session event detected belonging to the actor we are listening for - at stage: "+event.getStage().toString());
}
else
{
System.out.println("Edit session event detected but doesn't belong to the correct actor, so ignoring");
return;
}

//Creates the new extent
AbstractDelegateExtent blockChangeRecorderExtent = new AbstractDelegateExtent(event.getExtent())
{
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block) {
Bukkit.getConsoleSender().sendMessage("\nA world edit block change has been detected, belonging to the listener for task " +iTaskID +". Recording to the given virtual blocks list");
onBlockChange(position, block);
//return super.setBlock(position, block);
return false; // It's unclear whether this should really be used.
// We don't want it to actually set the block so we can just cancel the whole event, but we do also want to set the block or at least try to
}


protected <B extends BlockStateHolder<B>> void onBlockChange(BlockVector3 pt, B block)
{
// //This should only ever be for one of the 3 stages anyway right?
// if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) {
// return;
// }
//Unregisters the event after 0.1 seconds (2 ticks)
Bukkit.getScheduler().runTaskLater(TeachingTutorials.getInstance(), () ->
{
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Unregistering world edit listener for task "+iTaskID);
worldEdit.getEventBus().unregister(worldEditEditEvent);
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Unregistered world edit listener for task "+iTaskID);

int iSize = virtualBlocks.size();

Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] There were " +iSize + " block changes detected for task "+iTaskID);
}, 2L);


//Calculates the old block
Location location = BukkitAdapter.adapt(bukkitWorld, pt);
Block blockBefore = location.getBlock();
BlockData blockDataBefore = blockBefore.getBlockData();

//Gets the new block
BlockData blockDataNew = BukkitAdapter.adapt(block);

//If there is actually a change of block
if (!blockDataBefore.equals(blockDataNew))
{
Bukkit.getConsoleSender().sendMessage("There was a change of block: ");
Bukkit.getConsoleSender().sendMessage("New block: " +blockDataNew.getMaterial());
Bukkit.getConsoleSender().sendMessage("Location: " +location.toString());

//Creates a virtual block
VirtualBlock virtualBlock = new VirtualBlock(tutorialPlaythrough, player, location, blockDataNew);
//Adds it to the new list
virtualBlocks.add(virtualBlock);
}
}
};

//Sets the new extent into the event
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Setting the extent");
event.setExtent(blockChangeRecorderExtent);
}
};

Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Sending command: "+szWorldEditCommand);

Bukkit.getScheduler().runTask(TeachingTutorials.getInstance(), () ->
{
try
{
//Sets the selection
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Adjusting the selection");
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "/world "+tutorialPlaythrough.getLocation().getLocationID());
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "/pos1 " + ((CuboidRegion) correctSelectionRegion.getRegion()).getPos1().toParserString());
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "/pos2 " + ((CuboidRegion) correctSelectionRegion.getRegion()).getPos2().toParserString());

//Registers the world change event listener
worldEdit.getEventBus().register(worldEditEditEvent);
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] World edit change event listener registered");
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Upcoming command being run via the console: "+szWorldEditCommand);

//Runs the command
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Sending the command");
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), szWorldEditCommand);
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] Command sent");
}
catch (IncompleteRegionException e)
{

}
});
//Create a new calculation manager for this calculation and add to the list
WorldEditCalculation newCalculation = new WorldEditCalculation(szWorldEditCommand, correctSelectionRegion, tutorialPlaythrough, iTaskID, virtualBlocks);
WorldEdit.pendingCalculations.add(newCalculation);
Bukkit.getConsoleSender().sendMessage(ChatColor.AQUA +"[TeachingTutorials] This calculation has been added to the queue: "+szWorldEditCommand);
}
}
Loading

0 comments on commit b366b4c

Please sign in to comment.