Public Repository for the Magicbane Shadowbane Emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1382 lines
52 KiB

package engine.net.client.handlers;
import engine.Enum;
import engine.Enum.*;
import engine.InterestManagement.HeightMap;
import engine.InterestManagement.InterestManager;
import engine.InterestManagement.RealmMap;
import engine.InterestManagement.WorldGrid;
import engine.db.archive.CityRecord;
import engine.db.archive.DataWarehouse;
import engine.exception.MsgSendException;
import engine.gameManager.*;
import engine.math.Bounds;
import engine.math.Vector3fImmutable;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
import engine.net.client.ClientConnection;
import engine.net.client.msg.CityZoneMsg;
import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.ErrorPopupMsg;
import engine.net.client.msg.PlaceAssetMsg;
import engine.net.client.msg.PlaceAssetMsg.PlacementInfo;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* @Summary: Processes application protocol message which requests
* creation of new city / buildings from seeds/deeds in inventory.
*/
public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
// Useful constants
// ActionType 1 = client request
// 2 = Server confirms open window
// 3 = Request to place asset
// 4 = Server confirms/close window
private static final int CLIENTREQ_UNKNOWN = 1;
private static final int SERVER_OPENWINDOW = 2;
private static final int CLIENTREQ_NEWBUILDING = 3; // Request to place asset
private static final int SERVER_CLOSEWINDOW = 4;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public PlaceAssetMsgHandler() {
super(PlaceAssetMsg.class);
}
private static void closePlaceAssetWindow(ClientConnection origin) {
// Action type 4 is the server telling the client to
// close the asset placement window.
// This is believed to be a confirmation message to the client
PlaceAssetMsg pam = new PlaceAssetMsg();
pam.setActionType(4);
Dispatch dispatch = Dispatch.borrow(origin.getPlayerCharacter(), pam);
DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.SECONDARY);
}
// Default method: Validates and places all buildings that do not
// require special treatment in some fashion.
private static boolean validateTreeOfLifePlacement(PlayerCharacter playerCharacter, Realm serverRealm, Zone serverZone,
ClientConnection origin, PlaceAssetMsg msg) {
PlacementInfo placementInfo = msg.getFirstPlacementInfo();
// Your guild already owns a tree
if (playerCharacter.getGuild().getOwnedCity() != null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "Your guild already owns a tree!");
return false;
}
// Validate that the player is the leader of a guild
if (GuildStatusController.isGuildLeader(playerCharacter.getGuildStatus()) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 10, ""); // Must be a guild leader
return false;
}
// Validate that the player is the leader of a guild
// that is not currently Sovereign *** BUG? Doesn't look right. isGuildLeader()?
if ((playerCharacter.getGuild().getGuildState() != GuildState.Sworn
|| playerCharacter.getGuild().getGuildState() != GuildState.Errant) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 17, ""); // Your is not an errant or soverign guild
return false;
}
// All trees must be placed within a continent.
if (!serverZone.isContinent()) {
PlaceAssetMsg.sendPlaceAssetError(origin, 69, ""); // Tree must be within a territory
return false;
}
if (serverRealm == null || serverRealm.getCanPlaceCities() == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 57, playerCharacter.getName()); // No building may be placed within this territory
return false;
}
// Cannot place a tree underwater
if (HeightMap.isLocUnderwater(placementInfo.getLoc())) {
PlaceAssetMsg.sendPlaceAssetError(origin, 6, ""); // Cannot place underwater
return false;
}
//Test city not too close to any other zone
if (!ZoneManager.validTreePlacementLoc(serverZone, placementInfo.getLoc().x, placementInfo.getLoc().z)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 39, ""); // Too close to another tree
return false;
}
// Validate that Realm is not at it's city limit
if (serverRealm.isRealmFull() == true) {
int numCities;
numCities = serverRealm.getNumCities();
PlaceAssetMsg.sendPlaceAssetError(origin, 58, Integer.toString(numCities)); // This territory is full
return false;
}
return true;
}
private static boolean validateBuildingPlacement(Zone serverZone, PlaceAssetMsg msg, ClientConnection origin, PlayerCharacter player, PlacementInfo placementInfo) {
if (serverZone.isPlayerCity() == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 52, player.getName());
return false;
}
City city = ZoneManager.getCityAtLocation(placementInfo.getLoc());
if (player.getGuild().equals(city.getGuild()) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 40, player.getName());
return false;
}
if (city.isLocationOnCityGrid(placementInfo.getLoc()) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 41, player.getName());
return false;
}
// Retrieve the building details we're placing
if (serverZone.isNPCCity() == true) {
PlaceAssetMsg.sendPlaceAssetError(origin, 15, ""); // Cannot place in a peace zone
return false;
}
// Errant guilds cannot place assets
if (player.getGuild().getGuildState() == GuildState.Errant) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "Only sovereign or sworn guilds may place assets.");
return false;
}
// Player must be GL or IC of a guild to place buildings.
if (GuildStatusController.isGuildLeader(player.getGuildStatus()) == false && GuildStatusController.isInnerCouncil(player.getGuildStatus()) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 10, ""); // You must be a guild leader
return false;
}
// Cannot place a building underwater
if (HeightMap.isLocUnderwater(placementInfo.getLoc())) {
PlaceAssetMsg.sendPlaceAssetError(origin, 6, ""); // Cannot place underwater
return false;
}
// Players cannot place buildings in mob zones.
if ((serverZone.isMacroZone() == true)
|| (serverZone.getParent().isMacroZone() == true)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 57, player.getName()); // No building may be placed within this territory
return false;
}
Realm serverRealm = RealmMap.getRealmAtLocation(city.getLoc());
// Cannot place buildings on seafloor or other restricted realms
if (serverRealm == null || serverRealm.getCanPlaceCities() == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 57, player.getName()); // No building may be placed within this territory
return false;
}
// Cannot place assets on a dead tree
if ((serverZone.isPlayerCity())
&& (City.getCity(serverZone.getPlayerCityUUID()).getTOL().getRank() == -1)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "Cannot place asset on dead tree until world heals");
return false;
}
if (placementCollisionCheck(serverZone, origin, placementInfo)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 3, ""); // Conflict between proposed assets
return false;
}
return true;
}
private static boolean placementCollisionCheck(Zone serverZone, ClientConnection origin, PlacementInfo placementInfo) {
// Overlap check
for (Building building : serverZone.zoneBuildingSet) {
if ((building.getBlueprintUUID() != 0) && (Bounds.collide(placementInfo, building) == true)) {
// Ignore and remove from simulation if we are placing over rubble
if (building.getRank() == -1) {
if ((building.getBlueprintUUID() != 0)
&& (building.getBlueprint().getBuildingGroup() == BuildingGroup.SHRINE)) {
Shrine.RemoveShrineFromCacheByBuilding(building);
if (building.getCity() != null) {
}
}
building.removeFromCache();
WorldGrid.RemoveWorldObject(building);
WorldGrid.removeObject(building);
building.getParentZone().zoneBuildingSet.remove(building);
if (building.getBlueprint() != null && building.getBlueprint().getBuildingGroup().equals(BuildingGroup.BARRACK)) {
building.RemoveFromBarracksList();
}
continue;
}
PlaceAssetMsg.sendPlaceAssetError(origin, 3, ""); // Conflict between proposed assets
return true;
}
}
return false;
}
private static boolean validateCityBuildingPlacement(Zone serverZone, PlaceAssetMsg msg, ClientConnection origin, PlayerCharacter player, PlacementInfo buildingInfo) {
// Perform shared common validation first
if (validateBuildingPlacement(serverZone, msg, origin, player, buildingInfo) == false)
return false;
// Must be a player city
if (serverZone.isPlayerCity() == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 41, player.getName()); // Cannot place outside a guild zone
return false;
}
//Test zone has a city object
City city = City.getCity(serverZone.getPlayerCityUUID());
if (city == null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 52, ""); //"no city to associate asset with"
return false;
}
// City assets must be placed on the city grid
if (!city.isLocationOnCityGrid(buildingInfo.getLoc())) {
PlaceAssetMsg.sendPlaceAssetError(origin, 52, "");
return false;
}
// Make sure it's not an errant tree
if ((city.getGuild() == null || city.getGuild().isEmptyGuild() == true)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 18, ""); //"There are no guild trees to be found"
return false;
}
//Test player is in correct guild to place buildings
if (!player.isCSR)
if (player.getGuild().getObjectUUID() != city.getGuild().getObjectUUID()) {
PlaceAssetMsg.sendPlaceAssetError(origin, 9, ""); //You must be a guild member to place this asset
return false;
}
return true;
}
@Override
protected boolean _handleNetMsg(ClientNetMsg baseMsg, ClientConnection origin) throws MsgSendException {
// Member variable declaration
PlaceAssetMsg msg;
Boolean buildingCreated;
// Character location and session
PlayerCharacter playerCharacter;
PlacementInfo buildingList;
Blueprint buildingBlueprint;
// Tell compiler it's ok to trust us and parse
// what we need from the message structure
msg = (PlaceAssetMsg) baseMsg;
// Action type 3 is a client requesting to place an object
// For all other action types let's just early exit
if (msg.getActionType() != CLIENTREQ_NEWBUILDING)
return true;
// assign our character
playerCharacter = SessionManager.getPlayerCharacter(origin);
// We need to figure out what exactly the player is attempting
// to place, as some objects like tol/bane/walls are edge cases.
// So let's get the first item in their list.
buildingList = msg.getFirstPlacementInfo();
// Early exit if null building list.
if (buildingList == null) {
Logger.error("Player " + playerCharacter.getCombinedName()
+ " null building list on deed use");
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
closePlaceAssetWindow(origin);
return true;
}
Item contract = null;
for (Item inventoryItem : playerCharacter.getInventory()) {
if (inventoryItem.getItemBase().getUseID() == buildingList.getBlueprintUUID()) {
contract = inventoryItem;
break;
}
}
// Grab the blueprint from the uuid in the message
buildingBlueprint = Blueprint.getBlueprint(buildingList.getBlueprintUUID());
// Early exit if blueprint can't be retrieved for the object.
if (buildingBlueprint == null) {
Logger.error("Player " + playerCharacter.getCombinedName()
+ " null blueprint UUID: " + buildingList.getBlueprintUUID() + " on deed use");
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
closePlaceAssetWindow(origin);
return true;
}
// Let's now attempt to place the building
buildingCreated = false;
// Many buildings have particular validation and
// post-creation cleanup requirements.
boolean close = true;
lock.writeLock().lock();
boolean isSiege = false;
try {
switch (buildingBlueprint.getBuildingGroup()) {
case TOL:
if (contract == null)
break;
buildingCreated = placeTreeOfLife(playerCharacter, origin, msg);
break;
case WAREHOUSE:
if (contract == null)
break;
if (!playerCharacter.getCharItemManager().doesCharOwnThisItem(contract.getObjectUUID()))
break;
buildingCreated = placeWarehouse(playerCharacter, origin, msg);
break;
case SIEGETENT:
case BULWARK:
if (contract == null)
break;
if (!playerCharacter.getCharItemManager().doesCharOwnThisItem(contract.getObjectUUID()))
break;
buildingCreated = placeSiegeEquip(playerCharacter, origin, msg);
break;
case SPIRE:
if (contract == null)
break;
if (!playerCharacter.getCharItemManager().doesCharOwnThisItem(contract.getObjectUUID()))
break;
buildingCreated = placeSpire(playerCharacter, origin, msg);
break;
case SHRINE:
if (contract == null)
break;
if (!playerCharacter.getCharItemManager().doesCharOwnThisItem(contract.getObjectUUID()))
break;
buildingCreated = placeShrine(playerCharacter, origin, msg);
break;
case BARRACK:
if (contract == null)
break;
if (!playerCharacter.getCharItemManager().doesCharOwnThisItem(contract.getObjectUUID()))
break;
buildingCreated = placeBarrack(playerCharacter, origin, msg);
break;
case WALLSTRAIGHT:
case WALLCORNER:
case SMALLGATE:
case ARTYTOWER:
case WALLSTAIRS:
case WALLSTRAIGHTTOWER:
buildingCreated = placeCityWalls(playerCharacter, origin, msg);
close = false;
break;
default:
if (contract == null)
break;
if (!playerCharacter.getCharItemManager().doesCharOwnThisItem(contract.getObjectUUID()))
break;
buildingCreated = placeSingleBuilding(playerCharacter, origin, msg);
break;
}
} catch (Exception e) {
Logger.error("PlaceAssetHandler", e.getMessage());
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
// Remove the appropriate deed.
if (buildingCreated == true)
if (contract != null) {
playerCharacter.getCharItemManager().delete(contract);
playerCharacter.getCharItemManager().updateInventory();
}
// Close the window. We're done!
//DONT CLOSE THE WINDOW IF WALL KTHANX
if (close)
closePlaceAssetWindow(origin);
return true;
}
private boolean placeSingleBuilding(PlayerCharacter playerCharacter, ClientConnection origin, PlaceAssetMsg msg) {
PlacementInfo buildingList;
Zone serverZone;
// Retrieve the building details we're placing
buildingList = msg.getFirstPlacementInfo();
serverZone = ZoneManager.findSmallestZone(buildingList.getLoc());
// Early exit if something went horribly wrong
// with locating the current or zone
if (serverZone == null) {
Logger.error("Null zone in placeSingleBuilding");
return false;
}
// Method checks validation conditions arising when placing
// buildings. Player must be on a city grid, must be
// inner council of the city's guild, etc.
if (validateBuildingPlacement(serverZone, msg, origin, playerCharacter, buildingList) == false)
return false; // Close window here?
// Place the building
if (createStructure(playerCharacter, buildingList, serverZone) == null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
return false;
}
return true;
}
private boolean placeWarehouse(PlayerCharacter player, ClientConnection origin, PlaceAssetMsg msg) {
Zone serverZone;
City cityObject;
PlacementInfo buildingList;
// Retrieve the building details we're placing
buildingList = msg.getFirstPlacementInfo();
// Setup working variables we'll need
serverZone = ZoneManager.findSmallestZone(buildingList.getLoc());
// Early exit if something went horribly wrong
if (serverZone == null)
return false;
cityObject = City.getCity(serverZone.getPlayerCityUUID());
// Early exit if something went horribly wrong
if (cityObject == null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 52, "");
return false;
}
// Method checks validation conditions arising when placing
// buildings. Player must be on a city grid, must be
// inner council of the city's guild, etc.
if (validateCityBuildingPlacement(serverZone, msg, origin, player, buildingList) == false)
return false;
if (cityObject.getWarehouse() != null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 50, ""); //"You can only have one warehouse"
return false;
}
// Create the warehouse object and it's entry in the database
if (createWarehouse(player, msg.getFirstPlacementInfo(), serverZone) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
return false;
}
return true;
}
private boolean placeSiegeEquip(PlayerCharacter player, ClientConnection origin, PlaceAssetMsg msg) {
Zone serverZone;
Building siegeBuilding;
PlacementInfo buildingList;
City serverCity;
Bane bane;
// Retrieve the building details we're placing
buildingList = msg.getFirstPlacementInfo();
// Setup working variables we'll need
serverZone = ZoneManager.findSmallestZone(buildingList.getLoc());
// Early exit if something went horribly wrong
// with locating the current city and/or zone
if (serverZone == null) {
Logger.error("Error obtaining reference to zone");
return false;
}
serverCity = ZoneManager.getCityAtLocation(buildingList.getLoc());
// No valid player city found
if (serverCity == null || serverCity.getParent().isPlayerCity() == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 52, ""); // Cannot place outisde a guild zone
return false;
}
// No bane no bow
bane = serverCity.getBane();
if (bane == null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 66, ""); // There is no bane circle to support this building of war
return false;
}
// Must belong to either attacker or defenders.
if ((player.getGuild().equals(serverCity.getBane().getOwner().getGuild()) == false)
&& (player.getGuild().equals(serverCity.getGuild()) == false)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 54, ""); // Must belong to attacker or defender
return false;
}
// Player must be GL or IC of the bane guild to place bow.
if (GuildStatusController.isGuildLeader(player.getGuildStatus()) == false
&& GuildStatusController.isInnerCouncil(player.getGuildStatus()) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 10, player.getName()); // You must be a guild leader to place this asset
return false;
}
// Attackers cannot place on grid until bane is live
if (bane.getSiegePhase() != SiegePhase.WAR &&
player.getGuild().equals(serverCity.getBane().getOwner().getGuild()) &&
serverCity.isLocationOnCityGrid(buildingList.getLoc())) {
PlaceAssetMsg.sendPlaceAssetError(origin, 53, player.getName()); // Buildings of war cannot be placed around a city grid unless there is an active bane
return false;
}
// If there is a bane placed, we limit bow placement to 2x the stone rank's worth of attacker assets
// and 1x the tree rank for defenders
if (validateSiegeLimits(player, origin, serverCity.getBane()) == false)
return false;
// Collision check (Removes rubble side effect)
if (placementCollisionCheck(serverZone, origin, buildingList)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 3, ""); // Conflict between proposed assets
return false;
}
// Create the siege Building
siegeBuilding = createStructure(player, msg.getFirstPlacementInfo(), serverZone);
// Oops something went really wrong
if (siegeBuilding == null)
return false;
// passes validation: can assign auto-protection to war asset
siegeBuilding.setProtectionState(ProtectionState.PROTECTED);
return true;
}
private boolean validateSiegeLimits(PlayerCharacter playerCharacter, ClientConnection origin, Bane bane) {
City serverCity = bane.getCity();
HashSet<AbstractWorldObject> awoList;
HashSet<AbstractWorldObject> attackerBuildings = new HashSet<>();
HashSet<AbstractWorldObject> defenderBuildings = new HashSet<>();
;
int maxAttackerAssets = serverCity.getBane().getStone().getRank() * 2;
int maxDefenderAssets = serverCity.getRank();
// Count bow for attackers and defenders
awoList = WorldGrid.getObjectsInRangePartial(serverCity, 1000, MBServerStatics.MASK_BUILDING);
for (AbstractWorldObject awo : awoList) {
Building building = (Building) awo;
if (building.getBlueprint() != null)
if (!building.getBlueprint().isSiegeEquip())
continue;
if (!building.getLoc().isInsideCircle(serverCity.getLoc(), CityBoundsType.ZONE.extents))
continue;
if (building.getGuild() == null)
continue;
if (building.getGuild().isEmptyGuild())
continue;
if (!building.getGuild().equals(serverCity.getGuild()) && !building.getGuild().equals(serverCity.getBane().getOwner().getGuild()))
continue;
if (building.getRank() < 0) {
continue;
}
if (building.getGuild().equals(serverCity.getGuild()))
defenderBuildings.add(building);
if (building.getGuild().equals(serverCity.getBane().getOwner().getGuild()))
attackerBuildings.add(building);
}
// Validate bane limits on siege assets
if (playerCharacter.getGuild().equals(serverCity.getGuild())) {
//defender attempting to place asset
if (defenderBuildings.size() >= maxDefenderAssets) {
PlaceAssetMsg.sendPlaceAssetError(origin, 62, "");
return false;
}
}
if (playerCharacter.getGuild().equals(serverCity.getBane().getStone().getGuild())) {
//attacker attempting to place asset
if (attackerBuildings.size() >= maxAttackerAssets) {
PlaceAssetMsg.sendPlaceAssetError(origin, 61, "");
return false;
}
}
// Passed validation
return true;
}
private boolean placeTreeOfLife(PlayerCharacter playerCharacter, ClientConnection origin, PlaceAssetMsg msg) {
Realm serverRealm;
Zone serverZone;
ArrayList<AbstractGameObject> cityObjects; // MySql result set
HashMap<GameObjectType, AbstractGameObject> cityObjectMap = new HashMap<>();
PlacementInfo treeInfo;
Guild playerNation;
PlacementInfo treePlacement = msg.getFirstPlacementInfo();
Building treeObject;
City cityObject;
Zone zoneObject;
// Setup working variables we'll need
serverRealm = RealmMap.getRealmAtLocation(treePlacement.getLoc());
serverZone = ZoneManager.findSmallestZone(treePlacement.getLoc());
// Early exit if something went horribly wrong
// with locating the current realm and/or zone
if (serverRealm == null || serverZone == null)
return false;
// Method checks validation conditions arising when placing
// trees
if (validateTreeOfLifePlacement(playerCharacter, serverRealm, serverZone, origin, msg) == false)
return false;
// Retrieve tree info for the w value it's passing.
treeInfo = msg.getFirstPlacementInfo();
if (treeInfo == null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
return false;
}
Vector3fImmutable plantLoc = new Vector3fImmutable(treeInfo.getLoc().x,
HeightMap.getWorldHeight(treeInfo.getLoc()),
treeInfo.getLoc().z);
cityObjects = DbManager.CityQueries.CREATE_CITY(playerCharacter.getObjectUUID(), serverZone.getObjectUUID(),
serverRealm.getRealmID(),
plantLoc.x - serverZone.getAbsX(), plantLoc.y,
plantLoc.z - serverZone.getAbsZ(), treeInfo.getRot().y, treeInfo.getW(), playerCharacter.getGuild().getName(), LocalDateTime.now());
// Uh oh!
if (cityObjects == null || cityObjects.isEmpty()) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
return false;
}
// Assign our worker variables after figuring out what
// is what in the result set.
for (AbstractGameObject gameObject : cityObjects)
cityObjectMap.put(gameObject.getObjectType(), gameObject);
treeObject = (Building) cityObjectMap.get(GameObjectType.Building);
treeObject.runAfterLoad();
;
cityObject = (City) cityObjectMap.get(GameObjectType.City);
zoneObject = (Zone) cityObjectMap.get(GameObjectType.Zone);
// not allowed to plant a tree if ur not an errant guild.
// Desub from any previous nation.
// This should be done automatically in a method inside Guild *** Refactor
// Player is now a Sovereign guild, configure them as such.
playerCharacter.getGuild().setNation(playerCharacter.getGuild());
playerNation = playerCharacter.getGuild();
playerNation.setGuildState(GuildState.Sovereign);
// Link the zone with the city and then add
// to the appropriate hash tables and cache
zoneObject.setPlayerCity(true);
if (zoneObject.getParent() != null)
zoneObject.getParent().addNode(zoneObject); //add as child to parent
ZoneManager.addZone(zoneObject.getObjectUUID(), zoneObject);
ZoneManager.addPlayerCityZone(zoneObject);
serverZone.addNode(zoneObject);
zoneObject.generateWorldAltitude();
cityObject.setParent(zoneObject);
cityObject.setObjectTypeMask(MBServerStatics.MASK_CITY); // *** Refactor : should have it already
//Link the tree of life with the new zone
treeObject.setObjectTypeMask(MBServerStatics.MASK_BUILDING);
treeObject.setParentZone(zoneObject);
MaintenanceManager.setMaintDateTime(treeObject, LocalDateTime.now().plusDays(7));
// Update guild binds and tags
//load the new city on the clients
CityZoneMsg czm = new CityZoneMsg(1, treeObject.getLoc().x, treeObject.getLoc().y, treeObject.getLoc().z, cityObject.getCityName(), zoneObject, Enum.CityBoundsType.ZONE.extents, Enum.CityBoundsType.ZONE.extents);
DispatchMessage.dispatchMsgToAll(czm);
GuildManager.updateAllGuildBinds(playerNation, cityObject);
GuildManager.updateAllGuildTags(playerNation);
// Send all the cities to the clients?
// *** Refactor : figure out how to send like, one?
City.lastCityUpdate = System.currentTimeMillis();
treeObject.setLoc(treeObject.getLoc());
InterestManager.setObjectDirty(treeObject);
// WorldGrid.addObject(treeObject, playerCharacter);
serverRealm.addCity(cityObject.getObjectUUID());
playerNation.setCityUUID(cityObject.getObjectUUID());
// Bypass warehouse entry if we're an admin
if (playerCharacter.getAccount().status.equals(AccountStatus.ADMIN))
return true;
// Push this event to the data warehouse
CityRecord cityRecord = CityRecord.borrow(cityObject, RecordEventType.CREATE);
DataWarehouse.pushToWarehouse(cityRecord);
return true;
}
// Method validates the location we have selected for our new city
private boolean placeSpire(PlayerCharacter playerCharacter, ClientConnection origin, PlaceAssetMsg msg) {
Zone serverZone;
Building spireBuilding;
Blueprint blueprint;
City cityObject;
PlacementInfo buildingList;
// Setup working variables we'll need
buildingList = msg.getFirstPlacementInfo();
serverZone = ZoneManager.findSmallestZone(buildingList.getLoc());
// Early exit if something went horribly wrong
// with locating the current realm and/or city
if (serverZone == null)
return false;
cityObject = City.getCity(serverZone.getPlayerCityUUID());
if (cityObject == null)
return false;
// Method checks validation conditions arising when placing
// buildings. Player must be on a city grid, must be
// inner council of the city's guild, etc.
if (validateCityBuildingPlacement(serverZone, msg, origin, playerCharacter, buildingList) == false)
return false;
// Loop through all buildings in this city looking for a spire of the.
// same type we are placing. There can be only one of each type
int spireCount = 0;
blueprint = Blueprint.getBlueprint(msg.getFirstPlacementInfo().getBlueprintUUID());
for (Building building : serverZone.zoneBuildingSet) {
if (building.getBlueprint().getBuildingGroup() == BuildingGroup.SPIRE) {
if (building.getBlueprintUUID() == blueprint.getMeshForRank(0)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 46, ""); // "Spire of that type exists"
return false;
}
spireCount++;
}
}
// Too many spires for this tree's rank?
if (spireCount >= Blueprint.getMaxShrines(cityObject.getTOL().getRank())) {
PlaceAssetMsg.sendPlaceAssetError(origin, 45, ""); //Tree cannot support anymore spires
return false;
}
// Create the spire
spireBuilding = createStructure(playerCharacter, msg.getFirstPlacementInfo(), serverZone);
return spireBuilding != null;
}
private boolean placeShrine(PlayerCharacter playerCharacter, ClientConnection origin, PlaceAssetMsg msg) {
Zone serverZone;
Blueprint blueprint;
City cityObject;
PlacementInfo buildingList;
// Setup working variables we'll need
buildingList = msg.getFirstPlacementInfo();
serverZone = ZoneManager.findSmallestZone(buildingList.getLoc());
// Early exit if something went horribly wrong
// with locating the current realm and/or zone
if (serverZone == null)
return false;
// Method checks validation conditions arising when placing
// buildings. Player must be on a city grid, must be
// inner council of the city's guild, etc.
if (validateCityBuildingPlacement(serverZone, msg, origin, playerCharacter, buildingList) == false)
return false;
// Loop through all buildings in this city looking for a shrine of the.
// same type we are placing. There can be only one of each type
int shrineCount = 0;
cityObject = City.getCity(serverZone.getPlayerCityUUID());
// Cannot place shrine in abandoned city. Shrines must be owned
// by the tol owner not the person placing them.
if (cityObject.getTOL().getOwnerUUID() == 0) {
PlaceAssetMsg.sendPlaceAssetError(origin, 42, ""); //Tree cannot support anymore shrines
return false;
}
blueprint = Blueprint.getBlueprint(msg.getFirstPlacementInfo().getBlueprintUUID());
if (blueprint == null) {
return false;
}
for (Building building : serverZone.zoneBuildingSet) {
if (building.getBlueprint() == null)
continue;
if (building.getBlueprint().getBuildingGroup() == BuildingGroup.SHRINE) {
if (building.getBlueprintUUID() == blueprint.getMeshForRank(0)) {
PlaceAssetMsg.sendPlaceAssetError(origin, 43, ""); // "shrine of that type exists"
return false;
}
shrineCount++;
}
}
// Too many shrines for this tree's rank?
if (shrineCount >= Blueprint.getMaxShrines(cityObject.getTOL().getRank())) {
PlaceAssetMsg.sendPlaceAssetError(origin, 42, ""); //Tree cannot support anymore shrines
return false;
}
// Create the shrine
return createShrine((PlayerCharacter) cityObject.getTOL().getOwner(), msg.getFirstPlacementInfo(), serverZone);
}
private boolean placeBarrack(PlayerCharacter playerCharacter, ClientConnection origin, PlaceAssetMsg msg) {
Zone serverZone;
City cityObject;
PlacementInfo buildingList;
// Setup working variables we'll need
buildingList = msg.getFirstPlacementInfo();
serverZone = ZoneManager.findSmallestZone(buildingList.getLoc());
// Early exit if something went horribly wrong
// with locating the current realm and/or zone
if (serverZone == null)
return false;
// Method checks validation conditions arising when placing
// buildings. Player must be on a city grid, must be
// inner council of the city's guild, etc.
if (validateCityBuildingPlacement(serverZone, msg, origin, playerCharacter, buildingList) == false)
return false;
// Loop through all buildings in this city counting barracks .
int barracksCount = 0;
cityObject = City.getCity(serverZone.getPlayerCityUUID());
// Cannot place barracks in abandoned city.
if (cityObject.getTOL().getOwnerUUID() == 0) {
PlaceAssetMsg.sendPlaceAssetError(origin, 42, ""); //Tree cannot support anymore shrines
return false;
}
for (Building building : serverZone.zoneBuildingSet) {
if (building.getBlueprint().getBuildingGroup() == BuildingGroup.BARRACK)
barracksCount++;
}
// Too many shrines for this tree's rank?
if (barracksCount >= cityObject.getTOL().getRank()) {
PlaceAssetMsg.sendPlaceAssetError(origin, 47, ""); //Tree cannot support anymore shrines
return false;
}
// Create the shrine
return createBarracks((PlayerCharacter) cityObject.getTOL().getOwner(), msg.getFirstPlacementInfo(), serverZone);
}
private boolean placeCityWalls(PlayerCharacter player, ClientConnection origin, PlaceAssetMsg msg) {
// Member variables
Zone serverZone;
City cityObject;
int placementCost = 0;
CharacterItemManager itemMan;
Item goldItem;
Building wallPiece;
// Setup working variables we'll need
serverZone = ZoneManager.findSmallestZone(player.getLoc());
// Early exit if something went horribly wrong
if (serverZone == null)
return false;
if (player.getCharItemManager().getGoldTrading() > 0) {
ErrorPopupMsg.sendErrorPopup(player, 195);
return false;
}
// Method checks validation conditions arising when placing
// buildings. Player must be on a city grid, must be
// inner council of the city's guild, etc.
if (validateCityBuildingPlacement(serverZone, msg, origin, player, msg.getFirstPlacementInfo()) == false)
return false;
cityObject = City.getCity(serverZone.getPlayerCityUUID());
// We need to be able to access how much gold a character is carrying
itemMan = player.getCharItemManager();
if (itemMan == null)
return false;
goldItem = itemMan.getGoldInventory();
// Grab list of walls we're placing
ArrayList<PlacementInfo> walls = msg.getPlacementInfo();
// Character must be able to afford walls
for (PlacementInfo wall : walls) {
placementCost += PlaceAssetMsg.getWallCost(wall.getBlueprintUUID());
}
// Early exit if not enough gold in character's inventory to place walls
if (placementCost > goldItem.getNumOfItems()) {
PlaceAssetMsg.sendPlaceAssetError(origin, 28, ""); // Not enough gold
return false;
}
placementCost = 0; // reset placement cost for fix bug with wall pieces somethings not taking gold out if forced an error.
// Overlap check and wall deed verifications
for (PlacementInfo wall : walls) {
if (Blueprint.isMeshWallPiece(wall.getBlueprintUUID()) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 48, ""); //"Assets (except walls) must be placed one at a time"
continue;
}
// Ignore wall pieces not on the city grid
if (cityObject.isLocationOnCityGrid(wall.getLoc()) == false) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "Asset " + cityObject.getName() + " not on citygrid");
continue;
}
// Does this wall collide with any other building?
for (Building building : serverZone.zoneBuildingSet) {
//TODO Clean up collision with placementInfo. don't need to create the same placementinfo bounds for collision checks on each building.
if ((building.getBlueprintUUID() != 0) && (Bounds.collide(wall, building) == true)) {
if (building.getRank() == -1) {
building.removeFromCache();
WorldGrid.RemoveWorldObject(building);
WorldGrid.removeObject(building);
building.getParentZone().getParent().zoneBuildingSet.remove(building);
if (building.getBlueprint() != null && building.getBlueprint().getBuildingGroup().equals(BuildingGroup.BARRACK)) {
building.RemoveFromBarracksList();
}
continue;
}
// remove gold from walls already placed before returning.
PlaceAssetMsg.sendPlaceAssetError(origin, 3, building.getName()); //"Conflict between assets"
return false;
}
}
placementCost = PlaceAssetMsg.getWallCost(wall.getBlueprintUUID());
if (!itemMan.modifyInventoryGold(-placementCost)) {
ChatManager.chatSystemInfo(player, player.getFirstName() + " can't has free moneys! no for real.. Thor.. seriously... I didnt fix it because you getting laid isnt important enough for me.");
return false;
}
// Attempt to place wall piece
wallPiece = createStructure(player, wall, serverZone);
if (wallPiece == null) {
PlaceAssetMsg.sendPlaceAssetError(origin, 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
continue;
}
// walls are auto protected
wallPiece.setProtectionState(ProtectionState.PROTECTED);
PlaceAssetMsg.sendPlaceAssetConfirmWall(origin, serverZone);
}
// Deduct gold from character's inventory
return true;
}
private Building createStructure(PlayerCharacter playerCharacter, PlacementInfo buildingInfo, Zone currentZone) {
Blueprint blueprint;
Building newMesh;
DateTime completionDate;
float vendorRotation;
float buildingRotation;
blueprint = Blueprint.getBlueprint(buildingInfo.getBlueprintUUID());
if (blueprint == null) {
Logger.error("CreateStructure: DB returned null blueprint.");
return null;
}
// All siege buildings build in 15 minutes
if ((blueprint.getBuildingGroup().equals(BuildingGroup.SIEGETENT))
|| (blueprint.getBuildingGroup().equals(BuildingGroup.BULWARK)))
completionDate = DateTime.now().plusMinutes(15);
else
completionDate = DateTime.now().plusHours(blueprint.getRankTime(1));
Vector3fImmutable localLoc = new Vector3fImmutable(ZoneManager.worldToLocal(buildingInfo.getLoc(), currentZone));
buildingRotation = buildingInfo.getRot().y;
vendorRotation = buildingInfo.getW();
// if W return is negative, this is a -90 rotation not a 90?
newMesh = DbManager.BuildingQueries.CREATE_BUILDING(
currentZone.getObjectUUID(), playerCharacter.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.NONE, 0, 0,
completionDate, blueprint.getMeshForRank(0), vendorRotation, buildingRotation);
// Make sure we have a valid mesh
if (newMesh == null) {
Logger.error("CreateStructure: DB returned null object.");
return null;
}
newMesh.setObjectTypeMask(MBServerStatics.MASK_BUILDING);
MaintenanceManager.setMaintDateTime(newMesh, LocalDateTime.now().plusDays(7));
// WorldGrid.addObject(newMesh, playerCharacter);
newMesh.setLoc(newMesh.getLoc());
InterestManager.setObjectDirty(newMesh);
return newMesh;
}
// Validates that player is able to place buildings
private boolean createShrine(PlayerCharacter player, PlacementInfo buildingInfo, Zone currentZone) {
Blueprint blueprint;
Building newMesh;
Shrine newShrine;
City city;
ShrineType shrineType;
if (player == null)
return false;
blueprint = Blueprint.getBlueprint(buildingInfo.getBlueprintUUID());
if (blueprint == null) {
Logger.error("CreateShrine: DB returned null blueprint.");
return false;
}
shrineType = Shrine.getShrineTypeByBlueprintUUID(blueprint.getBlueprintUUID());
city = City.getCity(currentZone.getPlayerCityUUID());
if (city == null)
return false;
if (!city.isLocationOnCityGrid(buildingInfo.getLoc()))
return false;
Vector3fImmutable localLoc = new Vector3fImmutable(ZoneManager.worldToLocal(buildingInfo.getLoc(), currentZone));
float buildingRotation = buildingInfo.getRot().y;
float vendorRotation = buildingInfo.getW();
ArrayList<AbstractGameObject> shrineObjects = DbManager.ShrineQueries.CREATE_SHRINE(
currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.PROTECTED, 0, 0,
DateTime.now().plusHours(blueprint.getRankTime(1)), blueprint.getMeshForRank(0), vendorRotation, buildingRotation, shrineType.name());
if (shrineObjects == null) {
PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
return false;
}
for (AbstractGameObject ago : shrineObjects) {
switch (ago.getObjectType()) {
case Building:
newMesh = (Building) ago;
newMesh.runAfterLoad();
newMesh.setObjectTypeMask(MBServerStatics.MASK_BUILDING);
MaintenanceManager.setMaintDateTime(newMesh, LocalDateTime.now().plusDays(7));
newMesh.setLoc(newMesh.getLoc());
InterestManager.setObjectDirty(newMesh);
break;
case Shrine:
newShrine = (Shrine) ago;
newShrine.getShrineType().addShrineToServerList(newShrine);
break;
default:
PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
break;
}
}
return true;
}
private boolean createBarracks(PlayerCharacter player, PlacementInfo buildingInfo, Zone currentZone) {
Blueprint blueprint;
Building newMesh;
Shrine newShrine;
City city;
if (player == null)
return false;
blueprint = Blueprint.getBlueprint(buildingInfo.getBlueprintUUID());
if (blueprint == null) {
Logger.error("CreateShrine: DB returned null blueprint.");
return false;
}
city = City.getCity(currentZone.getPlayerCityUUID());
if (city == null)
return false;
if (!city.isLocationOnCityGrid(buildingInfo.getLoc()))
return false;
Vector3fImmutable localLoc = new Vector3fImmutable(ZoneManager.worldToLocal(buildingInfo.getLoc(), currentZone));
float buildingRotation = buildingInfo.getRot().y;
float vendorRotation = buildingInfo.getW();
DateTime completionDate = DateTime.now().plusHours(blueprint.getRankTime(1));
newMesh = DbManager.BuildingQueries.CREATE_BUILDING(
currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.PROTECTED, 0, 0,
completionDate, blueprint.getMeshForRank(0), vendorRotation, buildingRotation);
// Make sure we have a valid mesh
if (newMesh == null) {
Logger.error("CreateStructure: DB returned null object.");
return false;
}
newMesh.setObjectTypeMask(MBServerStatics.MASK_BUILDING);
MaintenanceManager.setMaintDateTime(newMesh, LocalDateTime.now().plusDays(7));
newMesh.setLoc(newMesh.getLoc());
InterestManager.setObjectDirty(newMesh);
return true;
}
private boolean createWarehouse(PlayerCharacter player, PlacementInfo buildingInfo, Zone currentZone) {
Blueprint blueprint;
Building newMesh = null;
ArrayList<AbstractGameObject> warehouseObjects;
blueprint = Blueprint.getBlueprint(buildingInfo.getBlueprintUUID());
if (blueprint == null) {
Logger.error("CreateWarehouse: DB returned null blueprint.");
return false;
}
Vector3fImmutable localLoc = new Vector3fImmutable(ZoneManager.worldToLocal(buildingInfo.getLoc(), currentZone));
float buildingRotation = buildingInfo.getRot().y;
float vendorRotation = buildingInfo.getW();
warehouseObjects = DbManager.WarehouseQueries.CREATE_WAREHOUSE(
currentZone.getObjectUUID(), player.getObjectUUID(), blueprint.getName(), blueprint.getMeshForRank(0),
localLoc, 1.0f, blueprint.getMaxHealth(0), ProtectionState.NONE, 0, 0,
DateTime.now().plusHours(blueprint.getRankTime(1)), blueprint.getMeshForRank(0), vendorRotation, buildingRotation);
if (warehouseObjects == null) {
PlaceAssetMsg.sendPlaceAssetError(player.getClientConnection(), 1, "A Serious error has occurred. Please post details for to ensure transaction integrity");
return false;
}
// Load the building into the simulation
for (AbstractGameObject ago : warehouseObjects) {
if (ago.getObjectType() == GameObjectType.Building) {
newMesh = (Building) ago;
newMesh.setObjectTypeMask(MBServerStatics.MASK_BUILDING);
MaintenanceManager.setMaintDateTime(newMesh, LocalDateTime.now().plusDays(7));
// WorldGrid.addObject(newMesh, player);
newMesh.setLoc(newMesh.getLoc());
InterestManager.setObjectDirty(newMesh);
newMesh.runAfterLoad();
} else if (ago.getObjectType() == GameObjectType.Warehouse) {
Warehouse warehouse = (Warehouse) ago;
City city = City.getCity(currentZone.getPlayerCityUUID());
if (city == null)
return true;
city.setWarehouseBuildingID(newMesh.getObjectUUID());
Warehouse.warehouseByBuildingUUID.put(newMesh.getObjectUUID(), warehouse);
}
}
return true;
}
}