So I’ve hit a dead spot here. I’m trying to make a loop that’ll wait a certain amount of time before it fixes blocks…any assistance would be awesome :0 thank you
If you want to stop an explosion causing damage then just cancel the ExplosionEvent
, or are you looking to specifically allow an explosion then revert it at some point after?
yes i’m trying to revert it after wards for a mini game please help
Oh an i’m sure i’ll just cancel the drop item event anyway so i’m not too worried about that.
OK so assuming you want to revert a specific explosion (not just a random one like a creeper in the distance) you first need to define a rule so you can target just the explosions you’re interested in.
Now, the event. The event we’re interested in is ExplosionEvent.Detonate
, specifically because it is fired when an explosion is calculated and just before it takes effect.
We need to grab all changes the explosion will make. For that make a call to event.getTransactions()
this contains every block transaction (i.e before->after) that will be made.
Store this list of transactions, this will be what you rollback later.
In order to be sure the transactions in the event are the transactions that actually take effect in the world, we need to listen to the event at the latest possible time. This means using order=Order.POST
in the @Listener
annotation.
When it comes to restoring the world, simply grab the stored transaction and revert every change to the original (original block before explosion).
Unless I’ve overlooked something I think that’s all that you need to do it.
Here’s a quick draft up of how you might implement this in code
private final List<List<Transaction<BlockSnapshot>>> capturedExplosionTransactions;
@listener(order = Order.POST)
public void onExplodeEvent(ExplosionEvent.Detonate event) {
// Your explosion capture rule goes in this 'if' statement
if (event.getCause().first(Player.class).isPresent() && someOtherConditions) {
// Capture all changes
capturedExplosionTransactions.add(event.getTransactions());
}
}
// Called some point in the future
public void rollbackTransaction(int num) {
// Get the transaction we're interested in
List<Transaction<BlockSnapshot>> transactions = capturedExplosionTransactions.remove(num);
// For every block that was changed:
for (Transaction<BlockSnapshot> transaction : transactions) {
transaction.getOriginal().restore(true, true); // Restore the block
}
}
Disclaimer: This is literally the first thing that popped into by head when I read your question so it may or may not work. Code written directly on this post and not tested.
ok so yes this is part of what i need however where would i imput the amount of time for these to regenerate?
Introducing… The SchedulerService
!
The scheduler allows you to create a task that runs at some point in the future and supports repeating tasks.
I suggest you check out the documentation here: https://docs.spongepowered.org/en/plugin/scheduler.html
and the interface source code: https://github.com/SpongePowered/SpongeAPI/blob/master/src/main/java/org/spongepowered/api/service/scheduler/SchedulerService.java
Lets say you want to restore an explosion every minute (you can of course make this configurable in a config or something).
game.getScheduler().createTaskBuilder()
.execute(task -> {
// Add stuff to do here
rollbackTransaction(num);
})
.interval(1, TimeUnit.MINUTES) // The interval
.submit(myPlugin); // Submit the task to the scheduler
Hopefully this will help you get stuck-in creating your plugin
Ok so quite a bit of issues I followed what you said but i’m getting error’s up and down …help please?
I gave you code snippets, they won’t work on their own. You have to have a basic understanding of how to create a plugin first. I could provide a complete solution but then you won’t learn much,
The variables capturedExplosionTransactions
and game
are fields in your plugin class.
game
is the game instance, you can declare this like so:
@Inject
private Game game;
and capturedExplosionTransactions
like:
private final List<List<Transaction<BlockSnapshot>>> capturedExplosionTransactions = Lists.newArrayList();
Remember to import all classes used, in eclipse there is a shortcut, 'Ctrl+Shift+O'
Ok see I have that issue because I was coding in bukkit for the longest times and now i’m trying to recode code to Sponge because I like it so any and every bit of help is awesome. I only started working on plugins about a year ago…if you could look over what i have and give me any hints that would be awesome…or advice on where to pick up how to’s. cause I have never read api’s before and English was not my first language. So please tell me what i’m missing and i’ll fix it… that’s how i learn if you could do that I would be extremely thankful
cause then i can take the examples I learn from you and move forwards
package me.Cleardragonf.ExplosionGuard;
import com.google.common.collect.Lists;
import org.spongepowered.api.Game;
import org.spongepowered.api.service.scheduler.Task.Builder;
import org.spongepowered.api.service.scheduler.SchedulerService;
import org.spongepowered.api.event.Order;
import org.spongepowered.api.event.block.ChangeBlockEvent.Post;
import org.spongepowered.api.data.Transaction;
import org.spongepowered.api.block.BlockSnapshot;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.entity.explosive.PrimedTNT;import org.spongepowered.api.entity.living.monster.Creeper;
import org.spongepowered.api.event.world.ExplosionEvent;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.Listener;
import java.awt.List;
import java.io.File;
import java.util.logging.Logger;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.service.config.DefaultConfig;import com.google.inject.Inject;
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;@Plugin(id = “me.Cleardragonf.ExplosionGuard”, name = “ExplosionGuard”, version = “Beta.1.0”)
public class MainClass {
@Inject private Logger logger; @Inject private void setLogger(Logger logger){ this.logger = logger; } public Logger getLogger(){ return logger; } @Inject @DefaultConfig(sharedRoot = true) private File configFile; @Inject @DefaultConfig(sharedRoot = true) ConfigurationLoader<CommentedConfigurationNode> configManager; @Listener public void onInitialization(GamePreInitializationEvent e) { ConfigurationManager.getInstance().setup(configFile, configManager); }
@Listener public void onExplosionEvent(ExplosionEvent.Pre event) { if (event.getCause().first(Creeper.class).isPresent()) { if (ConfigurationManager.getInstance().getConfig().getNode("Explosions", "Creeper").getString().equalsIgnoreCase("true")){ event.setCancelled(true); } if (ConfigurationManager.getInstance().getConfig().getNode("Explosions", "Creeper").getString().equalsIgnoreCase("false")){ event.setCancelled(false); } } if (event.getCause().first(PrimedTNT.class).isPresent()){ if (ConfigurationManager.getInstance().getConfig().getNode("Explosions", "TNT").getString().equalsIgnoreCase("true")){ event.setCancelled(true); } if (ConfigurationManager.getInstance().getConfig().getNode("Explosions", "TNT").getString().equalsIgnoreCase("false")){ event.setCancelled(false); } } //this is here for logging what caused the explosiong so it can be logged //*getLogger().info(event.getCause().toString());
} private final List<List<Transaction<BlockSnapshot>>> capturedExplosionTransactions = Lists.newArrayList(); @Listener(order = Order.POST) public void onRegisterEvent(ExplosionEvent.Detonate event){ if (event.getCause().first(Creeper.class).isPresent()){ capturedExplosionTransactions.add(event.getTransactions()); } } @Inject private Game game; SchedulerService scheduler = game.getScheduler(); Builder taskBuilder = scheduler.createTaskBuilder(); game.getScheduler().createTaskBuilder() .execute(task -> { rollbackTransaction(num); }) .interval(1, TimeUnit.MINUTES) .submit(myPlugin);
}
This was the initial code for creepermend which accomplishes exactly this.
However you will run into troubles when it comes to blocks reacting to the explosion, signs falling off etc.
May need to listen for a generic block break caused by the explosion afterwards and add that to the list of blocks to be restored.