Shopkeepers

Shopkeepers

2M Downloads

All shops got whiped, no errors.

MithrandirCraft opened this issue ยท 4 comments

commented

Hello. This has happened to me once before in the past. The yml data has been misteriously reset.
What happened was: Afer the usual 8A.M Factions restart, all shops did not spawn. Some players found out, and savaged some of the player shops.
I checked the logs, but there where no errors. I also checked the save.yml file, which was perfectly fine, which left me perplex. Even restarting the server and reloading the plugin had no effect on the apparently frozen yml file and non spawning shops.
So I tried adding a new villager, and once I did, then the file got reset.

Now I'll just apply a backup of both the affected world and the save file (It's no big deal honestly). It does worry me that it may happen again very soon though.

Possible solution for future issues: Maybe you should consider implementing mysql as a data storage option. I'm sure it's been said many times, but this is the only solution I can come up with.

Shopkeepers version: 1.82
No errors. Plugin loads fine.

commented

MySQL will probably just bring a different batch of issues.
For the next update there are some loading/saving related changes planned already, maybe those help:
f1db584
5be3923

Especially: This should fix a rare race condition during plugin disable, if the data is currently getting saved async and the plugin disable triggers another sync save at the same time. And it waits for ongoing async tasks before continuing disable, maybe this helps on restarts.

However, your described problem seems to be related to loading mostly (save.yml exists with correct data, but doesn't get loaded properly):
If it detects some issue there, you should either get a severe message from bukkit, a stack trace from shopkeepers or a warning by shopkeepers (depending on the underlying issue). Could you check your logs again if there are really no errors/warnings at all? If there are no stacktraces, and you were using 1.82, maybe search your logs especially for the messages appearing in this code section:

private boolean load() {
File file = this.getSaveFile();
if (!file.exists()) {
// file does not exist yet -> no shopkeeper data available
return true;
}
YamlConfiguration shopkeepersConfig = new YamlConfiguration();
Scanner scanner = null;
FileInputStream stream = null;
try {
if (Settings.fileEncoding != null && !Settings.fileEncoding.isEmpty()) {
stream = new FileInputStream(file);
scanner = new Scanner(stream, Settings.fileEncoding);
scanner.useDelimiter("\\A");
if (!scanner.hasNext()) {
return true; // file is completely empty -> no shopkeeper data is available
}
String data = scanner.next();
shopkeepersConfig.loadFromString(data);
} else {
shopkeepersConfig.load(file);
}
} catch (Exception e) {
// issue detected:
e.printStackTrace();
return false; // disable without save
} finally {
if (scanner != null) {
scanner.close();
}
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Set<String> ids = shopkeepersConfig.getKeys(false);
for (String id : ids) {
ConfigurationSection shopkeeperSection = shopkeepersConfig.getConfigurationSection(id);
ShopType<?> shopType = shopTypesManager.get(shopkeeperSection.getString("type"));
// unknown shop type
if (shopType == null) {
// got an owner entry? -> default to normal player shop type
if (shopkeeperSection.contains("owner")) {
Log.warning("No valid shop type specified for shopkeeper '" + id + "': defaulting to "
+ DefaultShopTypes.PLAYER_NORMAL().getIdentifier());
shopType = DefaultShopTypes.PLAYER_NORMAL();
} else {
// no valid shop type given..
Log.warning("Failed to load shopkeeper '" + id + "': unknown type");
return false; // disable without save
}
}
// MC 1.11: convert old skeleton and zombie variants to new mob types
// TODO remove again in future updates
boolean hasStrayType = false;
boolean hasWitherSkeletonType = false;
boolean hasZombieVillagerType = false;
try {
hasStrayType = (EntityType.valueOf("STRAY") != null);
} catch (Exception e) {
}
try {
hasWitherSkeletonType = (EntityType.valueOf("WITHER_SKELETON") != null);
} catch (Exception e) {
}
try {
hasZombieVillagerType = (EntityType.valueOf("ZOMBIE_VILLAGER") != null);
} catch (Exception e) {
}
if (hasStrayType || hasWitherSkeletonType || hasZombieVillagerType) {
String objectType = shopkeeperSection.getString("object");
if ("skeleton".equalsIgnoreCase(objectType)) {
String skeletonType = shopkeeperSection.getString("skeletonType");
if (hasStrayType && "STRAY".equalsIgnoreCase(skeletonType)) {
Log.warning("Converting skeleton shopkeeper '" + id + "' with stray variant to new stray shopkeeper.");
shopkeeperSection.set("object", "stray");
} else if (hasWitherSkeletonType && "WITHER".equalsIgnoreCase(skeletonType)) {
Log.warning("Converting skeleton shopkeeper '" + id + "' with wither variant to new wither-skeleton shopkeeper.");
shopkeeperSection.set("object", "wither_skeleton");
}
}
if ("zombie".equalsIgnoreCase(objectType)) {
if (hasZombieVillagerType && shopkeeperSection.getBoolean("villagerZombie")) {
Log.warning("Converting zombie shopkeeper '" + id + "' with zombie-villager variant to new zombie-villager shopkeeper.");
shopkeeperSection.set("object", "zombie_villager");
}
}
}
// load shopkeeper:
try {
Shopkeeper shopkeeper = shopType.loadShopkeeper(shopkeeperSection);
if (shopkeeper == null) {
throw new ShopkeeperCreateException("ShopType returned null shopkeeper!");
}
} catch (ShopkeeperCreateException e) {
Log.warning("Failed to load shopkeeper '" + id + "': " + e.getMessage());
return false;
}
}
return true;

And it should print warnings in case the shops couldn't be loaded at chunk loads.

I am also going to added an info message at plugin start for the next update, indicating how many shops were sucessfully loaded/found in the save data.

commented

Also forgot to ask, but if you by chance still have the save file for which this can be reproduced, that would be helpful of course.

commented

The save file you sent me loads fine for me, so I can't really do anything about this issue right now.

The plugin already catches issues during loading of the save.yml file and then disables the plugin in order for the save data to not get lost. And it should at least print a stack trace if there is an unexpected error during loading of the individual shopkeepers, and in 1.84 it now catches any unexpected error there as well. So that in case the issue is related to loading a specific shopkeeper it should in the future disable the plugin instead of continuing and the potentially overwriting the save data later.

Edit: Actually, I just found a bug with the loading: Did your save.yml file by chance get larger than 1024kb in the past? I just tested with a massive amount of empty shopkeepers (10000) which yields a save file of 2000kb, and Shopkeepers will then only load the first 5000 of those shopkeepers, corresponding to the first 1024kb of the save file.

Edit: Nevermind, I confused the number of total loaded shops with the number of activated shops. Loading works fine for me even with 10000 (empty) shopkeepers.

I will change a minor thing with the next update (basically letting bukkit itself read the file contents, instead of having that in the plugin itself). But that shouldn't change any behavior.
And I will completely suround the loading procedure with a catch-all-errors code-block. So in case anything unexpected happens during loading, it will shut down the plugin and print a stack trace.
Hopefully this helps finding the issue the next time this occurs, and at the same time protect your save data. However, if the server goes online and Shopkeepers got disabled, all the chests will of course be unprotected. There is nothing I can do about that..

I will upload v1.85 with this change now, so you can start using it right away. I will close this ticket for the time being, until more information becomes available on this.

commented

This has happened a few (like 3 or 4 times) times in the 3-4 years I've been using your plugin. I wouldn't call it a very common event. I'm sorry to say I lost the logs, but I'll try to keep a look out for next time... I think I saw nothing when it happened.
I'll send you the current file through bukkit. However, I'd say pretty much anithing could be sparking this issue. It's thousands of lines of save data...