Make the forceOnePlayerNameCase much quicker and isolate it in an Engine class.

This commit is contained in:
Olof Larsson 2013-08-25 12:28:20 +02:00
parent 7f7f5db99d
commit 1b8ae6cf5f
5 changed files with 138 additions and 46 deletions

View File

@ -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<String, String> lowerToCorrect = new HashMap<String, String>();
// -------------------------------------------- //
// 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("<b>The player <h>%s <b>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("<b>Invalid uppercase and lowercase letters in name.\n<i>Please spell this name like \"<h>%s<i>\".", correct));
return;
}
}
}
}

View File

@ -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

View File

@ -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("<b>The player <h>%s <b>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("<b>Invalid uppercase and lowercase letters in name.\n<i>Please spell this name like \"<h>%s<i>\".", pdname));
}
}
// -------------------------------------------- //
// PLAYER CONNECTION WRAP INJECTION
// -------------------------------------------- //

View File

@ -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);

View File

@ -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<String> getLoadedWorldNames()
{
return WorldNameSetEngine.get().getWorldNames();
return EngineWorldNameSet.get().getWorldNames();
}
// -------------------------------------------- //