.
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.util.transformer.impl;
+
+import java.lang.reflect.Array;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.l2jserver.util.transformer.Transformer;
+import com.l2jserver.util.transformer.TransformerFactory;
+
+/**
+ * Transform an {@link Array} into an string.
+ *
+ * Important note: Array elements are by an |.
+ *
+ * @author Rogiel
+ * @param
+ * the array component type that this tranformer transforms
+ */
+public class ArrayTransformer implements Transformer {
+ /**
+ * This transformer shared instance
+ */
+ @SuppressWarnings("rawtypes")
+ public static final ArrayTransformer> SHARED_INSTANCE = new ArrayTransformer();
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public String transform(Class extends T[]> type, T[] value) {
+ final Transformer transformer = (Transformer) TransformerFactory
+ .getTransfromer(type.getComponentType());
+ final String[] values = new String[value.length];
+ int i = 0;
+ for (final T item : value) {
+ values[i++] = transformer.transform(
+ (Class extends T>) type.getComponentType(), item);
+ }
+ return StringUtils.join(values, '|');
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T[] untransform(Class extends T[]> type, String stringValue) {
+ final Transformer transformer = (Transformer) TransformerFactory
+ .getTransfromer(type.getComponentType());
+ final String[] stringValues = StringUtils.split(stringValue, '|');
+ final T[] values = (T[]) Array.newInstance(type.getComponentType(),
+ stringValues.length);
+ int i = 0;
+ for (final String value : stringValues) {
+ values[i++] = transformer.untransform(
+ (Class extends T>) type.getComponentType(), value);
+ }
+
+ return values;
+ }
+}
diff --git a/l2jserver2-common/src/main/java/com/l2jserver/util/transformer/impl/StringTransformer.java b/l2jserver2-common/src/main/java/com/l2jserver/util/transformer/impl/StringTransformer.java
new file mode 100644
index 000000000..f411dbef6
--- /dev/null
+++ b/l2jserver2-common/src/main/java/com/l2jserver/util/transformer/impl/StringTransformer.java
@@ -0,0 +1,42 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.util.transformer.impl;
+
+import com.l2jserver.util.transformer.Transformer;
+
+/**
+ * This tranformer does nothing!
+ *
+ * @author Rogiel
+ */
+public class StringTransformer implements Transformer {
+ /**
+ * This transformer shared instance
+ */
+ public static final StringTransformer SHARED_INSTANCE = new StringTransformer();
+
+ @Override
+ public String transform(Class extends String> type, String value) {
+ return value;
+ }
+
+ @Override
+ public String untransform(Class extends String> type, String value) {
+ return value;
+ }
+
+}
diff --git a/l2jserver2-common/src/test/java/com/l2jserver/util/transformer/impl/ArrayTransformerTest.java b/l2jserver2-common/src/test/java/com/l2jserver/util/transformer/impl/ArrayTransformerTest.java
new file mode 100644
index 000000000..bfd02031a
--- /dev/null
+++ b/l2jserver2-common/src/test/java/com/l2jserver/util/transformer/impl/ArrayTransformerTest.java
@@ -0,0 +1,94 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.util.transformer.impl;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Rogiel
+ *
+ */
+public class ArrayTransformerTest {
+ /**
+ * An Integer[] array as an string
+ */
+ private static final String INT_ARRAY_STRING = "1|2|3";
+ /**
+ * An Integer[] array
+ */
+ private static final Integer[] INT_ARRAY = new Integer[] { 1, 2, 3 };
+
+ /**
+ * An String[] array as an string
+ */
+ private static final String STRING_ARRAY_STRING = "test1|test2|test3";
+ /**
+ * An String[] array
+ */
+ private static final String[] STRING_ARRAY = new String[] { "test1",
+ "test2", "test3" };
+
+ /**
+ * An Class[] array as an string
+ */
+ private static final String CLASS_ARRAY_STRING = "java.lang.Object|java.lang.Integer|java.lang.Long";
+ /**
+ * An Class[] array
+ */
+ private static final Class>[] CLASS_ARRAY = new Class>[] {
+ Object.class, Integer.class, Long.class };
+
+ /**
+ * Tests transforming an {@link Integer} array
+ */
+ @Test
+ public void testIntegerTransforming() {
+ final ArrayTransformer transformer = new ArrayTransformer();
+ Assert.assertEquals(INT_ARRAY_STRING,
+ transformer.transform(Integer[].class, INT_ARRAY));
+ Assert.assertArrayEquals(INT_ARRAY,
+ transformer.untransform(Integer[].class, INT_ARRAY_STRING));
+ }
+
+ /**
+ * Tests transforming an {@link String} array
+ */
+ @Test
+ public void testStringTransforming() {
+ final ArrayTransformer transformer = new ArrayTransformer();
+ Assert.assertEquals(STRING_ARRAY_STRING,
+ transformer.transform(String[].class, STRING_ARRAY));
+ Assert.assertArrayEquals(STRING_ARRAY,
+ transformer.untransform(String[].class, STRING_ARRAY_STRING));
+ }
+
+ /**
+ * Tests transforming an {@link Class} array
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testClassTransforming() {
+ final ArrayTransformer> transformer = new ArrayTransformer>();
+ Assert.assertEquals(CLASS_ARRAY_STRING, transformer.transform(
+ (Class extends Class>[]>) Class[].class, CLASS_ARRAY));
+ Assert.assertArrayEquals(CLASS_ARRAY, transformer
+ .untransform((Class extends Class>[]>) Class[].class,
+ CLASS_ARRAY_STRING));
+ }
+
+}
diff --git a/l2jserver2-gameserver/distribution/services.xml b/l2jserver2-gameserver/distribution/services.xml
index a959bff0a..bc16dd81d 100644
--- a/l2jserver2-gameserver/distribution/services.xml
+++ b/l2jserver2-gameserver/distribution/services.xml
@@ -47,7 +47,7 @@
you normally don't need to change anything here nor in the firewall. -->
-
+
@@ -88,7 +88,14 @@
+ implementation="com.l2jserver.service.game.character.CharacterServiceImpl">
+
+
+
+
+
+
-
+
diff --git a/l2jserver2-gameserver/services-sample.xml b/l2jserver2-gameserver/services-sample.xml
index 1a271c8d8..14f95c415 100644
--- a/l2jserver2-gameserver/services-sample.xml
+++ b/l2jserver2-gameserver/services-sample.xml
@@ -109,7 +109,14 @@
+ implementation="com.l2jserver.service.game.character.CharacterServiceImpl">
+
+
+
+
+
+
.
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.service.game.character;
+
+/**
+ * Exception thrown when the character creation is disabled or not authrorized
+ * for the account.
+ *
+ * @author Rogiel
+ */
+public class CharacteCreationNotAllowedException extends
+ CharacterServiceException {
+ /**
+ * The Java Serialization API serial
+ */
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterInvalidRaceException.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterInvalidRaceException.java
new file mode 100644
index 000000000..ca8ccda6b
--- /dev/null
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterInvalidRaceException.java
@@ -0,0 +1,30 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.service.game.character;
+
+/**
+ * Exception thrown when the character creation does not allows the requested
+ * race
+ *
+ * @author Rogiel
+ */
+public class CharacterInvalidRaceException extends CharacterServiceException {
+ /**
+ * The Java Serialization API serial
+ */
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterInvalidSexException.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterInvalidSexException.java
new file mode 100644
index 000000000..09aff01ef
--- /dev/null
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterInvalidSexException.java
@@ -0,0 +1,30 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.service.game.character;
+
+/**
+ * Exception thrown when the character creation does not allows the requested
+ * sex
+ *
+ * @author Rogiel
+ */
+public class CharacterInvalidSexException extends CharacterServiceException {
+ /**
+ * The Java Serialization API serial
+ */
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterService.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterService.java
index 07a3fc355..5fb723164 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterService.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterService.java
@@ -46,6 +46,16 @@ import com.l2jserver.util.geometry.Point3D;
* @author Rogiel
*/
public interface CharacterService extends Service {
+ /**
+ * Checks whether the service and the given account can create new
+ * characters on this server.
+ *
+ * @param accountID
+ * the account ID
+ * @return true if new characters are permitted
+ */
+ boolean canCreate(AccountID accountID);
+
/**
*
* @param name
@@ -70,13 +80,27 @@ public interface CharacterService extends Service {
* if the appearance sent by the client is not valid
* @throws CharacterNameAlreadyExistsException
* the character name is already being used
+ * @throws CharacteCreationNotAllowedException
+ * if the character creation is disabled or not allowed for the
+ * account
+ * @throws CharacterInvalidRaceException
+ * if the service does not allow the creation of characters in
+ * the requested race
+ * @throws CharacterInvalidSexException
+ * if the service does not allow the creation of characters in
+ * the requested sex
+ * @throws TooManyCharactersException
+ * if the character limit has been exceeded and no more
+ * characters can be created on this account
*/
L2Character create(String name, AccountID accountID, ActorSex sex,
CharacterClass characterClass, CharacterHairStyle hairStyle,
CharacterHairColor hairColor, CharacterFace face)
throws CharacterInvalidNameException,
CharacterInvalidAppearanceException,
- CharacterNameAlreadyExistsException;
+ CharacterNameAlreadyExistsException,
+ CharacteCreationNotAllowedException, CharacterInvalidRaceException,
+ CharacterInvalidSexException, TooManyCharactersException;
/**
* Perform all operations required to this character join the world
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceConfiguration.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceConfiguration.java
new file mode 100644
index 000000000..575b6dbfe
--- /dev/null
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceConfiguration.java
@@ -0,0 +1,90 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.service.game.character;
+
+import com.l2jserver.model.template.actor.ActorSex;
+import com.l2jserver.model.template.character.CharacterRace;
+import com.l2jserver.service.ServiceConfiguration;
+import com.l2jserver.service.configuration.XMLConfigurationService.ConfigurationXPath;
+
+/**
+ * Configuration interface for {@link CharacterService}
+ *
+ * @author Rogiel
+ */
+public interface CharacterServiceConfiguration extends ServiceConfiguration {
+ /**
+ * @return whether the creation of new characters is available
+ */
+ @ConfigurationPropertyGetter(defaultValue = "true")
+ @ConfigurationXPath("creation/@allow")
+ boolean isCharacterCreationAllowed();
+
+ /**
+ * @param state
+ * whether the creation of new characters is available
+ *
+ */
+ @ConfigurationPropertySetter
+ @ConfigurationXPath("creation/@allow")
+ void setCharacterCreationAllowed(boolean state);
+
+ /**
+ * @return the allowed races for new characters
+ */
+ @ConfigurationPropertyGetter(defaultValue = "HUMAN|ELF|DARK_ELF|ORC|DWARF|KAMAEL")
+ @ConfigurationXPath("creation/@allowed-races")
+ CharacterRace[] getAllowedNewCharacterRaces();
+
+ /**
+ * @param allowedRaces
+ * the allowed races for new characters
+ */
+ @ConfigurationPropertySetter
+ @ConfigurationXPath("creation/@allowed-races")
+ void setAllowedNewCharacterRaces(CharacterRace[] allowedRaces);
+
+ /**
+ * @return the allowed gender for new characters
+ */
+ @ConfigurationPropertyGetter(defaultValue = "MALE|FEMALE")
+ @ConfigurationXPath("creation/@allowed-genders")
+ ActorSex[] getAllowedNewCharacterGenders();
+
+ /**
+ * @param allowedGenders
+ * the allowed genders
+ */
+ @ConfigurationPropertySetter
+ @ConfigurationXPath("creation/@allowed-genders")
+ void setAllowedNewCharacterGenders(ActorSex[] allowedGenders);
+
+ /**
+ * @return the maximum number of character per account on this server
+ */
+ @ConfigurationPropertyGetter(defaultValue = "8")
+ @ConfigurationXPath("creation/limits/@max-per-account")
+ int getMaxCharactersPerAccount();
+
+ /**
+ * @param maxCharactersPerAccount
+ * the maximum number of character per account on this server
+ */
+ @ConfigurationPropertySetter
+ @ConfigurationXPath("creation/limits/@max-per-account")
+ void setMaxCharactersPerAccount(int maxCharactersPerAccount);
+}
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java
index dc2f89a5c..e5106b8a5 100644
--- a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/CharacterServiceImpl.java
@@ -50,7 +50,7 @@ import com.l2jserver.model.world.character.event.CharacterStartMovingEvent;
import com.l2jserver.model.world.character.event.CharacterTargetDeselectedEvent;
import com.l2jserver.model.world.character.event.CharacterTargetSelectedEvent;
import com.l2jserver.model.world.character.event.CharacterWalkingEvent;
-import com.l2jserver.service.AbstractService;
+import com.l2jserver.service.AbstractConfigurableService;
import com.l2jserver.service.AbstractService.Depends;
import com.l2jserver.service.game.AttackService;
import com.l2jserver.service.game.npc.NPCService;
@@ -63,6 +63,7 @@ import com.l2jserver.service.game.world.WorldService;
import com.l2jserver.service.game.world.event.WorldEventDispatcher;
import com.l2jserver.service.network.broadcast.BroadcastService;
import com.l2jserver.service.network.gameguard.GameGuardService;
+import com.l2jserver.util.ArrayUtils;
import com.l2jserver.util.factory.CollectionFactory;
import com.l2jserver.util.geometry.Coordinate;
import com.l2jserver.util.geometry.Point3D;
@@ -73,7 +74,8 @@ import com.l2jserver.util.geometry.Point3D;
* @author Rogiel
*/
@Depends({ WorldService.class, SpawnService.class, AttackService.class })
-public class CharacterServiceImpl extends AbstractService implements
+public class CharacterServiceImpl extends
+ AbstractConfigurableService implements
CharacterService {
/**
* The logger
@@ -165,6 +167,7 @@ public class CharacterServiceImpl extends AbstractService implements
CharacterShortcutDAO shortcutDao,
CharacterTemplateIDProvider charTemplateIdProvider,
CharacterIDProvider charIdProvider) {
+ super(CharacterServiceConfiguration.class);
this.broadcastService = broadcastService;
this.eventDispatcher = eventDispatcher;
this.spawnService = spawnService;
@@ -177,13 +180,29 @@ public class CharacterServiceImpl extends AbstractService implements
this.charIdProvider = charIdProvider;
}
+ @Override
+ public boolean canCreate(AccountID accountID) {
+ if (!config.isCharacterCreationAllowed())
+ return false;
+ return characterDao.selectByAccount(accountID).size() < config
+ .getMaxCharactersPerAccount();
+ }
+
@Override
public L2Character create(String name, AccountID accountID, ActorSex sex,
CharacterClass characterClass, CharacterHairStyle hairStyle,
CharacterHairColor hairColor, CharacterFace face)
throws CharacterInvalidNameException,
CharacterInvalidAppearanceException,
- CharacterNameAlreadyExistsException {
+ CharacterNameAlreadyExistsException,
+ CharacteCreationNotAllowedException, CharacterInvalidRaceException,
+ CharacterInvalidSexException, TooManyCharactersException {
+ if (!config.isCharacterCreationAllowed())
+ throw new CharacteCreationNotAllowedException();
+ if(characterDao.selectByAccount(accountID).size() < config
+ .getMaxCharactersPerAccount())
+ throw new TooManyCharactersException();
+
log.debug(
"Requested creation of new character (name={}, sex={}, class={}, hairStyle={}, hairColor={}, face={})",
new Object[] { name, sex, characterClass, hairStyle, hairColor,
@@ -209,6 +228,13 @@ public class CharacterServiceImpl extends AbstractService implements
final CharacterTemplateID templateId = charTemplateIdProvider
.resolveID(characterClass.id);
final CharacterTemplate template = templateId.getTemplate();
+
+ if (!ArrayUtils.contains(config.getAllowedNewCharacterRaces(),
+ template.getRace()))
+ throw new CharacterInvalidRaceException();
+ if (!ArrayUtils.contains(config.getAllowedNewCharacterGenders(), sex))
+ throw new CharacterInvalidSexException();
+
log.debug("Creating character with template {}", template);
// everything is fine, allocate a new ID
diff --git a/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/TooManyCharactersException.java b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/TooManyCharactersException.java
new file mode 100644
index 000000000..6c4415f4c
--- /dev/null
+++ b/l2jserver2-gameserver/src/main/java/com/l2jserver/service/game/character/TooManyCharactersException.java
@@ -0,0 +1,31 @@
+/*
+ * This file is part of l2jserver2 .
+ *
+ * l2jserver2 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.
+ *
+ * l2jserver2 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 l2jserver2. If not, see .
+ */
+package com.l2jserver.service.game.character;
+
+/**
+ * Exception thrown when the character is trying to create a new character when
+ * the creation limit has been exceeded.
+ *
+ * @author Rogiel
+ */
+public class TooManyCharactersException extends
+ CharacterServiceException {
+ /**
+ * The Java Serialization API serial
+ */
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file