Replacing old inventory protecting with safe packet modifications using ProtocolLib.

Instead of clearing the inventory of players and storing it's contents in a file, we now prevent
the server from sending the inventory packet if the player is not logged in. The player will
see a empty inventory, but has still his items stored on the server. Therefore we don't
need to modify the player's inventory and we won't make any inventory corrupted.

Fixes Xephi/AuthMeReloaded#203,
Fixes Xephi/AuthMeReloaded#193,
Fixes Xephi/AuthMeReloaded#191,
Fixes Xephi/AuthMeReloaded#148

Remove dead code + Fix empty inventory on the unregister command

Fix NPE if ProtocolLib isn't enabled or installed
This commit is contained in:
games647 2015-09-30 18:55:41 +02:00
parent a013a6c54f
commit 86ff20b6c9
19 changed files with 1464 additions and 1537 deletions

View File

@ -294,6 +294,14 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!--ProtocolLib http://dev.bukkit.org/bukkit-plugins/protocollib/ -->
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>3.4.0</version>
<optional>true</optional>
</dependency>
<!-- Vault, http://dev.bukkit.org/bukkit-plugins/vault/ --> <!-- Vault, http://dev.bukkit.org/bukkit-plugins/vault/ -->
<dependency> <dependency>
<groupId>net.milkbowl.vault</groupId> <groupId>net.milkbowl.vault</groupId>

View File

@ -1,5 +1,6 @@
package fr.xephi.authme; package fr.xephi.authme;
import com.comphenix.protocol.ProtocolLibrary;
import com.earth2me.essentials.Essentials; import com.earth2me.essentials.Essentials;
import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.MultiverseCore;
import fr.xephi.authme.api.API; import fr.xephi.authme.api.API;
@ -73,6 +74,7 @@ public class AuthMe extends JavaPlugin {
public Essentials ess; public Essentials ess;
public MultiverseCore multiverse; public MultiverseCore multiverse;
public CombatTagPlus combatTagPlus; public CombatTagPlus combatTagPlus;
public AuthMeInventoryListener inventoryProtector;
// Manager // Manager
private ModuleManager moduleManager; private ModuleManager moduleManager;
@ -199,6 +201,9 @@ public class AuthMe extends JavaPlugin {
// Check Essentials // Check Essentials
checkEssentials(); checkEssentials();
//Check if the protocollib is available. If so we could listen for inventory protection
checkProtocolLib();
// Do backup on start if enabled // Do backup on start if enabled
if (Settings.isBackupActivated && Settings.isBackupOnStart) { if (Settings.isBackupActivated && Settings.isBackupOnStart) {
// Do backup and check return value! // Do backup and check return value!
@ -221,7 +226,7 @@ public class AuthMe extends JavaPlugin {
} }
// Setup the inventory backup // Setup the inventory backup
playerBackup = new JsonCache(this); playerBackup = new JsonCache();
// Set the DataManager // Set the DataManager
dataManager = new DataManager(this); dataManager = new DataManager(this);
@ -523,6 +528,13 @@ public class AuthMe extends JavaPlugin {
} }
} }
public void checkProtocolLib() {
if (server.getPluginManager().isPluginEnabled("ProtocolLib")) {
inventoryProtector = new AuthMeInventoryListener(this);
ProtocolLibrary.getProtocolManager().addPacketListener(inventoryProtector);
}
}
// Check if a player/command sender have a permission // Check if a player/command sender have a permission
public boolean authmePermissible(Player player, String perm) { public boolean authmePermissible(Player player, String perm) {
if (player.hasPermission(perm)) { if (player.hasPermission(perm)) {
@ -554,13 +566,10 @@ public class AuthMe extends JavaPlugin {
} }
if (LimboCache.getInstance().hasLimboPlayer(name)) { if (LimboCache.getInstance().hasLimboPlayer(name)) {
LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name);
if (Settings.protectInventoryBeforeLogInEnabled) {
player.getInventory().setArmorContents(limbo.getArmour());
player.getInventory().setContents(limbo.getInventory());
}
if (!Settings.noTeleport) { if (!Settings.noTeleport) {
player.teleport(limbo.getLoc()); player.teleport(limbo.getLoc());
} }
Utils.addNormal(player, limbo.getGroup()); Utils.addNormal(player, limbo.getGroup());
player.setOp(limbo.getOperator()); player.setOp(limbo.getOperator());
limbo.getTimeoutTaskId().cancel(); limbo.getTimeoutTaskId().cancel();

View File

@ -1,36 +1,17 @@
package fr.xephi.authme.cache.backup; package fr.xephi.authme.cache.backup;
import org.bukkit.inventory.ItemStack;
public class DataFileCache { public class DataFileCache {
private ItemStack[] inventory;
private ItemStack[] armor;
private String group; private String group;
private boolean operator; private boolean operator;
private boolean flying; private boolean flying;
public DataFileCache(ItemStack[] inventory, ItemStack[] armor) { public DataFileCache(String group, boolean operator, boolean flying) {
this(inventory, armor, "", false, false);
}
public DataFileCache(ItemStack[] inventory, ItemStack[] armor,
String group, boolean operator, boolean flying) {
this.inventory = inventory;
this.armor = armor;
this.group = group; this.group = group;
this.operator = operator; this.operator = operator;
this.flying = flying; this.flying = flying;
} }
public ItemStack[] getInventory() {
return inventory;
}
public ItemStack[] getArmour() {
return armor;
}
public String getGroup() { public String getGroup() {
return group; return group;
} }

View File

@ -3,20 +3,13 @@ package fr.xephi.authme.cache.backup;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.io.Files; import com.google.common.io.Files;
import com.google.gson.*; import com.google.gson.*;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.Utils; import fr.xephi.authme.Utils;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.ByteArrayInputStream; import org.bukkit.entity.Player;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -24,11 +17,9 @@ import java.lang.reflect.Type;
public class JsonCache { public class JsonCache {
private final Gson gson; private final Gson gson;
private final AuthMe plugin;
private final File cacheDir; private final File cacheDir;
public JsonCache(AuthMe plugin) { public JsonCache() {
this.plugin = plugin;
cacheDir = Settings.CACHE_FOLDER; cacheDir = Settings.CACHE_FOLDER;
if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) { if (!cacheDir.exists() && !cacheDir.isDirectory() && !cacheDir.mkdir()) {
ConsoleLogger.showError("Failed to create cache directory."); ConsoleLogger.showError("Failed to create cache directory.");
@ -99,49 +90,8 @@ public class JsonCache {
jsonObject.addProperty("operator", dataFileCache.getOperator()); jsonObject.addProperty("operator", dataFileCache.getOperator());
jsonObject.addProperty("flying", dataFileCache.isFlying()); jsonObject.addProperty("flying", dataFileCache.isFlying());
JsonArray arr;
ItemStack[] contents;
// inventory
contents = dataFileCache.getInventory();
arr = new JsonArray();
putItems(contents, arr);
jsonObject.add("inventory", arr);
// armour
contents = dataFileCache.getArmour();
arr = new JsonArray();
putItems(contents, arr);
jsonObject.add("armour", arr);
return jsonObject; return jsonObject;
} }
private void putItems(ItemStack[] contents, JsonArray target) {
for (ItemStack item : contents) {
if (item == null) {
item = new ItemStack(Material.AIR);
}
JsonObject val = new JsonObject();
if (item.getType() == Material.SKULL_ITEM) {
SkullMeta meta = (SkullMeta) item.getItemMeta();
if (meta.hasOwner() && (meta.getOwner() == null || meta.getOwner().isEmpty())) {
item.setItemMeta(plugin.getServer().getItemFactory().getItemMeta(Material.SKULL_ITEM));
}
}
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BukkitObjectOutputStream objectOut = new BukkitObjectOutputStream(baos);
objectOut.writeObject(item);
objectOut.close();
val.addProperty("item", Base64Coder.encodeLines(baos.toByteArray()));
} catch (IOException e) {
e.printStackTrace();
continue;
}
target.add(val);
}
}
} }
private static class PlayerDataDeserializer implements JsonDeserializer<DataFileCache> { private static class PlayerDataDeserializer implements JsonDeserializer<DataFileCache> {
@ -166,39 +116,7 @@ public class JsonCache {
flying = e.getAsBoolean(); flying = e.getAsBoolean();
} }
JsonArray arr; return new DataFileCache(group, operator, flying);
ItemStack[] inv = null;
ItemStack[] armour = null;
if (jsonObject.has("inventory")) {
arr = jsonObject.get("inventory").getAsJsonArray();
inv = getItems(arr);
}
if (jsonObject.has("armour")) {
arr = jsonObject.get("armour").getAsJsonArray();
armour = getItems(arr);
}
return new DataFileCache(inv, armour, group, operator, flying);
}
private ItemStack[] getItems(JsonArray arr) {
ItemStack[] contents = new ItemStack[arr.size()];
for (int i = 0; i < arr.size(); i++) {
JsonObject item = arr.get(i).getAsJsonObject();
String encoded = item.get("item").getAsString();
byte[] decoded = Base64Coder.decodeLines(encoded);
try {
ByteArrayInputStream baos = new ByteArrayInputStream(decoded);
BukkitObjectInputStream objectIn = new BukkitObjectInputStream(baos);
contents[i] = (ItemStack) objectIn.readObject();
objectIn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return contents;
} }
} }

View File

@ -11,7 +11,6 @@ import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -25,15 +24,13 @@ public class LimboCache {
private LimboCache(AuthMe plugin) { private LimboCache(AuthMe plugin) {
this.plugin = plugin; this.plugin = plugin;
this.cache = new ConcurrentHashMap<>(); this.cache = new ConcurrentHashMap<>();
this.playerData = new JsonCache(plugin); this.playerData = new JsonCache();
} }
public void addLimboPlayer(Player player) { public void addLimboPlayer(Player player) {
String name = player.getName().toLowerCase(); String name = player.getName().toLowerCase();
Location loc = player.getLocation(); Location loc = player.getLocation();
GameMode gameMode = player.getGameMode(); GameMode gameMode = player.getGameMode();
ItemStack[] arm;
ItemStack[] inv;
boolean operator = false; boolean operator = false;
String playerGroup = ""; String playerGroup = "";
boolean flying = false; boolean flying = false;
@ -42,12 +39,10 @@ public class LimboCache {
final StoreInventoryEvent event = new StoreInventoryEvent(player, playerData); final StoreInventoryEvent event = new StoreInventoryEvent(player, playerData);
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled() && event.getInventory() != null && event.getArmor() != null) { if (!event.isCancelled() && event.getInventory() != null && event.getArmor() != null) {
inv = event.getInventory(); player.getInventory().setContents(event.getInventory());
arm = event.getArmor(); player.getInventory().setArmorContents(event.getArmor());
} else {
inv = null;
arm = null;
} }
DataFileCache cache = playerData.readCache(player); DataFileCache cache = playerData.readCache(player);
if (cache != null) { if (cache != null) {
playerGroup = cache.getGroup(); playerGroup = cache.getGroup();
@ -58,12 +53,10 @@ public class LimboCache {
StoreInventoryEvent event = new StoreInventoryEvent(player); StoreInventoryEvent event = new StoreInventoryEvent(player);
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled() && event.getInventory() != null && event.getArmor() != null) { if (!event.isCancelled() && event.getInventory() != null && event.getArmor() != null) {
inv = event.getInventory(); player.getInventory().setContents(event.getInventory());
arm = event.getArmor(); player.getInventory().setArmorContents(event.getArmor());
} else {
inv = null;
arm = null;
} }
operator = player.isOp(); operator = player.isOp();
flying = player.isFlying(); flying = player.isFlying();
if (plugin.permission != null) { if (plugin.permission != null) {
@ -93,7 +86,7 @@ public class LimboCache {
if (player.isDead()) { if (player.isDead()) {
loc = plugin.getSpawnLocation(player); loc = plugin.getSpawnLocation(player);
} }
cache.put(name, new LimboPlayer(name, loc, inv, arm, gameMode, operator, playerGroup, flying)); cache.put(name, new LimboPlayer(name, loc, gameMode, operator, playerGroup, flying));
} }
public void addLimboPlayer(Player player, String group) { public void addLimboPlayer(Player player, String group) {

View File

@ -2,14 +2,11 @@ package fr.xephi.authme.cache.limbo;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
public class LimboPlayer { public class LimboPlayer {
private String name; private String name;
private ItemStack[] inventory;
private ItemStack[] armour;
private Location loc = null; private Location loc = null;
private BukkitTask timeoutTaskId = null; private BukkitTask timeoutTaskId = null;
private BukkitTask messageTaskId = null; private BukkitTask messageTaskId = null;
@ -18,19 +15,6 @@ public class LimboPlayer {
private String group = ""; private String group = "";
private boolean flying = false; private boolean flying = false;
public LimboPlayer(String name, Location loc, ItemStack[] inventory,
ItemStack[] armour, GameMode gameMode, boolean operator,
String group, boolean flying) {
this.name = name;
this.loc = loc;
this.inventory = inventory;
this.armour = armour;
this.gameMode = gameMode;
this.operator = operator;
this.group = group;
this.flying = flying;
}
public LimboPlayer(String name, Location loc, GameMode gameMode, public LimboPlayer(String name, Location loc, GameMode gameMode,
boolean operator, String group, boolean flying) { boolean operator, String group, boolean flying) {
this.name = name; this.name = name;
@ -54,22 +38,6 @@ public class LimboPlayer {
return loc; return loc;
} }
public ItemStack[] getArmour() {
return armour;
}
public ItemStack[] getInventory() {
return inventory;
}
public void setArmour(ItemStack[] armour) {
this.armour = armour;
}
public void setInventory(ItemStack[] inventory) {
this.inventory = inventory;
}
public GameMode getGameMode() { public GameMode getGameMode() {
return gameMode; return gameMode;
} }
@ -105,5 +73,4 @@ public class LimboPlayer {
public boolean isFlying() { public boolean isFlying() {
return flying; return flying;
} }
} }

View File

@ -18,7 +18,6 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
@ -34,7 +33,7 @@ public class UnregisterCommand implements CommandExecutor {
public UnregisterCommand(AuthMe plugin) { public UnregisterCommand(AuthMe plugin) {
this.plugin = plugin; this.plugin = plugin;
this.playerCache = new JsonCache(plugin); this.playerCache = new JsonCache();
} }
@Override @Override
@ -79,8 +78,7 @@ public class UnregisterCommand implements CommandExecutor {
player.teleport(tpEvent.getTo()); player.teleport(tpEvent.getTo());
} }
} }
player.getInventory().setContents(new ItemStack[36]);
player.getInventory().setArmorContents(new ItemStack[4]);
player.saveData(); player.saveData();
PlayerCache.getInstance().removePlayer(player.getName().toLowerCase()); PlayerCache.getInstance().removePlayer(player.getName().toLowerCase());
if (!Settings.getRegisteredGroup.isEmpty()) if (!Settings.getRegisteredGroup.isEmpty())

View File

@ -18,12 +18,11 @@ public class ProtectInventoryEvent extends CustomEvent {
private ItemStack[] emptyArmor = null; private ItemStack[] emptyArmor = null;
private Player player; private Player player;
public ProtectInventoryEvent(Player player, ItemStack[] storedinventory, public ProtectInventoryEvent(Player player) {
ItemStack[] storedarmor) {
super(true); super(true);
this.player = player; this.player = player;
this.storedinventory = storedinventory; this.storedinventory = player.getInventory().getContents();
this.storedarmor = storedarmor; this.storedarmor = player.getInventory().getArmorContents();
this.emptyInventory = new ItemStack[36]; this.emptyInventory = new ItemStack[36];
this.emptyArmor = new ItemStack[4]; this.emptyArmor = new ItemStack[4];
} }

View File

@ -4,8 +4,7 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
/** /**
* * This event restore the inventory.
* This event restore the inventory from cache
* *
* @author Xephi59 * @author Xephi59
*/ */
@ -15,16 +14,14 @@ public class RestoreInventoryEvent extends CustomEvent {
private ItemStack[] armor; private ItemStack[] armor;
private Player player; private Player player;
public RestoreInventoryEvent(Player player, ItemStack[] inventory, public RestoreInventoryEvent(Player player) {
ItemStack[] armor) {
this.player = player; this.player = player;
this.inventory = inventory; this.inventory = player.getInventory().getContents();
this.armor = armor; this.armor = player.getInventory().getArmorContents();
} }
public RestoreInventoryEvent(Player player, ItemStack[] inventory, public RestoreInventoryEvent(Player player, boolean async) {
ItemStack[] armor, boolean b) { super(async);
super(b);
this.player = player; this.player = player;
this.inventory = inventory; this.inventory = inventory;
this.armor = armor; this.armor = armor;
@ -53,5 +50,4 @@ public class RestoreInventoryEvent extends CustomEvent {
public void setPlayer(Player player) { public void setPlayer(Player player) {
this.player = player; this.player = player;
} }
} }

View File

@ -1,6 +1,5 @@
package fr.xephi.authme.events; package fr.xephi.authme.events;
import fr.xephi.authme.cache.backup.DataFileCache;
import fr.xephi.authme.cache.backup.JsonCache; import fr.xephi.authme.cache.backup.JsonCache;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -24,14 +23,8 @@ public class StoreInventoryEvent extends CustomEvent {
public StoreInventoryEvent(Player player, JsonCache jsonCache) { public StoreInventoryEvent(Player player, JsonCache jsonCache) {
this.player = player; this.player = player;
DataFileCache cache = jsonCache.readCache(player); this.inventory = player.getInventory().getContents();
if (cache != null) { this.armor = player.getInventory().getArmorContents();
this.inventory = cache.getInventory();
this.armor = cache.getArmour();
} else {
this.inventory = player.getInventory().getContents();
this.armor = player.getInventory().getArmorContents();
}
} }
public ItemStack[] getInventory() { public ItemStack[] getInventory() {
@ -57,5 +50,4 @@ public class StoreInventoryEvent extends CustomEvent {
public void setPlayer(Player player) { public void setPlayer(Player player) {
this.player = player; this.player = player;
} }
} }

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2015 AuthMe-Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.xephi.authme.listener;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.settings.Settings;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.logging.Level;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class AuthMeInventoryListener extends PacketAdapter {
private static final int PLAYER_INVENTORY = 0;
//http://wiki.vg/Inventory#Inventory (0-4 crafting, 5-8 armor, 9-35 main inventory, 36-44 inventory)
//+1 because an index starts with 0
private static final int PLAYER_CRAFTING_SIZE = 5;
private static final int HOTBAR_SIZE = 9;
public AuthMeInventoryListener(AuthMe plugin) {
super(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS);
}
@Override
public void onPacketSending(PacketEvent packetEvent) {
Player player = packetEvent.getPlayer();
PacketContainer packet = packetEvent.getPacket();
byte windowId = packet.getIntegers().read(0).byteValue();
if (windowId == PLAYER_INVENTORY && Settings.protectInventoryBeforeLogInEnabled
&& !PlayerCache.getInstance().isAuthenticated(player.getName())) {
packetEvent.setCancelled(true);
}
}
public void sendInventoryPacket(Player player) {
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
PacketContainer inventoryPacket = protocolManager.createPacket(PacketType.Play.Server.WINDOW_ITEMS);
//we are sending our own inventory
inventoryPacket.getIntegers().write(0, PLAYER_INVENTORY);
ItemStack[] playerCrafting = new ItemStack[PLAYER_CRAFTING_SIZE];
ItemStack[] armorContents = player.getInventory().getArmorContents();
ItemStack[] mainInventory = player.getInventory().getContents();
//bukkit saves the armor in reversed order
Collections.reverse(Arrays.asList(armorContents));
//same main inventory. The hotbar is at the beginning but it should be at the end of the array
ItemStack[] hotbar = Arrays.copyOfRange(mainInventory, 0, HOTBAR_SIZE);
ItemStack[] storedInventory = Arrays.copyOfRange(mainInventory, HOTBAR_SIZE, mainInventory.length);
//concat all parts of the inventory together
int inventorySize = playerCrafting.length + armorContents.length + mainInventory.length;
ItemStack[] completeInventory = new ItemStack[inventorySize];
System.arraycopy(playerCrafting, 0, completeInventory, 0, playerCrafting.length);
System.arraycopy(armorContents, 0, completeInventory, playerCrafting.length, armorContents.length);
//storedInventory and hotbar
System.arraycopy(storedInventory, 0, completeInventory
, playerCrafting.length + armorContents.length, storedInventory.length);
System.arraycopy(hotbar, 0, completeInventory
, playerCrafting.length + armorContents.length + storedInventory.length, hotbar.length);
inventoryPacket.getItemArrayModifier().write(0, completeInventory);
try {
protocolManager.sendServerPacket(player, inventoryPacket, false);
} catch (InvocationTargetException invocationExc) {
plugin.getLogger().log(Level.WARNING, "Error during inventory recovery", invocationExc);
}
}
}

View File

@ -68,6 +68,10 @@ public class AuthMeServerListener implements Listener {
plugin.permission = null; plugin.permission = null;
ConsoleLogger.showError("Vault has been disabled, unhook permissions!"); ConsoleLogger.showError("Vault has been disabled, unhook permissions!");
} }
if (pluginName.equalsIgnoreCase("ProtocolLib")) {
plugin.inventoryProtector = null;
ConsoleLogger.showError("ProtocolLib has been disabled, unhook packet inventory protection!");
}
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
@ -83,5 +87,8 @@ public class AuthMeServerListener implements Listener {
plugin.checkCombatTagPlus(); plugin.checkCombatTagPlus();
if (pluginName.equalsIgnoreCase("Vault")) if (pluginName.equalsIgnoreCase("Vault"))
plugin.checkVault(); plugin.checkVault();
if (pluginName.equalsIgnoreCase("ProtocolLib")) {
plugin.checkProtocolLib();
}
} }
} }

View File

@ -6,10 +6,7 @@ import fr.xephi.authme.Utils;
import fr.xephi.authme.Utils.GroupType; import fr.xephi.authme.Utils.GroupType;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.backup.DataFileCache;
import fr.xephi.authme.cache.backup.JsonCache;
import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.cache.limbo.LimboPlayer;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.FirstSpawnTeleportEvent; import fr.xephi.authme.events.FirstSpawnTeleportEvent;
import fr.xephi.authme.events.ProtectInventoryEvent; import fr.xephi.authme.events.ProtectInventoryEvent;
@ -26,7 +23,6 @@ import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
@ -39,13 +35,11 @@ public class AsyncronousJoin {
protected AuthMe plugin; protected AuthMe plugin;
protected String name; protected String name;
private Messages m = Messages.getInstance(); private Messages m = Messages.getInstance();
private JsonCache playerBackup;
public AsyncronousJoin(Player player, AuthMe plugin, DataSource database) { public AsyncronousJoin(Player player, AuthMe plugin, DataSource database) {
this.player = player; this.player = player;
this.plugin = plugin; this.plugin = plugin;
this.database = database; this.database = database;
this.playerBackup = new JsonCache(plugin);
this.name = player.getName().toLowerCase(); this.name = player.getName().toLowerCase();
} }
@ -127,27 +121,14 @@ public class AsyncronousJoin {
} }
placePlayerSafely(player, spawnLoc); placePlayerSafely(player, spawnLoc);
LimboCache.getInstance().updateLimboPlayer(player); LimboCache.getInstance().updateLimboPlayer(player);
DataFileCache dataFile = new DataFileCache(LimboCache.getInstance().getLimboPlayer(name).getInventory(), LimboCache.getInstance().getLimboPlayer(name).getArmour());
playerBackup.createCache(player, dataFile);
// protect inventory // protect inventory
if (Settings.protectInventoryBeforeLogInEnabled) { if (Settings.protectInventoryBeforeLogInEnabled && plugin.inventoryProtector != null) {
LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(player.getName().toLowerCase()); ProtectInventoryEvent ev = new ProtectInventoryEvent(player);
ProtectInventoryEvent ev = new ProtectInventoryEvent(player, limbo.getInventory(), limbo.getArmour());
plugin.getServer().getPluginManager().callEvent(ev); plugin.getServer().getPluginManager().callEvent(ev);
if (ev.isCancelled()) { if (ev.isCancelled()) {
plugin.inventoryProtector.sendInventoryPacket(player);
if (!Settings.noConsoleSpam) if (!Settings.noConsoleSpam)
ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + " ..."); ConsoleLogger.info("ProtectInventoryEvent has been cancelled for " + player.getName() + " ...");
} else {
final ItemStack[] inv = ev.getEmptyArmor();
final ItemStack[] armor = ev.getEmptyArmor();
sched.scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
plugin.api.setPlayerInventory(player, inv, armor);
}
});
} }
} }
} else { } else {

View File

@ -42,7 +42,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable {
this.name = player.getName().toLowerCase(); this.name = player.getName().toLowerCase();
this.limbo = LimboCache.getInstance().getLimboPlayer(name); this.limbo = LimboCache.getInstance().getLimboPlayer(name);
this.auth = database.getAuth(name); this.auth = database.getAuth(name);
this.playerCache = new JsonCache(plugin); this.playerCache = new JsonCache();
} }
public LimboPlayer getLimbo() { public LimboPlayer getLimbo() {
@ -92,10 +92,11 @@ public class ProcessSyncronousPlayerLogin implements Runnable {
} }
protected void restoreInventory() { protected void restoreInventory() {
RestoreInventoryEvent event = new RestoreInventoryEvent(player, limbo.getInventory(), limbo.getArmour()); RestoreInventoryEvent event = new RestoreInventoryEvent(player);
Bukkit.getServer().getPluginManager().callEvent(event); Bukkit.getServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) { if (!event.isCancelled()) {
plugin.api.setPlayerInventory(player, event.getInventory(), event.getArmor()); plugin.api.setPlayerInventory(player, event.getInventory(), event.getArmor());
plugin.inventoryProtector.sendInventoryPacket(player);
} }
} }
@ -128,7 +129,7 @@ public class ProcessSyncronousPlayerLogin implements Runnable {
// Inventory - Make it after restore GameMode , cause we need to // Inventory - Make it after restore GameMode , cause we need to
// restore the // restore the
// right inventory in the right gamemode // right inventory in the right gamemode
if (Settings.protectInventoryBeforeLogInEnabled && player.hasPlayedBefore()) { if (Settings.protectInventoryBeforeLogInEnabled && plugin.inventoryProtector != null) {
restoreInventory(); restoreInventory();
} }
if (Settings.forceOnlyAfterLogin) { if (Settings.forceOnlyAfterLogin) {

View File

@ -9,8 +9,6 @@ import fr.xephi.authme.Utils;
import fr.xephi.authme.Utils.GroupType; import fr.xephi.authme.Utils.GroupType;
import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.backup.DataFileCache;
import fr.xephi.authme.cache.backup.JsonCache;
import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.AuthMeTeleportEvent; import fr.xephi.authme.events.AuthMeTeleportEvent;
@ -25,7 +23,6 @@ public class AsyncronousLogout {
protected DataSource database; protected DataSource database;
protected boolean canLogout = true; protected boolean canLogout = true;
private Messages m = Messages.getInstance(); private Messages m = Messages.getInstance();
private JsonCache playerBackup;
public AsyncronousLogout(Player player, AuthMe plugin, public AsyncronousLogout(Player player, AuthMe plugin,
DataSource database) { DataSource database) {
@ -33,7 +30,6 @@ public class AsyncronousLogout {
this.plugin = plugin; this.plugin = plugin;
this.database = database; this.database = database;
this.name = player.getName().toLowerCase(); this.name = player.getName().toLowerCase();
this.playerBackup = new JsonCache(plugin);
} }
private void preLogout() { private void preLogout() {
@ -79,13 +75,7 @@ public class AsyncronousLogout {
LimboCache.getInstance().deleteLimboPlayer(name); LimboCache.getInstance().deleteLimboPlayer(name);
LimboCache.getInstance().addLimboPlayer(player); LimboCache.getInstance().addLimboPlayer(player);
Utils.setGroup(player, GroupType.NOTLOGGEDIN); Utils.setGroup(player, GroupType.NOTLOGGEDIN);
if (Settings.protectInventoryBeforeLogInEnabled) {
player.getInventory().clear();
// create cache file for handling lost of inventories on unlogged in
// status
DataFileCache playerData = new DataFileCache(LimboCache.getInstance().getLimboPlayer(name).getInventory(), LimboCache.getInstance().getLimboPlayer(name).getArmour());
playerBackup.createCache(player, playerData);
}
sched.scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerLogout(p, plugin)); sched.scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerLogout(p, plugin));
} }
} }

View File

@ -3,7 +3,6 @@ package fr.xephi.authme.process.quit;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
@ -13,7 +12,6 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.cache.limbo.LimboPlayer;
import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.RestoreInventoryEvent;
import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.listener.AuthMePlayerListener;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
@ -23,8 +21,6 @@ public class AsyncronousQuit {
protected DataSource database; protected DataSource database;
protected Player player; protected Player player;
private String name; private String name;
private ItemStack[] armor = null;
private ItemStack[] inv = null;
private boolean isOp = false; private boolean isOp = false;
private boolean isFlying = false; private boolean isFlying = false;
private boolean needToChange = false; private boolean needToChange = false;
@ -60,10 +56,6 @@ public class AsyncronousQuit {
if (LimboCache.getInstance().hasLimboPlayer(name)) { if (LimboCache.getInstance().hasLimboPlayer(name)) {
LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name);
if (Settings.protectInventoryBeforeLogInEnabled && player.hasPlayedBefore()) {
inv = limbo.getInventory();
armor = limbo.getArmour();
}
if (limbo.getGroup() != null && !limbo.getGroup().equals("")) if (limbo.getGroup() != null && !limbo.getGroup().equals(""))
Utils.addNormal(player, limbo.getGroup()); Utils.addNormal(player, limbo.getGroup());
needToChange = true; needToChange = true;
@ -94,17 +86,8 @@ public class AsyncronousQuit {
PlayerCache.getInstance().removePlayer(name); PlayerCache.getInstance().removePlayer(name);
database.setUnlogged(name); database.setUnlogged(name);
} }
AuthMePlayerListener.gameMode.remove(name); AuthMePlayerListener.gameMode.remove(name);
final Player p = player; Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerQuit(plugin, player, isOp, isFlying, needToChange));
RestoreInventoryEvent ev = new RestoreInventoryEvent(player, inv, armor, true);
Bukkit.getPluginManager().callEvent(ev);
if (ev.isCancelled()) {
inv = null;
armor = null;
} else {
inv = ev.getInventory();
armor = ev.getArmor();
}
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerQuit(plugin, p, inv, armor, isOp, isFlying, needToChange));
} }
} }

View File

@ -2,10 +2,11 @@ package fr.xephi.authme.process.quit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import fr.xephi.authme.AuthMe; import fr.xephi.authme.AuthMe;
import fr.xephi.authme.events.RestoreInventoryEvent;
import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Settings;
import org.bukkit.Bukkit;
public class ProcessSyncronousPlayerQuit implements Runnable { public class ProcessSyncronousPlayerQuit implements Runnable {
@ -13,26 +14,26 @@ public class ProcessSyncronousPlayerQuit implements Runnable {
protected Player player; protected Player player;
protected boolean isOp; protected boolean isOp;
protected boolean isFlying; protected boolean isFlying;
protected ItemStack[] inv;
protected ItemStack[] armor;
protected boolean needToChange; protected boolean needToChange;
public ProcessSyncronousPlayerQuit(AuthMe plugin, Player player, public ProcessSyncronousPlayerQuit(AuthMe plugin, Player player
ItemStack[] inv, ItemStack[] armor, boolean isOp, boolean isFlying, , boolean isOp, boolean isFlying
boolean needToChange) { , boolean needToChange) {
this.plugin = plugin; this.plugin = plugin;
this.player = player; this.player = player;
this.isOp = isOp; this.isOp = isOp;
this.isFlying = isFlying; this.isFlying = isFlying;
this.armor = armor;
this.inv = inv;
this.needToChange = needToChange; this.needToChange = needToChange;
} }
@Override @Override
public void run() { public void run() {
if (inv != null && armor != null) RestoreInventoryEvent ev = new RestoreInventoryEvent(player);
plugin.api.setPlayerInventory(player, inv, armor); Bukkit.getPluginManager().callEvent(ev);
if (!ev.isCancelled()) {
plugin.api.setPlayerInventory(player, ev.getInventory(), ev.getArmor());
}
if (needToChange) { if (needToChange) {
player.setOp(isOp); player.setOp(isOp);
if (player.getGameMode() != GameMode.CREATIVE && !Settings.isMovementAllowed) { if (player.getGameMode() != GameMode.CREATIVE && !Settings.isMovementAllowed) {

View File

@ -91,14 +91,17 @@ public class ProcessSyncronousPasswordRegister implements Runnable {
player.teleport(tpEvent.getTo()); player.teleport(tpEvent.getTo());
} }
} }
if (Settings.protectInventoryBeforeLogInEnabled && limbo.getInventory() != null && limbo.getArmour() != null) {
RestoreInventoryEvent event = new RestoreInventoryEvent(player, limbo.getInventory(), limbo.getArmour()); if (Settings.protectInventoryBeforeLogInEnabled && plugin.inventoryProtector != null) {
RestoreInventoryEvent event = new RestoreInventoryEvent(player);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled() && event.getArmor() != null && event.getInventory() != null) { if (!event.isCancelled() && event.getArmor() != null && event.getInventory() != null) {
player.getInventory().setContents(event.getInventory()); player.getInventory().setContents(event.getInventory());
player.getInventory().setArmorContents(event.getArmor()); player.getInventory().setArmorContents(event.getArmor());
plugin.inventoryProtector.sendInventoryPacket(player);
} }
} }
limbo.getTimeoutTaskId().cancel(); limbo.getTimeoutTaskId().cancel();
limbo.getMessageTaskId().cancel(); limbo.getMessageTaskId().cancel();
LimboCache.getInstance().deleteLimboPlayer(name); LimboCache.getInstance().deleteLimboPlayer(name);
@ -153,6 +156,5 @@ public class ProcessSyncronousPasswordRegister implements Runnable {
// Register is now finish , we can force all commands // Register is now finish , we can force all commands
forceCommands(); forceCommands();
} }
} }

View File

@ -4,7 +4,7 @@ website: http://dev.bukkit.org/bukkit-plugins/authme-reloaded/
description: AuthMe prevents people, which aren't logged in, from doing stuff like placing blocks, moving, typing commands or seeing the inventory of the player. description: AuthMe prevents people, which aren't logged in, from doing stuff like placing blocks, moving, typing commands or seeing the inventory of the player.
main: fr.xephi.authme.AuthMe main: fr.xephi.authme.AuthMe
version: ${project.version} version: ${project.version}
softdepend: [Vault, ChestShop, Multiverse-Core, Citizens, CombatTag, Essentials, EssentialsSpawn, PerWorldInventories] softdepend: [Vault, ChestShop, Multiverse-Core, Citizens, CombatTag, Essentials, EssentialsSpawn, PerWorldInventories, ProtocolLib]
commands: commands:
register: register:
description: Register an account description: Register an account