diff --git a/nge.cfg b/nge.cfg index a584b254..f68edd20 100644 --- a/nge.cfg +++ b/nge.cfg @@ -1,4 +1,4 @@ -#Thu May 21 23:36:44 CDT 2015 +#Fri May 22 01:51:04 CDT 2015 CLEAN-CHARACTER-DATA=0 LOAD-BUILDOUTS=false LOCAL-USER=nge @@ -7,12 +7,12 @@ AUTO-LOGIN=0 SESSION-TOKEN-LENGTH=24 LOGIN-PORT=44453 PACKET-DEBUG=false -LOCAL-DB=nge MAX-PACKET-SIZE=496 -DEBUG-SERVICES=true -LOCAL-PASS=nge -WIPE-ODB-FILES=0 +LOCAL-DB=nge LOGIN-SERVER-ID=1 -GALAXY-MAX-ONLINE=3000 +WIPE-ODB-FILES=0 +LOCAL-PASS=nge GALAXY-MAX-CHARACTERS=2 +GALAXY-MAX-ONLINE=3000 +ENABLE-LOGGING=true LOGIN-VERSION-CHECKS=true diff --git a/src/resources/control/Service.java b/src/resources/control/Service.java index 88285af4..3432b16a 100644 --- a/src/resources/control/Service.java +++ b/src/resources/control/Service.java @@ -27,9 +27,6 @@ ***********************************************************************************/ package resources.control; -import java.text.DateFormat; -import java.text.SimpleDateFormat; - import network.OutboundPacketService; import network.packets.Packet; import resources.config.ConfigFile; @@ -45,7 +42,6 @@ import resources.services.Config; public class Service implements IntentReceiver { private static final OutboundPacketService outboundPacketService = new OutboundPacketService(); - private static final DateFormat LOG_FORMAT = new SimpleDateFormat("dd-mm-yy HH:mm:ss.SSS"); /** * Initializes this service. If the service returns false on this method @@ -164,19 +160,4 @@ public class Service implements IntentReceiver { return DataManager.getInstance().getLocalDatabase(); } - /** - * Logs the string to the server log file, formatted to display the time, - * tag and message. - * @param tag the tag to use for the log - * @param str the format string for the log - * @param args the string format arguments, if specified - */ - public synchronized final void log(String tag, String str, Object ... args) { - if (getConfig(ConfigFile.PRIMARY).getBoolean("DEBUG-SERVICES", true)) { - String logStr = String.format(str, args); - String log = String.format("%s [%s]: %s", LOG_FORMAT.format(System.currentTimeMillis()), tag, logStr); - DataManager.getInstance().log(log); - } - } - } diff --git a/src/resources/server_info/DataManager.java b/src/resources/server_info/DataManager.java index 281b6230..08a1afc3 100644 --- a/src/resources/server_info/DataManager.java +++ b/src/resources/server_info/DataManager.java @@ -42,7 +42,6 @@ public class DataManager { private Map config; private RelationalDatabase localDatabase; - private Logger logger; private boolean initialized; private DataManager() { @@ -52,7 +51,8 @@ public class DataManager { private synchronized void initialize() { initializeConfig(); initializeDatabases(); - initializeLogger(); + if (getConfig(ConfigFile.PRIMARY).getBoolean("ENABLE-LOGGING", true)) + Log.start(); initialized = localDatabase.isOnline() && localDatabase.isTable("users"); } @@ -77,15 +77,6 @@ public class DataManager { initializeLocalDatabase(c); } - private synchronized void initializeLogger() { - logger = new Logger("log.txt"); - try { - logger.open(); - } catch (IOException e) { - e.printStackTrace(); - } - } - private synchronized void initializeLocalDatabase(Config c) { String db = c.getString("LOCAL-DB", "nge"); String user = c.getString("LOCAL-USER", "nge"); @@ -115,14 +106,6 @@ public class DataManager { return localDatabase; } - public synchronized final void log(String str) { - try { - logger.write(str); - } catch (IOException e) { - e.printStackTrace(); - } - } - public synchronized final boolean isInitialized() { return initialized; } diff --git a/src/resources/server_info/Log.java b/src/resources/server_info/Log.java new file mode 100644 index 00000000..95014c94 --- /dev/null +++ b/src/resources/server_info/Log.java @@ -0,0 +1,157 @@ +package resources.server_info; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +public class Log { + + private static final DateFormat LOG_FORMAT = new SimpleDateFormat("dd-mm-yy HH:mm:ss.SSS"); + private static final Log LOG = new Log("log.txt"); + + private final File file; + private BufferedWriter writer; + private boolean open; + + private Log(String filename) { + this.file = new File(filename); + open = false; + } + + private synchronized void open() throws IOException { + if (!open) + writer = new BufferedWriter(new FileWriter(file)); + open = true; + } + + private synchronized void close() throws IOException { + if (open) + writer.close(); + open = false; + } + + private synchronized void write(String str) throws IOException { + if (open) { + writer.write(str); + writer.newLine(); + writer.flush(); + } + } + + protected static final void start() { + try { + LOG.open(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + protected static final void stop() { + try { + LOG.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Logs the string to the server log file, formatted to display the log + * severity, time, tag and message. + * @param level the log level of this message between INFO and ASSERT + * @param tag the tag to use for the log + * @param str the format string for the log + * @param args the string format arguments, if specified + */ + public static final void log(LogLevel level, String tag, String str, Object ... args) { + String date = LOG_FORMAT.format(System.currentTimeMillis()); + String logStr = String.format(str, args); + String log = String.format("%s %c/[%s]: %s", date, level.getChar(), tag, logStr); + synchronized (LOG) { + try { + LOG.write(log); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Logs the string to the server log file, formatted to display the log + * severity as INFO, as well as the time, tag and message. + * @param level the log level of this message between INFO and ASSERT + * @param tag the tag to use for the log + * @param str the format string for the log + * @param args the string format arguments, if specified + */ + public static final void i(String tag, String message, Object ... args) { + log(LogLevel.INFO, tag, message, args); + } + + /** + * Logs the string to the server log file, formatted to display the log + * severity as DEBUG, as well as the time, tag and message. + * @param level the log level of this message between INFO and ASSERT + * @param tag the tag to use for the log + * @param str the format string for the log + * @param args the string format arguments, if specified + */ + public static final void d(String tag, String message, Object ... args) { + log(LogLevel.DEBUG, tag, message, args); + } + + /** + * Logs the string to the server log file, formatted to display the log + * severity as WARN, as well as the time, tag and message. + * @param level the log level of this message between INFO and ASSERT + * @param tag the tag to use for the log + * @param str the format string for the log + * @param args the string format arguments, if specified + */ + public static final void w(String tag, String message, Object ... args) { + log(LogLevel.WARN, tag, message, args); + } + + /** + * Logs the string to the server log file, formatted to display the log + * severity as ERROR, as well as the time, tag and message. + * @param level the log level of this message between INFO and ASSERT + * @param tag the tag to use for the log + * @param str the format string for the log + * @param args the string format arguments, if specified + */ + public static final void e(String tag, String message, Object ... args) { + log(LogLevel.ERROR, tag, message, args); + } + + /** + * Logs the string to the server log file, formatted to display the log + * severity as ASSERT, as well as the time, tag and message. + * @param level the log level of this message between INFO and ASSERT + * @param tag the tag to use for the log + * @param str the format string for the log + * @param args the string format arguments, if specified + */ + public static final void a(String tag, String message, Object ... args) { + log(LogLevel.ASSERT, tag, message, args); + } + + public static enum LogLevel { + INFO ('I'), + DEBUG ('D'), + WARN ('W'), + ERROR ('E'), + ASSERT ('A'); + + private char c; + + LogLevel(char c) { + this.c = c; + } + + public char getChar() { return c; } + } + +} diff --git a/src/resources/server_info/Logger.java b/src/resources/server_info/Logger.java deleted file mode 100644 index b550e105..00000000 --- a/src/resources/server_info/Logger.java +++ /dev/null @@ -1,31 +0,0 @@ -package resources.server_info; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -public class Logger { - - private final File file; - private BufferedWriter writer; - - public Logger(String filename) { - this.file = new File(filename); - } - - public synchronized void open() throws IOException { - writer = new BufferedWriter(new FileWriter(file)); - } - - public synchronized void close() throws IOException { - writer.close(); - } - - public synchronized void write(String str) throws IOException { - writer.write(str); - writer.newLine(); - writer.flush(); - } - -} diff --git a/src/services/galaxy/ConnectionService.java b/src/services/galaxy/ConnectionService.java index 355ad3a9..895e3201 100644 --- a/src/services/galaxy/ConnectionService.java +++ b/src/services/galaxy/ConnectionService.java @@ -49,6 +49,7 @@ import resources.player.Player; import resources.player.PlayerEvent; import resources.player.PlayerFlags; import resources.player.PlayerState; +import resources.server_info.Log; import utilities.ThreadUtilities; public class ConnectionService extends Service { @@ -188,6 +189,7 @@ public class ConnectionService extends Service { } private void logOut(Player p, boolean addToDisappear) { + Log.i("ConnectionService", "Logged out %s with character %s", p.getUsername(), p.getCharacterName()); updatePlayTime(p); if (p.getPlayerState() != PlayerState.LOGGED_OUT) System.out.println("[" + p.getUsername() +"] Logged out " + p.getCharacterName()); @@ -201,12 +203,14 @@ public class ConnectionService extends Service { } private void disappear(Player p) { + Log.i("ConnectionService", "Disappeared %s with character %s", p.getUsername(), p.getCharacterName()); p.setPlayerState(PlayerState.DISCONNECTED); System.out.println("[" + p.getUsername() +"] " + p.getCharacterName() + " disappeared"); new PlayerEventIntent(p, PlayerEvent.PE_DISAPPEAR).broadcast(); } private void disconnect(Player player, DisconnectReason reason) { + Log.i("ConnectionService", "Disconnected %s with character %s", player.getUsername(), player.getCharacterName()); new CloseConnectionIntent(player.getConnectionId(), player.getNetworkId(), reason).broadcast(); } diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index bc3cc63a..b760d46c 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -66,6 +66,7 @@ import resources.player.PlayerEvent; import resources.player.PlayerFlags; import resources.player.PlayerState; import resources.server_info.CachedObjectDatabase; +import resources.server_info.Log; import resources.server_info.ObjectDatabase; import resources.server_info.ObjectDatabase.Traverser; import resources.services.Config; @@ -98,7 +99,7 @@ public class ObjectManager extends Manager { private void loadObjects() { long startLoad = System.nanoTime(); - log("ObjectManager", "Loading objects from ObjectDatabase..."); + Log.i("ObjectManager", "Loading objects from ObjectDatabase..."); System.out.println("ObjectManager: Loading objects from ObjectDatabase..."); objects.load(); objects.traverse(new Traverser() { @@ -111,7 +112,7 @@ public class ObjectManager extends Manager { } }); double loadTime = (System.nanoTime() - startLoad) / 1E6; - log("ObjectManager", "Finished loading %d objects. Time: %fms", objects.size(), loadTime); + Log.i("ObjectManager", "Finished loading %d objects. Time: %fms", objects.size(), loadTime); System.out.printf("ObjectManager: Finished loading %d objects. Time: %fms%n", objects.size(), loadTime); } @@ -135,7 +136,7 @@ public class ObjectManager extends Manager { double loadTime = (System.nanoTime() - startLoad) / 1E6; System.out.printf("ObjectManager: Finished loading buildouts. Time: %fms%n", loadTime); } else { - log("ObjectManager", "Did not load buildouts. Reason: Disabled."); + Log.w("ObjectManager", "Did not load buildouts. Reason: Disabled."); System.out.println("ObjectManager: Buildouts not loaded. Reason: Disabled!"); } } @@ -233,6 +234,7 @@ public class ObjectManager extends Manager { for (SWGObject slot : obj.getSlots().values()) if (slot != null) deleteObject(slot.getObjectId()); + Log.i("ObjectManager", "Deleted object %d [%s]", obj.getObjectId(), obj.getTemplate()); return obj; } } @@ -286,6 +288,7 @@ public class ObjectManager extends Manager { obj.setLocation(l); objectAwareness.add(obj); objects.put(objectId, obj); + Log.i("ObjectManager", "Created object %d [%s]", obj.getObjectId(), obj.getTemplate()); return obj; } } @@ -335,6 +338,7 @@ public class ObjectManager extends Manager { creature.clearAware(); objectAwareness.update(creature); System.out.println("[" + player.getUsername() + "] " + player.getCharacterName() + " is zoning in"); + Log.i("ObjectManager", "Zoning in %s with character %s", player.getUsername(), player.getCharacterName()); new PlayerEventIntent(player, galaxy, PlayerEvent.PE_ZONE_IN).broadcast(); } @@ -344,6 +348,7 @@ public class ObjectManager extends Manager { SWGObject creature = objects.get(characterId); if (creature == null) { System.err.println("ObjectManager: Failed to start zone - CreatureObject could not be fetched from database [Character: " + characterId + " User: " + player.getUsername() + "]"); + return; } if (!(creature instanceof CreatureObject)) { diff --git a/src/services/player/LoginService.java b/src/services/player/LoginService.java index 9c69cb6b..ad6b8950 100644 --- a/src/services/player/LoginService.java +++ b/src/services/player/LoginService.java @@ -68,6 +68,7 @@ import resources.objects.creature.CreatureObject; import resources.player.AccessLevel; import resources.player.Player; import resources.player.PlayerState; +import resources.server_info.Log; import resources.server_info.RelationalDatabase; import resources.services.Config; @@ -128,8 +129,10 @@ public class LoginService extends Service { private void handleCharDeletion(GalacticIntent intent, Player player, DeleteCharacterRequest request) { SWGObject obj = intent.getObjectManager().destroyObject(request.getPlayerId()); - if (obj != null && obj instanceof CreatureObject) + if (obj != null && obj instanceof CreatureObject) { + Log.i("LoginService", "Deleted character %s for user %s", ((CreatureObject)obj).getName(), player.getUsername()); System.out.println("[" + player.getUsername() + "] Delete Character: " + ((CreatureObject)obj).getName() + ". IP: " + request.getAddress() + ":" + request.getPort()); + } sendPacket(player, new DeleteCharacterResponse(deleteCharacter(request.getPlayerId()))); } @@ -140,9 +143,9 @@ public class LoginService extends Service { } final boolean doClientCheck = getConfig(ConfigFile.PRIMARY).getBoolean("LOGIN-VERSION-CHECKS", true); if (doClientCheck) - System.out.println("LoginService: Running login checks for '" + id.getUsername() + "'"); + Log.d("LoginService", "Running login checks for %s", id.getUsername()); else - System.out.println("LoginService: Skipping login checks for '" + id.getUsername() + "'"); + Log.d("LoginService", "Skipping login checks for %s", id.getUsername()); if (!id.getVersion().equals(REQUIRED_VERSION) && doClientCheck) { onLoginClientVersionError(player, id); return; @@ -165,12 +168,13 @@ public class LoginService extends Service { onInvalidUserPass(player, id); } catch (SQLException e) { e.printStackTrace(); - onLoginServerError(player); + onLoginServerError(player, id); } } private void onLoginClientVersionError(Player player, LoginClientId id) { System.err.println("LoginService: " + id.getUsername() + " cannot login due to invalid version code: " + id.getVersion()); + Log.i("LoginService", "%s cannot login due to invalid version code: %s, expected %s from %s:%d", player.getUsername(), id.getVersion(), REQUIRED_VERSION, id.getAddress(), id.getPort()); String type = "Login Failed!"; String message = "Invalid Client Version Code: " + id.getVersion(); sendPacket(player.getNetworkId(), new ErrorMessage(type, message, false)); @@ -195,6 +199,7 @@ public class LoginService extends Service { } sendLoginSuccessPacket(player); System.out.println("[" + player.getUsername() + "] Connected to the login server. IP: " + id.getAddress() + ":" + id.getPort()); + Log.i("LoginService", "%s connected to the login server from %s:%d", player.getUsername(), id.getAddress(), id.getPort()); new LoginEventIntent(player.getNetworkId(), LoginEvent.LOGIN_SUCCESS).broadcast(); } @@ -203,6 +208,7 @@ public class LoginService extends Service { String message = "Sorry, you're banned!"; sendPacket(player.getNetworkId(), new ErrorMessage(type, message, false)); System.err.println("[" + id.getUsername() + "] Can't login - Banned! IP: " + id.getAddress() + ":" + id.getPort()); + Log.i("LoginService", "%s cannot login due to a ban, from %s:%d", id.getAddress(), id.getPort()); player.setPlayerState(PlayerState.DISCONNECTED); new LoginEventIntent(player.getNetworkId(), LoginEvent.LOGIN_FAIL_BANNED).broadcast(); } @@ -221,15 +227,17 @@ public class LoginService extends Service { sendPacket(player, new LoginIncorrectClientId(getServerString(), "3.14159265")); sendPacket(player, new ErrorMessage(type, message, false)); System.err.println("[" + id.getUsername() + "] Invalid user/pass combo! IP: " + id.getAddress() + ":" + id.getPort()); + Log.i("LoginService", "%s cannot login due to invalid user/pass from %s:%d", id.getUsername(), id.getAddress(), id.getPort()); player.setPlayerState(PlayerState.DISCONNECTED); new LoginEventIntent(player.getNetworkId(), LoginEvent.LOGIN_FAIL_INVALID_USER_PASS).broadcast(); } - private void onLoginServerError(Player player) { + private void onLoginServerError(Player player, LoginClientId id) { String type = "Login Failed!"; String message = "Server Error."; sendPacket(player.getNetworkId(), new ErrorMessage(type, message, false)); player.setPlayerState(PlayerState.DISCONNECTED); + Log.e("LoginService", "%s cannot login due to server error, from %s:%d", id.getUsername(), id.getAddress(), id.getPort()); new LoginEventIntent(player.getNetworkId(), LoginEvent.LOGIN_FAIL_SERVER_ERROR).broadcast(); } diff --git a/src/services/player/PlayerManager.java b/src/services/player/PlayerManager.java index 55a73f57..503bd253 100644 --- a/src/services/player/PlayerManager.java +++ b/src/services/player/PlayerManager.java @@ -50,6 +50,7 @@ import resources.network.ServerType; import resources.player.Player; import resources.player.PlayerEvent; import resources.player.PlayerState; +import resources.server_info.Log; public class PlayerManager extends Manager { @@ -190,6 +191,7 @@ public class PlayerManager extends Manager { p.setNetworkId(networkId); p.setGalaxyId(galaxyId); players.put(networkId, p); + Log.i("PlayerManager", "Transitioned %s from login to zone", p.getUsername()); return p; } } diff --git a/src/services/player/ZoneService.java b/src/services/player/ZoneService.java index 94f767eb..775e890c 100644 --- a/src/services/player/ZoneService.java +++ b/src/services/player/ZoneService.java @@ -84,6 +84,7 @@ import resources.player.AccessLevel; import resources.player.Player; import resources.player.PlayerEvent; import resources.player.PlayerState; +import resources.server_info.Log; import resources.services.Config; import resources.zone.NameFilter; import services.objects.ObjectManager; @@ -193,10 +194,12 @@ public class ZoneService extends Service { player.setPlayerState(PlayerState.ZONED_IN); player.sendPacket(p); System.out.println("[" + player.getUsername() +"] " + player.getCharacterName() + " zoned in"); + Log.i("ZoneService", "%s with character %s zoned in from %s:%d", player.getUsername(), player.getCharacterName(), p.getAddress(), p.getPort()); } private void handleClientIdMsg(Player player, ClientIdMsg clientId) { System.out.println("[" + player.getUsername() + "] Connected to the zone server. IP: " + clientId.getAddress() + ":" + clientId.getPort()); + Log.i("ZoneService", "%s connected to the zone server from %s:%d", player.getUsername(), clientId.getAddress(), clientId.getPort()); sendPacket(player.getNetworkId(), new HeartBeatMessage()); sendPacket(player.getNetworkId(), new AccountFeatureBits()); sendPacket(player.getNetworkId(), new ClientPermissionsMessage()); @@ -223,29 +226,38 @@ public class ZoneService extends Service { } private void handleCharCreation(ObjectManager objManager, Player player, ClientCreateCharacter create) { - System.out.println("[" + player.getUsername() + "] Create Character: " + create.getName() + ". IP: " + create.getAddress() + ":" + create.getPort()); - long characterId = createCharacter(objManager, player, create); - ErrorMessage err = getNameValidity(create.getName(), player.getAccessLevel() != AccessLevel.PLAYER); - if (err == ErrorMessage.NAME_APPROVED && createCharacterInDb(characterId, create.getName(), player)) { - sendPacket(player, new CreateCharacterSuccess(characterId)); - new PlayerEventIntent(player, PlayerEvent.PE_CREATE_CHARACTER).broadcast(); - } else { - NameFailureReason reason = NameFailureReason.NAME_SYNTAX; - if (err == ErrorMessage.NAME_APPROVED) { // Then it must have been a database error - err = ErrorMessage.NAME_DECLINED_INTERNAL_ERROR; - reason = NameFailureReason.NAME_RETRY; - } else if (err == ErrorMessage.NAME_DECLINED_IN_USE) - reason = NameFailureReason.NAME_IN_USE; - else if (err == ErrorMessage.NAME_DECLINED_EMPTY) - reason = NameFailureReason.NAME_DECLINED_EMPTY; - else if (err == ErrorMessage.NAME_DECLINED_FICTIONALLY_INAPPROPRIATE) - reason = NameFailureReason.NAME_FICTIONALLY_INAPPRORIATE; - else if (err == ErrorMessage.NAME_DECLINED_RESERVED) - reason = NameFailureReason.NAME_DEV_RESERVED; - System.err.println("ZoneService: Unable to create character [Name: " + create.getName() + " User: " + player.getUsername() + "] and put into database! Reason: " + err); - sendPacket(player, new CreateCharacterFailure(reason)); + if (err == ErrorMessage.NAME_APPROVED) { + long characterId = createCharacter(objManager, player, create); + if (createCharacterInDb(characterId, create.getName(), player)) { + System.out.println("[" + player.getUsername() + "] Create Character: " + create.getName() + ". IP: " + create.getAddress() + ":" + create.getPort()); + Log.i("ZoneService", "%s created character %s from %s:%d", player.getUsername(), create.getName(), create.getAddress(), create.getPort()); + sendPacket(player, new CreateCharacterSuccess(characterId)); + new PlayerEventIntent(player, PlayerEvent.PE_CREATE_CHARACTER).broadcast(); + return; + } + Log.e("ZoneService", "Failed to create character %s for user %s with server error from %s:%d", create.getName(), player.getUsername(), create.getAddress(), create.getPort()); + objManager.deleteObject(characterId); } + sendCharCreationFailure(player, create, err); + } + + private void sendCharCreationFailure(Player player, ClientCreateCharacter create, ErrorMessage err) { + NameFailureReason reason = NameFailureReason.NAME_SYNTAX; + if (err == ErrorMessage.NAME_APPROVED) { // Then it must have been a database error + err = ErrorMessage.NAME_DECLINED_INTERNAL_ERROR; + reason = NameFailureReason.NAME_RETRY; + } else if (err == ErrorMessage.NAME_DECLINED_IN_USE) + reason = NameFailureReason.NAME_IN_USE; + else if (err == ErrorMessage.NAME_DECLINED_EMPTY) + reason = NameFailureReason.NAME_DECLINED_EMPTY; + else if (err == ErrorMessage.NAME_DECLINED_FICTIONALLY_INAPPROPRIATE) + reason = NameFailureReason.NAME_FICTIONALLY_INAPPRORIATE; + else if (err == ErrorMessage.NAME_DECLINED_RESERVED) + reason = NameFailureReason.NAME_DEV_RESERVED; + System.err.println("ZoneService: Unable to create character [Name: " + create.getName() + " User: " + player.getUsername() + "] and put into database! Reason: " + err); + Log.e("ZoneService", "Failed to create character %s for user %s with error %s and reason %s from %s:%d", create.getName(), player.getUsername(), err, reason, create.getAddress(), create.getPort()); + sendPacket(player, new CreateCharacterFailure(reason)); } private boolean createCharacterInDb(long characterId, String name, Player player) { @@ -423,6 +435,7 @@ public class ZoneService extends Service { synchronized (lockedNames) { unlockName(player); lockedNames.put(firstName, player); + Log.i("ZoneService", "Locked name %s for user %s", firstName, player.getUsername()); } return true; } @@ -437,8 +450,10 @@ public class ZoneService extends Service { break; } } - if (fName != null) - lockedNames.remove(fName); + if (fName != null) { + if (lockedNames.remove(fName) != null) + Log.i("ZoneService", "Unlocked name %s for user %s", fName, player.getUsername()); + } } }