-
Notifications
You must be signed in to change notification settings - Fork 302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Commands blocks can’t create or unload worlds #2560
Comments
I'll be looking into this soon. ben pointed out that this is similar to #2167, and I agree with him that this is most likely the same issue. |
In the meantime, the link given by |
Here you go: https://j.mp/3pF1hMY |
[08:00:15] [Server thread/INFO]: [Multiverse-Core] World 'world2' was unloaded from Multiverse. Maybe it is running a commad multiple times |
It seems this issue has gone stale. If it helps, I recently tried doing this again to see if any updates had fixed the issue. Unfortunately, it still crashed, but I noticed this message in the console log: Here's the console log: latest.log If anyone wants to try to recreate this, here is my server information:
I think the only plugins that matter are Multiverse, ConfigCommands, and CommandAPI. I don't know if the version matters, but I have debug: true
commands:
regenWorld:
args:
- name: <world>
type: String
commands:
- do <sender>.sendMessage("Regenerating ".join(<world>).join("..."))
- /mvregen <world> -s
- do <sender>.sendMessage(<sender>.dispatchCommand("mvconfirm"))
- do <sender>.sendMessage("Done!")
name: regenworld Now, if you run |
It was concluded as a server software limitation, see: PaperMC/Paper#6072 |
So should this issue be closed or will the Multiverse code need to change so that it never tries to create a world while the worlds are being ticked? It seems that the server crashes anyways despite the paper fix, so I think this issue is still not resolved. |
Okay, so PaperMC/Paper#6072 addressed the issue where trying to create a world while the worlds were being ticked would cause a crash. Now, when you try to run Even after that is fixed, I don't think this issue should be closed. I propose that if a command like |
Is there any workaround whatsoever to this? Really bugging me. Thanks |
Well, on Paper servers at least the server shouldn't crash anymore when running these commands in a command block if you have the latest version. Spigot servers will still crash, which I'm hoping will be resolved by SPIGOT-7089. While not accidentally causing the server to crash is good, the command blocks are still not able to unload/create worlds. Since this issue hasn't been closed yet I might assume it is being worked on, though we'll have to see. I haven't found any way around this yet. It makes sense to not allow removing or creating worlds while they are being looped through, so you would probably need some way to delay command execution until when the worlds are no longer being ticked. The Multiverse code probably needs to change to make this happen. |
Ok got this working - Used a BukkitRunnable and cancel it after one iteration after just waiting 10 ticks, shown below.
|
What do you mean that this doesn't work for command blocks? I tried this out myself and I was able to trigger the world regeneration from a command block. Here's the code I used: package me.willkroboth.TestMainPlugin;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
public class TestMainPlugin extends JavaPlugin {
public void onEnable() {
getCommand("regenfromcommandblock").setExecutor(this);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length != 1) return false;
String world = args[0];
new BukkitRunnable() {
public void run() {
//Regen World
Bukkit.dispatchCommand(sender, "mvregen " + world + " -s");
Bukkit.dispatchCommand(sender, "mvconfirm");
}
}.runTask(this);
return true;
}
} Using |
Oh awesome! Thanks for the information, still relatively new to Spigot plugin coding. 😄 |
I tried it out and using a BukkitRunnable like this to delay code until the worlds are no longer being ticked looks compatible with the Multiverse code! I think I got |
Actually, I realized that I can't do anything until SPIGOT-7089 resolves. What I was trying to do was this: try {
attemptWorldRegen(sender, worldName, useSeed, randomSeed, seed, keepGamerules);
} catch (IllegalStateException ignored){
Logging.fine("Worlds were being ticked when attempting to regenerate %s. Trying again in the next tick.", worldName);
// delay second attempt until the worlds are no longer being ticked
new BukkitRunnable() {
public void run() {
attemptWorldRegen(sender, worldName, useSeed, randomSeed, seed, keepGamerules);
}
}.runTask(plugin);
} If regenerating the world caused an IllegalStateException because the worlds were being ticked, a BukkitRunnable would be created to try regenerating the world again once the worlds were not being ticked. This doesn't change anything if the worlds are not being ticked but successfully triggers the world regeneration at a better time if the worlds are being ticked. The problem is that Spigot servers don't throw this error (or do something else to stop the crash) yet. This code works on a Paper server, but there is still no way to check if the worlds are being ticked on a Spigot server until it is too late and the server is crashing. If there was some way to tell if the worlds were being ticked on a Spigot server, something like this would work. if(worldsAreNotBeingTicked){
modifyWorlds();
} else {
new BukkitRunnable() {
public void run() {
modifyWorlds();
}
}.runTask(plugin);
} |
Addresses Multiverse#2560 Commands that load or unload worlds trigger an IllegalStateException if they are run via a command block while the worlds are being ticked. Using a BukkitRunnable, the operation can be delayed until the next tick at a time when the worlds are not being ticked. MVWorldManager#addOrRemoveWorldSafely performs this logic, either running the operation now or delaying it. 8 commands were modified to use MVWorldManager#addOrRemoveWorldSafely, which I think are all the relevant commands. Unfortunately I haven't found a way to tell when the worlds are being ticked on a Spigot server. There probably won't be any way to do this until [SPIGOT-7089](https://hub.spigotmc.org/jira/browse/SPIGOT-7089) resolves
Edit: Nevermind I see the issue isn't solved by this, apologies
|
Spigot-7089 has been resolved! On the latest versions of Spigot, command blocks can load and unload worlds with no problems. Unfortunately, the fixes added by PaperMC/Paper#7653 and PaperMC/Paper#8081 are still in effect, so Paper servers are still trying to avoid the crash by throwing an IllegalStateException. I'll close this issue once that gets resolved and Paper embraces or modifies the Spigot fix (watching PaperMC/Paper#8300). |
Update: PaperMC/Paper#8300 has been resolved as: plugins have to deal with this difference between Spigot and Paper. So Spigot currently allows worlds to be loaded/unloaded while the worlds are being ticked, while Paper does not. For this issue, that means that command blocks can create or unload worlds on Spigot, but not on Paper. I'm currently working on a PR that will fully resolve this issue by switching behavior based on whether or not the Paper patches are active. |
I have finished dealing with the world load/unload difference between Spigot and Paper. The summary of that is this new method: private boolean safeToAddOrRemoveWorld(){
Server server = Bukkit.getServer();
Logging.finest("Using reflection to test for Paper build after PR #7653");
try {
// basically doing ((CraftServer) Bukkit.getServer()).getServer().isIteratingOverLevels;
Method getConsole = server.getClass().getMethod("getServer");
Object console = getConsole.invoke(server);
Field isTickingWorlds = console.getClass().getField("isIteratingOverLevels");
boolean isTicking = isTickingWorlds.getBoolean(console);
Logging.finest("Paper fix active");
return !isTicking;
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
Logging.finest("%sUnexpected exception: %s", ChatColor.RED, e.getMessage());
Logging.finest("Assuming Paper fix is inactive");
// If the Paper fix actually is active it should become obvious when Paper complains
// about a world being loaded/unloaded while being ticked
// If that happens, this method needs to be fixed
return true;
} catch (NoSuchFieldException ignored) {
// Expected to fail when field isIteratingOverLevels doesn't exist
// Therefore, Paper fixes aren't active, so it is always considered safe to proceed
Logging.finest("Paper fix inactive");
return true;
}
} This method uses reflection to check first if Paper's fix is active, and if so whether or not it is currently safe to load or unload worlds. I think this is a good enough solution considering the perspectives of the Paper devs. |
(Final?) update: Paper has decided to align with Spigot, at least for now, on the world load/unload issue. In this context, that means that command blocks can now create and unload worlds on the latest versions of both Spigot and Paper without having to modify Multiverse. I'll leave the pull request open since the Paper devs asked to consider not loading/unloading worlds while being ticked, but that's not necessary to resolve this issue. |
Addresses Multiverse#2560 Commands that load or unload worlds trigger an IllegalStateException if they are run via a command block while the worlds are being ticked. Using a BukkitRunnable, the operation can be delayed until the next tick at a time when the worlds are not being ticked. MVWorldManager#addOrRemoveWorldSafely performs this logic, either running the operation now or delaying it. 8 commands were modified to use MVWorldManager#addOrRemoveWorldSafely, which I think are all the relevant commands. Unfortunately I haven't found a way to tell when the worlds are being ticked on a Spigot server. There probably won't be any way to do this until [SPIGOT-7089](https://hub.spigotmc.org/jira/browse/SPIGOT-7089) resolves
Addresses Multiverse#2560 Commands that load or unload worlds trigger an IllegalStateException if they are run via a command block while the worlds are being ticked. Using a BukkitRunnable, the operation can be delayed until the next tick at a time when the worlds are not being ticked. MVWorldManager#addOrRemoveWorldSafely performs this logic, either running the operation now or delaying it. 8 commands were modified to use MVWorldManager#addOrRemoveWorldSafely, which I think are all the relevant commands. Unfortunately I haven't found a way to tell when the worlds are being ticked on a Spigot server. There probably won't be any way to do this until [SPIGOT-7089](https://hub.spigotmc.org/jira/browse/SPIGOT-7089) resolves
On my server, I'm trying to make a minigame that takes place in an entire survival world. One thing I can't figure out how to do is creating or reloading the world so that each round has a random seed and nothing from previous rounds affects any of the others. Looking through the command reference for Multiverse-Core, I found the mvregen command. This seemed to be exactly what I need to do, so I made a command in my commands.yml like this:
aliases:
regenMinigame:
- mvregen world -s
- mvconfirm
- mvregen world_nether -s
- mvconfirm
- mvreg world_end -s
- mvconfirm
Running the regenMinigame command seems to work perfectly fine when run by a player or even from the console, but when I run the command in a command block (which I need to do for it to be automatic), the sever crashes and it creates this crash log:
crash-2021-02-13_12.40.13-server.txt
When I restart and rejoin the server, I find that the worlds have been regenerated as I wanted. Is there any way to do what I want to do without crashing my sever? If you want any more information about the server, feel free to ask.
The text was updated successfully, but these errors were encountered: