diff --git a/src/com/massivecraft/mcore/EngineOfflineCase.java b/src/com/massivecraft/mcore/EngineOfflineCase.java new file mode 100644 index 00000000..3048fa18 --- /dev/null +++ b/src/com/massivecraft/mcore/EngineOfflineCase.java @@ -0,0 +1,131 @@ +package com.massivecraft.mcore; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerLoginEvent.Result; + +import com.massivecraft.mcore.util.MUtil; +import com.massivecraft.mcore.util.Txt; + +/** + * In minecraft a player name is case insensitive but has one and only one correct casing when written out. + * The correct casing is decided upon buying minecraft. + * If you register "Steve" noone else can register "stEvE". + * + * If you then try to log in using "STEVE" in the minecraft launcher the name will be corrected to "Steve". + * This feature does however only work in online mode. + * + * If you use a cracked client and an offline mode server you may log on to the server using both "Steve" and "STEVE". + * This cause unintended side effects. Some file systems (windows) are case insensitive and some (unix) are case sensitive. + * On Unix "Steve" and "STEVE" would have different inventories, locations etc. They would be considered different players. + * That would be confusing for the players. + * They would seem to lose their inventory when mistyping their name and this would only happen on some servers (those using unix). + * + * Additionally plugins may start acting weird if this rule is broken. + * + * The purpose of this "engine" is to enforce the use of the one and same casing for offline mode servers. + * You "register" the correct casing at the first login. + * After that you get kicked when using an incorrect casing. + * + */ +public class EngineOfflineCase implements Listener +{ + // -------------------------------------------- // + // INSTANCE & CONSTRUCT + // -------------------------------------------- // + + private static EngineOfflineCase i = new EngineOfflineCase(); + public static EngineOfflineCase get() { return i; } + + // -------------------------------------------- // + // SETUP + // -------------------------------------------- // + + public void setup() + { + this.lowerToCorrect.clear(); + + for (Player player : Bukkit.getOnlinePlayers()) + { + this.registerCase(player.getName()); + } + + for (String pdname : MUtil.getPlayerDirectoryNames()) + { + this.registerCase(pdname); + } + + Bukkit.getPluginManager().registerEvents(this, MCore.get()); + } + + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + private Map lowerToCorrect = new HashMap(); + + // -------------------------------------------- // + // UTIL + // -------------------------------------------- // + + private void registerCase(String playerName) + { + this.lowerToCorrect.put(playerName.toLowerCase(), playerName); + } + + // -------------------------------------------- // + // LISTENER + // -------------------------------------------- // + + @EventHandler(priority = EventPriority.LOWEST) + public void forceOnePlayerNameCase(PlayerLoginEvent event) + { + // Stop if the feature is disabled + if (!ConfServer.forceOnePlayerNameCase) return; + + // Stop if we are using online mode + if (Bukkit.getOnlineMode()) return; + + // Prepare some variables + final Player player = event.getPlayer(); + final String playerName = player.getName(); + final String playerNameLower = playerName.toLowerCase(); + + // Kick if the player already is online + // NOTE: Bukkit.getPlayerExact is case insensitive as it should be + final Player onlinePlayer = Bukkit.getPlayerExact(playerName); + if (onlinePlayer != null) + { + event.setResult(Result.KICK_OTHER); + event.setKickMessage(Txt.parse("The player %s is already online.", onlinePlayer.getName())); + return; + } + + // Consider dat case! + String correct = this.lowerToCorrect.get(playerNameLower); + if (correct == null) + { + // "Register" + this.registerCase(playerName); + } + else + { + // Kick if the case is wrong + if (!correct.equals(playerName)) + { + event.setResult(Result.KICK_OTHER); + event.setKickMessage(Txt.parse("Invalid uppercase and lowercase letters in name.\nPlease spell this name like \"%s\".", correct)); + return; + } + } + + } + +} diff --git a/src/com/massivecraft/mcore/WorldNameSetEngine.java b/src/com/massivecraft/mcore/EngineWorldNameSet.java similarity index 87% rename from src/com/massivecraft/mcore/WorldNameSetEngine.java rename to src/com/massivecraft/mcore/EngineWorldNameSet.java index 62e091c6..f51bf780 100644 --- a/src/com/massivecraft/mcore/WorldNameSetEngine.java +++ b/src/com/massivecraft/mcore/EngineWorldNameSet.java @@ -12,14 +12,14 @@ import org.bukkit.event.Listener; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; -public class WorldNameSetEngine implements Listener +public class EngineWorldNameSet implements Listener { // -------------------------------------------- // // INSTANCE & CONSTRUCT // -------------------------------------------- // - private static WorldNameSetEngine i = new WorldNameSetEngine(); - public static WorldNameSetEngine get() { return i; } + private static EngineWorldNameSet i = new EngineWorldNameSet(); + public static EngineWorldNameSet get() { return i; } // -------------------------------------------- // // SETUP diff --git a/src/com/massivecraft/mcore/InternalListener.java b/src/com/massivecraft/mcore/InternalListener.java index beee2edc..11dd1ce0 100644 --- a/src/com/massivecraft/mcore/InternalListener.java +++ b/src/com/massivecraft/mcore/InternalListener.java @@ -31,10 +31,8 @@ import com.massivecraft.mcore.event.MCoreSenderUnregisterEvent; import com.massivecraft.mcore.mixin.Mixin; import com.massivecraft.mcore.store.Coll; import com.massivecraft.mcore.store.SenderColl; -import com.massivecraft.mcore.util.MUtil; import com.massivecraft.mcore.util.SenderUtil; import com.massivecraft.mcore.util.SmokeUtil; -import com.massivecraft.mcore.util.Txt; import com.massivecraft.mcore.wrap.PlayerConnectionWrapMCore; public class InternalListener implements Listener @@ -56,44 +54,6 @@ public class InternalListener implements Listener Bukkit.getPluginManager().registerEvents(this, MCore.get()); } - // -------------------------------------------- // - // FORCE ONE PLAYER NAME CASE - // -------------------------------------------- // - // This is used with offline servers to prevent bugs on case sensitive file systems. - - @EventHandler(priority = EventPriority.LOWEST) - public void forceOnePlayerNameCase(PlayerLoginEvent event) - { - // If we are enforcing one player name case ... - if (!ConfServer.forceOnePlayerNameCase) return; - - // ... and the server is running in offline mode ... - if (Bukkit.getOnlineMode()) return; - - // ... prepare vars ... - Player player = event.getPlayer(); - String playerName = player.getName(); - - // ... is the player already online? ... - for (Player onlinePlayer: Bukkit.getOnlinePlayers()) - { - if (!playerName.equalsIgnoreCase(onlinePlayer.getName())) continue; - event.setResult(Result.KICK_OTHER); - event.setKickMessage(Txt.parse("The player %s is already online.", onlinePlayer.getName())); - return; - } - - // ... is the first found file name different? - for (String pdname : MUtil.getPlayerDirectoryNames()) - { - if (!playerName.equalsIgnoreCase(pdname)) continue; - if (playerName.equals(pdname)) break; - event.setResult(Result.KICK_OTHER); - event.setKickMessage(Txt.parse("Invalid uppercase and lowercase letters in name.\nPlease spell this name like \"%s\".", pdname)); - } - - } - // -------------------------------------------- // // PLAYER CONNECTION WRAP INJECTION // -------------------------------------------- // diff --git a/src/com/massivecraft/mcore/MCore.java b/src/com/massivecraft/mcore/MCore.java index 8d2c6ae1..caadb922 100644 --- a/src/com/massivecraft/mcore/MCore.java +++ b/src/com/massivecraft/mcore/MCore.java @@ -142,7 +142,8 @@ public class MCore extends MPlugin InternalListener.get().setup(); ScheduledTeleportEngine.get().setup(); TeleportMixinCauseEngine.get().setup(); - WorldNameSetEngine.get().setup(); + EngineWorldNameSet.get().setup(); + EngineOfflineCase.get().setup(); // Schedule the collection ticker. Bukkit.getScheduler().scheduleSyncRepeatingTask(this, this.collTickTask, 1, 1); diff --git a/src/com/massivecraft/mcore/util/MUtil.java b/src/com/massivecraft/mcore/util/MUtil.java index 12e9d6b4..752048e3 100644 --- a/src/com/massivecraft/mcore/util/MUtil.java +++ b/src/com/massivecraft/mcore/util/MUtil.java @@ -47,7 +47,7 @@ import org.bukkit.potion.PotionEffectType; import com.massivecraft.mcore.InternalListener; import com.massivecraft.mcore.MCore; -import com.massivecraft.mcore.WorldNameSetEngine; +import com.massivecraft.mcore.EngineWorldNameSet; import com.massivecraft.mcore.util.extractor.Extractor; import com.massivecraft.mcore.util.extractor.ExtractorMoneyUniverse; import com.massivecraft.mcore.util.extractor.ExtractorPlayer; @@ -394,7 +394,7 @@ public class MUtil public static Set getLoadedWorldNames() { - return WorldNameSetEngine.get().getWorldNames(); + return EngineWorldNameSet.get().getWorldNames(); } // -------------------------------------------- //