diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgObjectDatabase.java b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgObjectDatabase.java index d8cdf666..fa536a48 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgObjectDatabase.java +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgObjectDatabase.java @@ -38,6 +38,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class PswgObjectDatabase implements PswgDatabase { @@ -74,8 +75,23 @@ public class PswgObjectDatabase implements PswgDatabase { new BulkWriteOptions().ordered(false)); } - public void removeObject(long id) { - collection.deleteOne(Filters.eq("id", id)); + public boolean removeObject(long id) { + return collection.deleteOne(Filters.eq("id", id)).getDeletedCount() > 0; + } + + public int getCharacterCount(String account) { + return (int) collection.countDocuments(Filters.eq("account", account)); + } + + public boolean isCharacter(String firstName) { + return collection.countDocuments(Filters.and( + Filters.regex("template", "object/creature/player/shared_.+\\.iff"), + Filters.regex("base3.objectName", Pattern.compile(Pattern.quote(firstName) + "( .+|$)", Pattern.CASE_INSENSITIVE)) + )) > 0; + } + + public long clearObjects() { + return collection.deleteMany(Filters.exists("_id")).getDeletedCount(); } @NotNull diff --git a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgUserDatabase.java b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgUserDatabase.java index 933de7b5..5d1a72ae 100644 --- a/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgUserDatabase.java +++ b/src/main/java/com/projectswg/holocore/resources/support/data/server_info/mongodb/PswgUserDatabase.java @@ -28,13 +28,13 @@ package com.projectswg.holocore.resources.support.data.server_info.mongodb; import com.mongodb.client.MongoCollection; -import com.mongodb.client.model.*; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.IndexOptions; +import com.mongodb.client.model.Indexes; import org.bson.Document; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; - public class PswgUserDatabase implements PswgDatabase { private MongoCollection collection; @@ -47,7 +47,6 @@ public class PswgUserDatabase implements PswgDatabase { public void open(MongoCollection collection) { this.collection = collection; collection.createIndex(Indexes.ascending("username"), new IndexOptions().unique(true)); - collection.createIndex(Indexes.ascending("characters.firstName"), new IndexOptions().unique(true).partialFilterExpression(Filters.type("characters.firstName", "string"))); } @Nullable @@ -55,36 +54,6 @@ public class PswgUserDatabase implements PswgDatabase { return collection.find(Filters.eq("username", username)).map(UserMetadata::new).first(); } - @Nullable - public CharacterMetadata getCharacter(long id) { - return collection.find(Filters.eq("characters.id", id)).map(CharacterMetadata::new).first(); - } - - public boolean isCharacter(@NotNull String firstName) { - return collection.countDocuments(Filters.eq("characters.firstName", firstName.toLowerCase(Locale.US)), new CountOptions().limit(1)) > 0; - } - - @NotNull - public List getCharacters(@NotNull String username) { - return collection.aggregate(Arrays.asList(Aggregates.match(Filters.eq("username", username)), Aggregates.unwind("$characters"))).map(CharacterMetadata::new).into(new ArrayList<>()); - } - - public boolean deleteCharacters() { - return collection.updateMany(Filters.exists("characters"), Updates.unset("characters")).getModifiedCount() > 0; - } - - public boolean deleteCharacter(String username, long id) { - return collection.updateOne(Filters.and(Filters.eq("username", username), Filters.eq("characters.id", id)), Updates.pull("characters", Filters.eq("id", id))).getModifiedCount() > 0; - } - - public boolean deleteCharacter(long id) { - return collection.updateOne(Filters.eq("characters.id", id), Updates.pull("characters", Filters.eq("id", id))).getModifiedCount() > 0; - } - - public boolean insertCharacter(@NotNull String username, @NotNull CharacterMetadata character) { - return collection.updateOne(Filters.eq("username", username), Updates.addToSet("characters", character.toDocument())).getModifiedCount() > 0; - } - public static class UserMetadata { private final String accountId; @@ -123,61 +92,4 @@ public class PswgUserDatabase implements PswgDatabase { } - public static class CharacterMetadata { - - private final long id; - private final String firstName; - private final String name; - private final String race; - private final Document detailedData; - - public CharacterMetadata(Document doc) { - doc = doc.get("characters", Document.class); - this.id = doc.getLong("id"); - this.firstName = doc.getString("firstName"); - this.name = doc.getString("name"); - this.race = doc.getString("race"); - this.detailedData = doc.get("detail", Document.class); - } - - public CharacterMetadata(long id, String firstName, String name, String race, Document detailedData) { - this.id = id; - this.firstName = firstName; - this.name = name; - this.race = race; - this.detailedData = detailedData; - } - - public Document toDocument() { - Document doc = new Document(); - doc.put("id", id); - doc.put("firstName", firstName); - doc.put("name", name); - doc.put("race", race); - doc.put("detailedData", detailedData); - return doc; - } - - public long getId() { - return id; - } - - public String getFirstName() { - return firstName; - } - - public String getName() { - return name; - } - - public String getRace() { - return race; - } - - public Map getDetailedData() { - return Collections.unmodifiableMap(detailedData); - } - - } - } diff --git a/src/main/java/com/projectswg/holocore/services/support/data/ServerDataService.java b/src/main/java/com/projectswg/holocore/services/support/data/ServerDataService.java index 3013e8f6..1f1987ae 100644 --- a/src/main/java/com/projectswg/holocore/services/support/data/ServerDataService.java +++ b/src/main/java/com/projectswg/holocore/services/support/data/ServerDataService.java @@ -2,6 +2,7 @@ package com.projectswg.holocore.services.support.data; import com.projectswg.holocore.resources.support.data.server_info.mongodb.PswgDatabase; import me.joshlarson.jlcommon.control.Service; +import me.joshlarson.jlcommon.log.Log; public class ServerDataService extends Service { @@ -11,14 +12,11 @@ public class ServerDataService extends Service { @Override public boolean initialize() { - if (PswgDatabase.config().getBoolean(this, "cleanCharacterData", false)) - wipeCharacterDatabase(); + if (PswgDatabase.config().getBoolean(this, "wipeObjects", false)) { + Log.d("Cleared %d objects", PswgDatabase.objects().clearObjects()); + } return super.initialize(); } - private void wipeCharacterDatabase() { - PswgDatabase.users().deleteCharacters(); - } - } diff --git a/src/main/java/com/projectswg/holocore/services/support/global/zone/LoginService.java b/src/main/java/com/projectswg/holocore/services/support/global/zone/LoginService.java index 5180ed49..a984fe7f 100644 --- a/src/main/java/com/projectswg/holocore/services/support/global/zone/LoginService.java +++ b/src/main/java/com/projectswg/holocore/services/support/global/zone/LoginService.java @@ -94,7 +94,7 @@ public class LoginService extends Service { @IntentHandler private void handleDeleteCharacterIntent(DeleteCharacterIntent dci) { SWGObject obj = dci.getCreature(); - if (PswgDatabase.users().deleteCharacter(obj.getObjectId())) { + if (PswgDatabase.objects().removeObject(obj.getObjectId())) { DestroyObjectIntent.broadcast(obj); Player owner = obj.getOwner(); if (owner != null) @@ -161,7 +161,13 @@ public class LoginService extends Service { private void handleCharDeletion(Player player, DeleteCharacterRequest request) { SWGObject obj = ObjectLookup.getObjectById(request.getPlayerId()); - boolean success = obj instanceof CreatureObject && PswgDatabase.users().deleteCharacter(player.getUsername(), obj.getObjectId()); + boolean success; + if (obj instanceof CreatureObject) { + success = PswgDatabase.objects().removeObject(obj.getObjectId()); + players.getOrDefault(player.getAccountId(), new ArrayList<>()).remove(obj); + } else { + success = false; + } player.sendPacket(new DeleteCharacterResponse(success)); if (success) { DestroyObjectIntent.broadcast(obj); @@ -224,12 +230,12 @@ public class LoginService extends Service { private void onSuccessfulLogin(UserMetadata user, Player player) { switch(user.getAccessLevel()) { + default: case "player": player.setAccessLevel(AccessLevel.PLAYER); break; case "warden": player.setAccessLevel(AccessLevel.WARDEN); break; case "csr": player.setAccessLevel(AccessLevel.CSR); break; case "qa": player.setAccessLevel(AccessLevel.QA); break; case "dev": player.setAccessLevel(AccessLevel.DEV); break; - default: player.setAccessLevel(AccessLevel.PLAYER); break; } player.setAccountId(user.getUsername()); player.setPlayerState(PlayerState.LOGGED_IN); diff --git a/src/main/java/com/projectswg/holocore/services/support/global/zone/creation/CharacterCreationService.java b/src/main/java/com/projectswg/holocore/services/support/global/zone/creation/CharacterCreationService.java index a6da0d84..55fa44e1 100644 --- a/src/main/java/com/projectswg/holocore/services/support/global/zone/creation/CharacterCreationService.java +++ b/src/main/java/com/projectswg/holocore/services/support/global/zone/creation/CharacterCreationService.java @@ -94,7 +94,7 @@ public class CharacterCreationService extends Service { int spaceIndex = name.indexOf(' '); if (spaceIndex != -1) name = name.substring(0, spaceIndex); - return PswgDatabase.users().isCharacter(name); + return PswgDatabase.objects().isCharacter(name); } private void handleRandomNameRequest(Player player, RandomNameRequest request) { @@ -111,7 +111,7 @@ public class CharacterCreationService extends Service { String name = request.getName(); ErrorMessage err = getNameValidity(name, player.getAccessLevel() != AccessLevel.PLAYER); int max = PswgDatabase.config().getInt(this, "galaxyMaxCharacters", 0); - if (max != 0 && getCharacterCount(player.getUsername()) >= max) + if (max != 0 && getCharacterCount(player.getAccountId()) >= max) err = ErrorMessage.SERVER_CHARACTER_CREATION_MAX_CHARS; if (err == ErrorMessage.NAME_APPROVED_MODIFIED) name = nameFilter.cleanName(name); @@ -144,7 +144,7 @@ public class CharacterCreationService extends Service { } // Too many characters int max = PswgDatabase.config().getInt(this, "galaxyMaxCharacters", 0); - if (max != 0 && getCharacterCount(player.getUsername()) >= max) { + if (max != 0 && getCharacterCount(player.getAccountId()) >= max) { sendCharCreationFailure(player, create, ErrorMessage.SERVER_CHARACTER_CREATION_MAX_CHARS, "too many characters"); return null; } @@ -171,6 +171,7 @@ public class CharacterCreationService extends Service { private void sendCharCreationFailure(Player player, ClientCreateCharacter create, ErrorMessage err, String actualReason) { NameFailureReason reason = NameFailureReason.NAME_SYNTAX; switch (err) { + case NAME_DECLINED_INTERNAL_ERROR: case NAME_APPROVED: reason = NameFailureReason.NAME_RETRY; break; @@ -182,7 +183,6 @@ public class CharacterCreationService extends Service { case NAME_DECLINED_RESERVED: reason = NameFailureReason.NAME_DEV_RESERVED; break; case NAME_DECLINED_TOO_FAST: reason = NameFailureReason.NAME_TOO_FAST; break; case SERVER_CHARACTER_CREATION_MAX_CHARS: reason = NameFailureReason.TOO_MANY_CHARACTERS; break; - case NAME_DECLINED_INTERNAL_ERROR: reason = NameFailureReason.NAME_RETRY; default: break; } @@ -191,7 +191,7 @@ public class CharacterCreationService extends Service { } private int getCharacterCount(String username) { - return PswgDatabase.users().getCharacters(username).size(); + return PswgDatabase.objects().getCharacterCount(username); } private ErrorMessage getNameValidity(String name, boolean admin) {