Refactored character creation

This commit is contained in:
Obique PSWG
2016-12-31 12:37:02 -06:00
parent 0530a5dcbc
commit b87e06331d
5 changed files with 251 additions and 181 deletions
+2 -2
View File
@@ -142,9 +142,9 @@ public class IntentManager {
private void broadcast(IntentReceiver r, Intent i) {
try {
r.onIntentReceived(i);
} catch (Exception e) {
} catch (Throwable t) {
Log.e("IntentManager", "Fatal Exception while processing intent: " + i);
Log.e("IntentManager", e);
Log.e("IntentManager", t);
}
}
+11 -7
View File
@@ -186,10 +186,12 @@ public class ObjectAwareness extends Service implements TerrainMapCallback {
private void handleObjectCreatedIntent(ObjectCreatedIntent oci) {
SWGObject object = oci.getObject();
if (object.getParent() == null)
moveObject(object, object.getLocation());
else
if (object.getParent() == null) {
if (object.getTerrain() != null)
moveObject(object, object.getLocation());
} else {
moveObject(object, object.getParent(), object.getLocation());
}
}
private void handleDestroyObjectIntent(DestroyObjectIntent doi) {
@@ -249,11 +251,12 @@ public class ObjectAwareness extends Service implements TerrainMapCallback {
private void processContainerTransferIntent(ContainerTransferIntent i) {
Assert.notNull(i.getObject());
Assert.notNull(i.getObject().getTerrain());
if (i.getContainer() == null)
moveObject(i.getObject(), i.getObject().getLocation());
else
if (i.getContainer() == null) {
if (i.getObject().getTerrain() != null)
moveObject(i.getObject(), i.getObject().getLocation());
} else {
moveObject(i.getObject(), i.getContainer(), i.getObject().getLocation());
}
}
private void handleZoneIn(CreatureObject creature, Player player, boolean firstZone) {
@@ -316,6 +319,7 @@ public class ObjectAwareness extends Service implements TerrainMapCallback {
}
private void moveObject(SWGObject obj, Location requestedLocation) {
Assert.notNull(requestedLocation.getTerrain());
awarenessHandler.moveObject(obj, requestedLocation);
}
@@ -106,12 +106,10 @@ public class CharacterCreationRestriction {
public boolean isAbleToCreate() {
synchronized (lastCreations) {
Log.d("CharacterCreationRestriction", "Size: %d Period: %d", lastCreations.size(), creationsPerPeriod);
if (lastCreations.size() < creationsPerPeriod)
return true;
if (creationsPerPeriod == 0)
return true;
Log.d("CharacterCreationRestriction", "Last: %d Within: %b", lastCreations.getLast(), isWithinPeriod(lastCreations.getLast().longValue()));
return !isWithinPeriod(lastCreations.getLast().longValue());
}
}
@@ -125,9 +123,8 @@ public class CharacterCreationRestriction {
final long time = now();
if (hackSuccess) {
final String state = Arrays.toString(lastCreations.toArray(new Long[lastCreations.size()]));
Log.e("CharacterCreationRestriction", "Character created when not allowed! Current time/state: %s/%s", time, state);
Log.e(this, "Character created when not allowed! Current time/state: %s/%s", time, state);
}
Log.d("CharacterCreationRestriction", "HitMax: %b HackSuccess: %b", hitMax, hackSuccess);
if (hitMax)
lastCreations.pollLast();
lastCreations.addFirst(time);
+51 -168
View File
@@ -29,14 +29,10 @@ package services.player;
import intents.GalacticIntent;
import intents.PlayerEventIntent;
import intents.experience.GrantSkillIntent;
import intents.object.DestroyObjectIntent;
import intents.object.ObjectCreatedIntent;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -53,30 +49,22 @@ import network.packets.swg.login.creation.RandomNameRequest;
import network.packets.swg.login.creation.RandomNameResponse;
import network.packets.swg.login.creation.ClientVerifyAndLockNameResponse.ErrorMessage;
import network.packets.swg.login.creation.CreateCharacterFailure.NameFailureReason;
import resources.PvpFlag;
import resources.Race;
import resources.client_info.ClientFactory;
import resources.client_info.visitors.ProfTemplateData;
import resources.config.ConfigFile;
import resources.containers.ContainerPermissionsType;
import resources.control.Assert;
import resources.control.Service;
import resources.objects.SWGObject;
import resources.objects.building.BuildingObject;
import resources.objects.cell.CellObject;
import resources.objects.creature.CreatureObject;
import resources.objects.player.PlayerObject;
import resources.objects.tangible.TangibleObject;
import resources.objects.weapon.WeaponObject;
import resources.objects.weapon.WeaponType;
import resources.player.AccessLevel;
import resources.player.Player;
import resources.player.PlayerEvent;
import resources.player.PlayerState;
import resources.server_info.Log;
import resources.zone.NameFilter;
import services.objects.ObjectCreator;
import services.objects.ObjectManager;
import services.player.TerrainZoneInsertion.SpawnInformation;
import services.player.creation.CharacterCreation;
import utilities.namegen.SWGNameGenerator;
public class CharacterCreationService extends Service {
@@ -195,36 +183,56 @@ public class CharacterCreationService extends Service {
}
private void handleCharCreation(ObjectManager objManager, Player player, ClientCreateCharacter create) {
ErrorMessage err = getNameValidity(create.getName(), player.getAccessLevel() != AccessLevel.PLAYER);
boolean success = false;
int max = getConfig(ConfigFile.PRIMARY).getInt("GALAXY-MAX-CHARACTERS", 0);
if (max != 0 && getCharacterCount(player.getUserId()) >= max)
err = ErrorMessage.SERVER_CHARACTER_CREATION_MAX_CHARS;
else if (!creationRestriction.isAbleToCreate(player))
err = ErrorMessage.NAME_DECLINED_TOO_FAST;
else if (err == ErrorMessage.NAME_APPROVED) {
err = completeCharCreation(objManager, player, create);
success = (err == ErrorMessage.NAME_APPROVED);
}
if (!success)
sendCharCreationFailure(player, create, err);
CreatureObject creature = tryCharacterCreation(objManager, player, create);
if (creature == null)
return; // Unable to successfully create character
Assert.notNull(creature.getPlayerObject());
Assert.test(creature.isPlayer());
Assert.test(creature.getObjectId() > 0);
Log.i(this, "%s created character %s from %s:%d", player.getUsername(), create.getName(), create.getAddress(), create.getPort());
player.sendPacket(new CreateCharacterSuccess(creature.getObjectId()));
new PlayerEventIntent(player, PlayerEvent.PE_CREATE_CHARACTER).broadcast();
}
private ErrorMessage completeCharCreation(ObjectManager objManager, Player player, ClientCreateCharacter create) {
private CreatureObject tryCharacterCreation(ObjectManager objManager, Player player, ClientCreateCharacter create) {
// Valid Name
ErrorMessage err = getNameValidity(create.getName(), player.getAccessLevel() != AccessLevel.PLAYER);
if (err != ErrorMessage.NAME_APPROVED) {
sendCharCreationFailure(player, create, err);
return null;
}
// Too many characters
int max = getConfig(ConfigFile.PRIMARY).getInt("GALAXY-MAX-CHARACTERS", 0);
if (max != 0 && getCharacterCount(player.getUserId()) >= max) {
sendCharCreationFailure(player, create, ErrorMessage.SERVER_CHARACTER_CREATION_MAX_CHARS);
return null;
}
// Created too quickly
if (!creationRestriction.isAbleToCreate(player)) {
sendCharCreationFailure(player, create, ErrorMessage.NAME_DECLINED_TOO_FAST);
return null;
}
// Test for successful creation
CreatureObject creature = createCharacter(objManager, player, create);
if (creature == null) {
return ErrorMessage.NAME_DECLINED_INTERNAL_ERROR;
} else if (createCharacterInDb(creature, create.getName(), player)) {
creationRestriction.createdCharacter(player);
Log.i("ZoneService", "%s created character %s from %s:%d", player.getUsername(), create.getName(), create.getAddress(), create.getPort());
player.sendPacket(new CreateCharacterSuccess(creature.getObjectId()));
new PlayerEventIntent(player, PlayerEvent.PE_CREATE_CHARACTER).broadcast();
return ErrorMessage.NAME_APPROVED;
} else {
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());
new DestroyObjectIntent(creature).broadcast();
return ErrorMessage.NAME_DECLINED_INTERNAL_ERROR;
Log.e(this, "Failed to create CreatureObject!");
sendCharCreationFailure(player, create, ErrorMessage.NAME_DECLINED_INTERNAL_ERROR);
return null;
}
// Test for hacking
if (!creationRestriction.createdCharacter(player)) {
new DestroyObjectIntent(creature).broadcast();
sendCharCreationFailure(player, create, ErrorMessage.NAME_DECLINED_INTERNAL_ERROR);
return null;
}
// Test for successful database insertion
if (!createCharacterInDb(creature, create.getName(), player)) {
Log.e(this, "Failed to create character %s for user %s with server error from %s:%d", create.getName(), player.getUsername(), create.getAddress(), create.getPort());
new DestroyObjectIntent(creature).broadcast();
sendCharCreationFailure(player, create, ErrorMessage.NAME_DECLINED_INTERNAL_ERROR);
return null;
}
return creature;
}
private void sendCharCreationFailure(Player player, ClientCreateCharacter create, ErrorMessage err) {
@@ -242,6 +250,7 @@ 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;
}
@@ -305,140 +314,14 @@ public class CharacterCreationService extends Service {
}
private CreatureObject createCharacter(ObjectManager objManager, Player player, ClientCreateCharacter create) {
Race race = Race.getRaceByFile(create.getRace());
CreatureObject creatureObj = createCreature(objManager, race.getFilename(), getConfig(ConfigFile.PRIMARY).getString("PRIMARY-SPAWN-LOCATION", "tat_moseisley"));
if (creatureObj == null)
return null;
PlayerObject playerObj = createPlayer(objManager, "object/player/shared_player.iff");
playerObj.moveToContainer(creatureObj); // ghost slot
setCreatureObjectValues(objManager, creatureObj, create);
setPlayerObjectValues(playerObj, create);
createHair(objManager, creatureObj, create.getHair(), create.getHairCustomization());
createStarterClothing(objManager, creatureObj, create.getRace(), create.getClothes());
playerObj.setAdminTag(player.getAccessLevel());
new ObjectCreatedIntent(creatureObj).broadcast();
return creatureObj;
}
private CreatureObject createCreature(ObjectManager objManager, String template, String spawnLocation) {
String spawnLocation = getConfig(ConfigFile.PRIMARY).getString("PRIMARY-SPAWN-LOCATION", "tat_moseisley");
SpawnInformation info = insertion.generateSpawnLocation(spawnLocation);
if (info == null) {
Log.e("CharacterCreationService", "Failed to get spawn information for location: " + spawnLocation);
return null;
}
if (info.building)
return createCreatureBuilding(objManager, template, info);
else {
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
if (obj != null)
obj.setLocation(info.location);
if (obj instanceof CreatureObject)
return (CreatureObject) obj;
}
return null;
}
private CreatureObject createCreatureBuilding(ObjectManager objManager, String template, SpawnInformation info) {
SWGObject parent = objManager.getObjectById(info.buildingId);
if (parent == null || !(parent instanceof BuildingObject)) {
Log.e("CharacterCreationService", "Invalid parent! Either null or not a building: %s BUID: %d", parent, info.buildingId);
return null;
}
CellObject cell = ((BuildingObject) parent).getCellByName(info.cell);
if (cell == null) {
Log.e("CharacterCreationService", "Invalid cell! Cell does not exist: %s B-Template: %s BUID: %d", info.cell, parent.getTemplate(), info.buildingId);
return null;
}
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
obj.setLocation(info.location);
cell.addObject(obj);
if (obj instanceof CreatureObject)
return (CreatureObject) obj;
return null;
}
private PlayerObject createPlayer(ObjectManager objManager, String template) {
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
new ObjectCreatedIntent(obj).broadcast();
if (obj instanceof PlayerObject)
return (PlayerObject) obj;
return null;
}
private TangibleObject createTangible(ObjectManager objManager, String template) {
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
new ObjectCreatedIntent(obj).broadcast();
if (obj instanceof TangibleObject)
return (TangibleObject) obj;
return null;
}
private SWGObject createInventoryObject(ObjectManager objManager, CreatureObject creatureObj, String template) {
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
obj.moveToContainer(creatureObj);
obj.setContainerPermissions(ContainerPermissionsType.INVENTORY);
new ObjectCreatedIntent(obj).broadcast();
return obj;
}
private void createHair(ObjectManager objManager, CreatureObject creatureObj, String hair, byte [] customization) {
if (hair.isEmpty())
return;
TangibleObject hairObj = createTangible(objManager, ClientFactory.formatToSharedFile(hair));
hairObj.setAppearanceData(customization);
hairObj.moveToContainer(creatureObj); // hair slot
}
private void setCreatureObjectValues(ObjectManager objManager, CreatureObject creatureObj, ClientCreateCharacter create) {
creatureObj.setRace(Race.getRaceByFile(create.getRace()));
creatureObj.setAppearanceData(create.getCharCustomization());
creatureObj.setHeight(create.getHeight());
creatureObj.setName(create.getName());
creatureObj.setPvpFlags(PvpFlag.PLAYER);
creatureObj.setVolume(0x000F4240);
new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, create.getStartingPhase(), creatureObj, true).broadcast();
new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, "species_" + creatureObj.getRace().getSpecies(), creatureObj, true).broadcast();
WeaponObject defWeapon = (WeaponObject) createInventoryObject(objManager, creatureObj, "object/weapon/melee/unarmed/shared_unarmed_default_player.iff");
defWeapon.setMaxRange(5);
defWeapon.setType(WeaponType.UNARMED);
defWeapon.setAttackSpeed(1);
defWeapon.setMinDamage(50);
defWeapon.setMaxDamage(100);
creatureObj.setEquippedWeapon(defWeapon);
defWeapon.moveToContainer(creatureObj); // Occupies the default_weapon slot
createInventoryObject(objManager, creatureObj, "object/tangible/inventory/shared_character_inventory.iff");
createInventoryObject(objManager, creatureObj, "object/tangible/datapad/shared_character_datapad.iff");
createInventoryObject(objManager, creatureObj, "object/tangible/inventory/shared_appearance_inventory.iff");
createInventoryObject(objManager, creatureObj, "object/tangible/bank/shared_character_bank.iff");
createInventoryObject(objManager, creatureObj, "object/tangible/mission_bag/shared_mission_bag.iff");
}
private void setPlayerObjectValues(PlayerObject playerObj, ClientCreateCharacter create) {
playerObj.setProfession(create.getProfession());
Calendar date = Calendar.getInstance();
playerObj.setBornDate(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1, date.get(Calendar.DAY_OF_MONTH));
}
private void createStarterClothing(ObjectManager objManager, CreatureObject player, String race, String profession) {
if (player.getSlottedObject("inventory") == null)
return;
for (String template : profTemplates.get(profession).getItems(ClientFactory.formatToSharedFile(race))) {
TangibleObject item = createTangible(objManager, template);
if (item == null)
return;
// Move the new item to the player's clothing slots and add to equipment list
item.moveToContainer(player, player);
}
SWGObject inventory = player.getSlottedObject("inventory");
SWGObject item = ObjectCreator.createObjectFromTemplate("object/tangible/npe/shared_npe_uniform_box.iff");
item.moveToContainer(inventory);
new ObjectCreatedIntent(item).broadcast();
CharacterCreation creation = new CharacterCreation(objManager, profTemplates.get(create.getClothes()), create);
return creation.createCharacter(player.getAccessLevel(), info);
}
private void loadProfTemplates() {
@@ -0,0 +1,186 @@
/************************************************************************************
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* -------------------------------------------------------------------------------- *
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
* *
***********************************************************************************/
package services.player.creation;
import java.util.Calendar;
import intents.experience.GrantSkillIntent;
import intents.object.ObjectCreatedIntent;
import network.packets.swg.login.creation.ClientCreateCharacter;
import resources.PvpFlag;
import resources.Race;
import resources.client_info.ClientFactory;
import resources.client_info.visitors.ProfTemplateData;
import resources.containers.ContainerPermissionsType;
import resources.control.Assert;
import resources.objects.SWGObject;
import resources.objects.building.BuildingObject;
import resources.objects.cell.CellObject;
import resources.objects.creature.CreatureObject;
import resources.objects.player.PlayerObject;
import resources.objects.tangible.TangibleObject;
import resources.objects.weapon.WeaponObject;
import resources.objects.weapon.WeaponType;
import resources.player.AccessLevel;
import resources.server_info.Log;
import services.objects.ObjectCreator;
import services.objects.ObjectManager;
import services.player.TerrainZoneInsertion.SpawnInformation;
public class CharacterCreation {
private final ObjectManager objManager;
private final ProfTemplateData templateData;
private final ClientCreateCharacter create;
public CharacterCreation(ObjectManager objManager, ProfTemplateData templateData, ClientCreateCharacter create) {
this.objManager = objManager;
this.templateData = templateData;
this.create = create;
}
public CreatureObject createCharacter(AccessLevel accessLevel, SpawnInformation info) {
Race race = Race.getRaceByFile(create.getRace());
CreatureObject creatureObj = createCreature(race.getFilename(), info);
if (creatureObj == null)
return null;
PlayerObject playerObj = createPlayer(creatureObj, "object/player/shared_player.iff");
Assert.notNull(playerObj);
setCreatureObjectValues(creatureObj);
setPlayerObjectValues(playerObj);
createHair(creatureObj, create.getHair(), create.getHairCustomization());
createStarterClothing(creatureObj, create.getRace());
playerObj.setAdminTag(accessLevel);
new ObjectCreatedIntent(creatureObj).broadcast();
return creatureObj;
}
private CreatureObject createCreature(String template, SpawnInformation info) {
if (info.building)
return createCreatureBuilding(template, info);
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
Assert.test(obj instanceof CreatureObject);
obj.setLocation(info.location);
return (CreatureObject) obj;
}
private CreatureObject createCreatureBuilding(String template, SpawnInformation info) {
SWGObject parent = objManager.getObjectById(info.buildingId);
if (parent == null || !(parent instanceof BuildingObject)) {
Log.e(this, "Invalid parent! Either null or not a building: %s BUID: %d", parent, info.buildingId);
return null;
}
CellObject cell = ((BuildingObject) parent).getCellByName(info.cell);
if (cell == null) {
Log.e(this, "Invalid cell! Cell does not exist: %s B-Template: %s BUID: %d", info.cell, parent.getTemplate(), info.buildingId);
return null;
}
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
Assert.test(obj instanceof CreatureObject);
obj.setLocation(info.location);
obj.moveToContainer(cell);
return (CreatureObject) obj;
}
private PlayerObject createPlayer(CreatureObject creatureObj, String template) {
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
Assert.test(obj instanceof PlayerObject);
obj.moveToContainer(creatureObj);
new ObjectCreatedIntent(obj).broadcast();
return (PlayerObject) obj;
}
private TangibleObject createTangible(SWGObject container, ContainerPermissionsType type, String template) {
SWGObject obj = ObjectCreator.createObjectFromTemplate(template);
Assert.test(obj instanceof TangibleObject);
obj.setContainerPermissions(type);
obj.moveToContainer(container);
new ObjectCreatedIntent(obj).broadcast();
return (TangibleObject) obj;
}
/** Creates an object with default world visibility */
private TangibleObject createDefaultObject(SWGObject container, String template) {
return createTangible(container, ContainerPermissionsType.DEFAULT, template);
}
/** Creates an object with inventory-level world visibility (only the owner) */
private TangibleObject createInventoryObject(SWGObject container, String template) {
return createTangible(container, ContainerPermissionsType.INVENTORY, template);
}
private void createHair(CreatureObject creatureObj, String hair, byte [] customization) {
if (hair.isEmpty())
return;
TangibleObject hairObj = createDefaultObject(creatureObj, ClientFactory.formatToSharedFile(hair));
hairObj.setAppearanceData(customization);
}
private void setCreatureObjectValues(CreatureObject creatureObj) {
creatureObj.setRace(Race.getRaceByFile(create.getRace()));
creatureObj.setAppearanceData(create.getCharCustomization());
creatureObj.setHeight(create.getHeight());
creatureObj.setName(create.getName());
creatureObj.setPvpFlags(PvpFlag.PLAYER);
creatureObj.setVolume(0x000F4240);
new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, create.getStartingPhase(), creatureObj, true).broadcast();
new GrantSkillIntent(GrantSkillIntent.IntentType.GRANT, "species_" + creatureObj.getRace().getSpecies(), creatureObj, true).broadcast();
WeaponObject defWeapon = (WeaponObject) createInventoryObject(creatureObj, "object/weapon/melee/unarmed/shared_unarmed_default_player.iff");
defWeapon.setMaxRange(5);
defWeapon.setType(WeaponType.UNARMED);
defWeapon.setAttackSpeed(1);
defWeapon.setMinDamage(50);
defWeapon.setMaxDamage(100);
creatureObj.setEquippedWeapon(defWeapon);
createInventoryObject(creatureObj, "object/tangible/inventory/shared_character_inventory.iff");
createInventoryObject(creatureObj, "object/tangible/datapad/shared_character_datapad.iff");
createInventoryObject(creatureObj, "object/tangible/inventory/shared_appearance_inventory.iff");
createInventoryObject(creatureObj, "object/tangible/bank/shared_character_bank.iff");
createInventoryObject(creatureObj, "object/tangible/mission_bag/shared_mission_bag.iff");
}
private void setPlayerObjectValues(PlayerObject playerObj) {
playerObj.setProfession(create.getProfession());
Calendar date = Calendar.getInstance();
playerObj.setBornDate(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1, date.get(Calendar.DAY_OF_MONTH));
}
private void createStarterClothing(CreatureObject creature, String race) {
for (String template : templateData.getItems(ClientFactory.formatToSharedFile(race))) {
createDefaultObject(creature, template);
}
SWGObject inventory = creature.getSlottedObject("inventory");
Assert.notNull(inventory);
createDefaultObject(inventory, "object/tangible/npe/shared_npe_uniform_box.iff");
}
}