Initial Repository Push
This commit is contained in:
@@ -0,0 +1,636 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.Enum.BuildingGroup;
|
||||
import engine.Enum.GameObjectType;
|
||||
import engine.InterestManagement.WorldGrid;
|
||||
import engine.job.JobContainer;
|
||||
import engine.job.JobScheduler;
|
||||
import engine.jobs.UpgradeBuildingJob;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.net.client.msg.ErrorPopupMsg;
|
||||
import engine.objects.*;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public enum BuildingManager {
|
||||
|
||||
BUILDINGMANAGER;
|
||||
|
||||
public static boolean playerCanManage(PlayerCharacter player, Building building) {
|
||||
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
if (building == null)
|
||||
return false;
|
||||
|
||||
|
||||
if (building.getRank() == -1)
|
||||
return false;
|
||||
|
||||
if (IsOwner(building, player))
|
||||
return true;
|
||||
|
||||
//individual friend.
|
||||
if (building.getFriends().get(player.getObjectUUID()) != null)
|
||||
return true;
|
||||
|
||||
//Admin's can access stuff
|
||||
|
||||
if (player.isCSR())
|
||||
return true;
|
||||
|
||||
//Guild stuff
|
||||
|
||||
|
||||
if (building.getGuild() != null && building.getGuild().isGuildLeader(player.getObjectUUID()))
|
||||
return true;
|
||||
|
||||
if (building.getFriends().get(player.getGuild().getObjectUUID()) != null
|
||||
&& building.getFriends().get(player.getGuild().getObjectUUID()).getFriendType() == 8)
|
||||
return true;
|
||||
|
||||
if (building.getFriends().get(player.getGuild().getObjectUUID()) != null
|
||||
&& building.getFriends().get(player.getGuild().getObjectUUID()).getFriendType() == 9
|
||||
&& GuildStatusController.isInnerCouncil(player.getGuildStatus()))
|
||||
return true;
|
||||
|
||||
if (Guild.sameGuild(building.getGuild(), player.getGuild()) && GuildStatusController.isInnerCouncil(player.getGuildStatus()))
|
||||
return true;
|
||||
|
||||
if (Guild.sameGuild(building.getGuild(), player.getGuild()) && GuildStatusController.isGuildLeader(player.getGuildStatus()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
//TODO test friends list once added
|
||||
//does not meet above criteria. Cannot access.
|
||||
}
|
||||
|
||||
public static boolean playerCanManageNotFriends(PlayerCharacter player, Building building) {
|
||||
|
||||
//Player Can only Control Building if player is in Same Guild as Building and is higher rank than IC.
|
||||
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
if (building == null)
|
||||
return false;
|
||||
|
||||
|
||||
if (building.getRank() == -1)
|
||||
return false;
|
||||
|
||||
if (IsOwner(building, player))
|
||||
return true;
|
||||
|
||||
//Somehow guild leader check fails? lets check if Player is true Guild GL.
|
||||
if (building.getGuild() != null && building.getGuild().isGuildLeader(player.getObjectUUID()))
|
||||
return true;
|
||||
if (GuildStatusController.isGuildLeader(player.getGuildStatus()) == false && GuildStatusController.isInnerCouncil(player.getGuildStatus()) == false)
|
||||
return false;
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public static synchronized boolean lootBuilding(PlayerCharacter player, Building building) {
|
||||
|
||||
if (building == null)
|
||||
return false;
|
||||
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
if (building.getRank() != -1)
|
||||
return false;
|
||||
|
||||
if (building.getBlueprintUUID() == 0)
|
||||
return false;
|
||||
|
||||
switch (building.getBlueprint().getBuildingGroup()) {
|
||||
case SHRINE:
|
||||
Shrine shrine = Shrine.shrinesByBuildingUUID.get(building.getObjectUUID());
|
||||
if (shrine == null)
|
||||
return false;
|
||||
|
||||
int amount = shrine.getFavors();
|
||||
//no more favors too loot!
|
||||
if (amount == 0) {
|
||||
|
||||
try {
|
||||
ErrorPopupMsg.sendErrorPopup(player, 166);
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemBase elanIB = ItemBase.getItemBase(1705032);
|
||||
|
||||
if (elanIB == null)
|
||||
return false;
|
||||
|
||||
if (!player.getCharItemManager().hasRoomInventory(elanIB.getWeight()))
|
||||
return false;
|
||||
|
||||
if (!Item.MakeItemForPlayer(elanIB, player, amount))
|
||||
return false;
|
||||
|
||||
shrine.setFavors(0);
|
||||
break;
|
||||
case WAREHOUSE:
|
||||
|
||||
Warehouse warehouse = Warehouse.warehouseByBuildingUUID.get(building.getObjectUUID());
|
||||
|
||||
if (warehouse == null)
|
||||
return false;
|
||||
|
||||
for (ItemBase resourceBase : ItemBase.getResourceList()) {
|
||||
if (!player.getCharItemManager().hasRoomInventory(resourceBase.getWeight())) {
|
||||
ChatManager.chatSystemInfo(player, "You can not carry any more of that item.");
|
||||
return false;
|
||||
}
|
||||
if (warehouse.getResources().get(resourceBase) == null)
|
||||
continue;
|
||||
|
||||
int resourceAmount = warehouse.getResources().get(resourceBase);
|
||||
|
||||
if (resourceAmount <= 0)
|
||||
continue;
|
||||
|
||||
if (warehouse.loot(player, resourceBase, resourceAmount, true))
|
||||
ChatManager.chatInfoInfo(player, "You have looted " + resourceAmount + ' ' + resourceBase.getName());
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
//Everything was looted, Maybe we should
|
||||
return true;
|
||||
}
|
||||
|
||||
//This method restarts an upgrade timer when a building is loaded from the database.
|
||||
// Submit upgrade job for this building based upon it's current upgradeDateTime
|
||||
|
||||
public static void submitUpgradeJob(Building building) {
|
||||
|
||||
if (building == null)
|
||||
return;
|
||||
|
||||
|
||||
if (building.getUpgradeDateTime() == null) {
|
||||
Logger.error("Attempt to submit upgrade job for non-ranking building");
|
||||
return;
|
||||
}
|
||||
|
||||
// Submit upgrade job for future date or current instant
|
||||
|
||||
if (building.getUpgradeDateTime().isAfter(LocalDateTime.now())) {
|
||||
JobContainer jc = JobScheduler.getInstance().scheduleJob(new UpgradeBuildingJob(building),
|
||||
building.getUpgradeDateTime().atZone(ZoneId.systemDefault())
|
||||
.toInstant().toEpochMilli());
|
||||
} else
|
||||
JobScheduler.getInstance().scheduleJob(new UpgradeBuildingJob(building), 0);
|
||||
}
|
||||
|
||||
public static void setUpgradeDateTime(Building building, LocalDateTime upgradeDateTime, int rankCost) {
|
||||
|
||||
if (building == null)
|
||||
return;
|
||||
if (!DbManager.BuildingQueries.updateBuildingUpgradeTime(upgradeDateTime, building, rankCost)) {
|
||||
Logger.error("Failed to set upgradeTime for building " + building.getObjectUUID());
|
||||
return;
|
||||
}
|
||||
|
||||
building.upgradeDateTime = upgradeDateTime;
|
||||
|
||||
}
|
||||
|
||||
// Method transfers ownership of all hirelings in a building
|
||||
|
||||
public static void refreshHirelings(Building building) {
|
||||
|
||||
if (building == null)
|
||||
return;
|
||||
|
||||
Guild newGuild;
|
||||
|
||||
if (building.getOwner() == null)
|
||||
newGuild = Guild.getErrantGuild();
|
||||
else
|
||||
newGuild = building.getOwner().getGuild();
|
||||
|
||||
for (AbstractCharacter hireling : building.getHirelings().keySet()) {
|
||||
hireling.setGuild(newGuild);
|
||||
WorldGrid.updateObject(hireling);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void cleanupHirelings(Building building) {
|
||||
|
||||
// Early exit: Cannot have hirelings in a building
|
||||
// without a blueprint.
|
||||
|
||||
if (building.getBlueprintUUID() == 0)
|
||||
return;
|
||||
|
||||
// Remove all hirelings for destroyed buildings
|
||||
|
||||
if (building.getRank() < 1) {
|
||||
|
||||
for (AbstractCharacter slottedNPC : building.getHirelings().keySet()) {
|
||||
|
||||
if (slottedNPC.getObjectType() == Enum.GameObjectType.NPC)
|
||||
((NPC) slottedNPC).remove();
|
||||
else if (slottedNPC.getObjectType() == Enum.GameObjectType.Mob)
|
||||
((Mob) slottedNPC).remove(building);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete hireling if building has deranked.
|
||||
for (AbstractCharacter hireling : building.getHirelings().keySet()) {
|
||||
|
||||
NPC npc = null;
|
||||
Mob mob = null;
|
||||
|
||||
if (hireling.getObjectType() == Enum.GameObjectType.NPC)
|
||||
npc = (NPC) hireling;
|
||||
else if (hireling.getObjectType() == Enum.GameObjectType.Mob)
|
||||
mob = (Mob) hireling;
|
||||
|
||||
if (building.getHirelings().get(hireling) > building.getBlueprint().getSlotsForRank(building.getRank()))
|
||||
|
||||
if (npc != null) {
|
||||
if (!npc.remove())
|
||||
Logger.error("Failed to remove npc " + npc.getObjectUUID()
|
||||
+ "from Building " + building.getObjectUUID());
|
||||
else
|
||||
building.getHirelings().remove(npc);
|
||||
} else if (mob != null) {
|
||||
if (!mob.remove(building))
|
||||
Logger.error("Failed to remove npc " + npc.getObjectUUID()
|
||||
+ "from Building " + building.getObjectUUID());
|
||||
else
|
||||
building.getHirelings().remove(npc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
refreshHirelings(building);
|
||||
}
|
||||
|
||||
public static Building getBuilding(int id) {
|
||||
|
||||
if (id == 0)
|
||||
return null;
|
||||
|
||||
Building building;
|
||||
|
||||
building = (Building) DbManager.getFromCache(Enum.GameObjectType.Building, id);
|
||||
|
||||
if (building != null)
|
||||
return building;
|
||||
|
||||
return DbManager.BuildingQueries.GET_BUILDINGBYUUID(id);
|
||||
|
||||
}
|
||||
|
||||
public static boolean PlayerCanControlNotOwner(Building building, PlayerCharacter player) {
|
||||
|
||||
if (player == null)
|
||||
return false;
|
||||
|
||||
if (building == null)
|
||||
return false;
|
||||
|
||||
if (building.getOwner() == null)
|
||||
return false;
|
||||
|
||||
//lets pass true if player is owner anyway.
|
||||
if (building.getOwner().equals(player))
|
||||
return true;
|
||||
|
||||
if (player.getGuild().isErrant())
|
||||
return false;
|
||||
|
||||
if (building.getGuild().isGuildLeader(player.getObjectUUID()))
|
||||
return true;
|
||||
|
||||
if (!Guild.sameGuild(building.getGuild(), player.getGuild()))
|
||||
return false;
|
||||
|
||||
return GuildStatusController.isGuildLeader(player.getGuildStatus()) != false || GuildStatusController.isInnerCouncil(player.getGuildStatus()) != false;
|
||||
}
|
||||
|
||||
//This is mainly used for Rolling and gold sharing between building and warehouse.
|
||||
|
||||
public static int GetWithdrawAmountForRolling(Building building, int cost) {
|
||||
|
||||
//all funds are available to roll.
|
||||
|
||||
if (cost <= GetAvailableGold(building))
|
||||
return cost;
|
||||
|
||||
// cost is more than available gold, return available gold
|
||||
|
||||
return GetAvailableGold(building);
|
||||
|
||||
}
|
||||
|
||||
public static int GetAvailableGold(Building building) {
|
||||
|
||||
if (building.getStrongboxValue() == 0)
|
||||
return 0;
|
||||
|
||||
if (building.getStrongboxValue() < building.reserve)
|
||||
return 0;
|
||||
|
||||
return building.getStrongboxValue() - building.reserve;
|
||||
}
|
||||
|
||||
public static int GetOverdraft(Building building, int cost) {
|
||||
int availableGold = GetWithdrawAmountForRolling(building, cost);
|
||||
return cost - availableGold;
|
||||
}
|
||||
|
||||
public static boolean IsPlayerHostile(Building building, PlayerCharacter player) {
|
||||
|
||||
//Nation Members and Guild members are not hostile.
|
||||
// if (building.getGuild() != null){
|
||||
// if (pc.getGuild() != null)
|
||||
// if (building.getGuild().getObjectUUID() == pc.getGuildUUID()
|
||||
// || pc.getGuild().getNation().getObjectUUID() == building.getGuild().getNation().getObjectUUID())
|
||||
// return false;
|
||||
// }
|
||||
if (Guild.sameNationExcludeErrant(building.getGuild(), player.getGuild()))
|
||||
return false;
|
||||
|
||||
if (!building.reverseKOS) {
|
||||
|
||||
Condemned condemn = building.getCondemned().get(player.getObjectUUID());
|
||||
|
||||
if (condemn != null && condemn.isActive())
|
||||
return true;
|
||||
|
||||
if (player.getGuild() != null) {
|
||||
|
||||
Condemned guildCondemn = building.getCondemned().get(player.getGuild().getObjectUUID());
|
||||
|
||||
if (guildCondemn != null && guildCondemn.isActive())
|
||||
return true;
|
||||
|
||||
Condemned nationCondemn = building.getCondemned().get(player.getGuild().getNation().getObjectUUID());
|
||||
return nationCondemn != null && nationCondemn.isActive() && nationCondemn.getFriendType() == Condemned.NATION;
|
||||
} else {
|
||||
//TODO ADD ERRANT KOS CHECK
|
||||
}
|
||||
} else {
|
||||
|
||||
Condemned condemn = building.getCondemned().get(player.getObjectUUID());
|
||||
|
||||
if (condemn != null && condemn.isActive())
|
||||
return false;
|
||||
|
||||
if (player.getGuild() != null) {
|
||||
|
||||
Condemned guildCondemn = building.getCondemned().get(player.getGuild().getObjectUUID());
|
||||
|
||||
if (guildCondemn != null && guildCondemn.isActive())
|
||||
return false;
|
||||
|
||||
Condemned nationCondemn = building.getCondemned().get(player.getGuild().getNation().getObjectUUID());
|
||||
return nationCondemn == null || !nationCondemn.isActive() || nationCondemn.getFriendType() != Condemned.NATION;
|
||||
} else {
|
||||
//TODO ADD ERRANT KOS CHECK
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//When we get to here, This means The building was not reverse KOS
|
||||
//and passed the hostile test.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final synchronized boolean addHirelingForWorld(Building building, PlayerCharacter contractOwner, Vector3fImmutable NpcLoc, Zone zone, Contract NpcID, int rank) {
|
||||
|
||||
String pirateName = NPC.getPirateName(NpcID.getMobbaseID());
|
||||
|
||||
NPC npc = null;
|
||||
|
||||
npc = NPC.createNPC( pirateName, NpcID.getObjectUUID(), NpcLoc, null, false, zone, (short) rank, false, building);
|
||||
|
||||
if (npc == null)
|
||||
return false;
|
||||
|
||||
|
||||
npc.setBuilding(building);
|
||||
npc.setParentZone(zone);
|
||||
WorldGrid.addObject(npc, contractOwner);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public static synchronized boolean addHireling(Building building, PlayerCharacter contractOwner, Vector3fImmutable NpcLoc, Zone zone, Contract NpcID, Item item) {
|
||||
|
||||
int rank = 1;
|
||||
|
||||
if (building.getBlueprintUUID() == 0)
|
||||
return false;
|
||||
|
||||
if (building.getBlueprint().getMaxSlots() == building.getHirelings().size())
|
||||
return false;
|
||||
|
||||
String pirateName = NPC.getPirateName(NpcID.getMobbaseID());
|
||||
|
||||
if (item.getChargesRemaining() > 0)
|
||||
rank = item.getChargesRemaining() * 10;
|
||||
else rank = 10;
|
||||
|
||||
Mob mob = null;
|
||||
NPC npc = null;
|
||||
|
||||
if (NPC.ISGuardCaptain(NpcID.getContractID())) {
|
||||
|
||||
mob = Mob.createMob( NpcID.getMobbaseID(), NpcLoc, contractOwner.getGuild(), true, zone, building, NpcID.getContractID());
|
||||
|
||||
if (mob == null)
|
||||
return false;
|
||||
|
||||
mob.setRank(rank);
|
||||
mob.setPlayerGuard(true);
|
||||
mob.setParentZone(zone);
|
||||
return true;
|
||||
} else {
|
||||
npc = NPC.createNPC( pirateName, NpcID.getObjectUUID(), NpcLoc, contractOwner.getGuild(), false, zone, (short) rank, false, building);
|
||||
|
||||
if (npc == null)
|
||||
return false;
|
||||
|
||||
|
||||
npc.setBindLoc(NpcLoc.x - zone.getAbsX(), NpcLoc.y - zone.getAbsY(), NpcLoc.z - zone.getAbsZ());
|
||||
|
||||
npc.setBuilding(building);
|
||||
npc.setParentZone(zone);
|
||||
|
||||
if (NPC.GetNPCProfits(npc) == null)
|
||||
NPCProfits.CreateProfits(npc);
|
||||
|
||||
WorldGrid.addObject(npc, contractOwner);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean IsWallPiece(Building building) {
|
||||
|
||||
if (building.getBlueprint() == null)
|
||||
return false;
|
||||
|
||||
BuildingGroup buildingGroup = building.getBlueprint().getBuildingGroup();
|
||||
|
||||
switch (buildingGroup) {
|
||||
case WALLSTRAIGHT:
|
||||
case WALLCORNER:
|
||||
case SMALLGATE:
|
||||
case ARTYTOWER:
|
||||
case WALLSTRAIGHTTOWER:
|
||||
case WALLSTAIRS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Building getBuildingFromCache(int id) {
|
||||
return (Building) DbManager.getFromCache(GameObjectType.Building, id);
|
||||
}
|
||||
|
||||
public static boolean IsOwner(Building building, PlayerCharacter player) {
|
||||
if (building == null || player == null)
|
||||
return false;
|
||||
|
||||
if (building.getOwner() == null)
|
||||
return false;
|
||||
|
||||
|
||||
return building.getOwner().getObjectUUID() == player.getObjectUUID();
|
||||
|
||||
}
|
||||
|
||||
public static float GetMissingHealth(Building building) {
|
||||
return building.healthMax - building.getCurrentHitpoints();
|
||||
}
|
||||
|
||||
public static int GetRepairCost(Building building) {
|
||||
return (int) (GetMissingHealth(building) * .10f);
|
||||
}
|
||||
|
||||
public static Regions GetRegion(Building building, float x, float y, float z) {
|
||||
if (building.getBounds() == null)
|
||||
return null;
|
||||
|
||||
if (building.getBounds().getRegions() == null)
|
||||
return null;
|
||||
|
||||
Regions currentRegion = null;
|
||||
for (Regions region : building.getBounds().getRegions()) {
|
||||
|
||||
if (region.isPointInPolygon(new Vector3fImmutable(x, y, z))) {
|
||||
if (y > (region.highLerp.y - 5))
|
||||
currentRegion = region;
|
||||
}
|
||||
}
|
||||
return currentRegion;
|
||||
}
|
||||
|
||||
public static Regions GetRegion(Building building, int room, int level, float x, float z) {
|
||||
if (building.getBounds() == null)
|
||||
return null;
|
||||
|
||||
if (building.getBounds().getRegions() == null)
|
||||
return null;
|
||||
|
||||
for (Regions region : building.getBounds().getRegions()) {
|
||||
|
||||
if (region.getLevel() != level)
|
||||
continue;
|
||||
if (region.getRoom() != room)
|
||||
continue;
|
||||
|
||||
if (region.isPointInPolygon(new Vector3fImmutable(x, 0, z))) {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Vector3fImmutable GetBindLocationForBuilding(Building building){
|
||||
|
||||
Vector3fImmutable bindLoc = null;
|
||||
|
||||
if (building == null)
|
||||
return Enum.Ruins.getRandomRuin().getLocation();
|
||||
|
||||
|
||||
bindLoc = building.getLoc();
|
||||
|
||||
|
||||
float radius = Bounds.meshBoundsCache.get(building.getMeshUUID()).radius;
|
||||
if ( building.getRank() == 8){
|
||||
bindLoc = building.getStuckLocation();
|
||||
if (bindLoc != null)
|
||||
return bindLoc;
|
||||
}
|
||||
|
||||
float x = bindLoc.getX();
|
||||
float z = bindLoc.getZ();
|
||||
float offset = ((ThreadLocalRandom.current().nextFloat() * 2) - 1) * radius;
|
||||
int direction = ThreadLocalRandom.current().nextInt(4);
|
||||
|
||||
switch (direction) {
|
||||
case 0:
|
||||
x += radius;
|
||||
z += offset;
|
||||
break;
|
||||
case 1:
|
||||
x += offset;
|
||||
z -= radius;
|
||||
break;
|
||||
case 2:
|
||||
x -= radius;
|
||||
z += offset;
|
||||
break;
|
||||
case 3:
|
||||
x += offset;
|
||||
z += radius;
|
||||
break;
|
||||
}
|
||||
bindLoc = new Vector3fImmutable(x, bindLoc.getY(), z);
|
||||
|
||||
return bindLoc;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,113 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
/* This enumeration implements Magicbane's configuration data which
|
||||
is loaded from environment variables.
|
||||
*/
|
||||
|
||||
import engine.Enum;
|
||||
import engine.net.NetMsgHandler;
|
||||
import engine.server.login.LoginServer;
|
||||
import engine.server.world.WorldServer;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum ConfigManager {
|
||||
|
||||
// Bind address can differ from public address
|
||||
// when running over a network bridge, etc.
|
||||
|
||||
MB_PUBLIC_ADDR,
|
||||
MB_BIND_ADDR,
|
||||
|
||||
// Database connection config
|
||||
|
||||
MB_DATABASE_ADDRESS,
|
||||
MB_DATABASE_PORT,
|
||||
MB_DATABASE_NAME,
|
||||
MB_DATABASE_USER,
|
||||
MB_DATABASE_PASS,
|
||||
|
||||
// Data warehouse remote connection
|
||||
|
||||
MB_WAREHOUSE_ADDR,
|
||||
MB_WAREHOUSE_USER,
|
||||
MB_WAREHOUSE_PASS,
|
||||
|
||||
// Login server config
|
||||
|
||||
MB_LOGIN_PORT,
|
||||
MB_MAJOR_VER,
|
||||
MB_MINOR_VER,
|
||||
|
||||
// Worldserver configuration
|
||||
|
||||
MB_WORLD_NAME,
|
||||
MB_WORLD_MAPID,
|
||||
MB_WORLD_PORT,
|
||||
MB_WORLD_ACCESS_LVL,
|
||||
MB_WORLD_UUID,
|
||||
MB_WORLD_WAREHOUSE_PUSH,
|
||||
MB_WORLD_MAINTENANCE,
|
||||
MB_WORLD_MAINTENANCE_HOUR,
|
||||
MB_WORLD_GREETING,
|
||||
MB_WORLD_KEYCLONE_MAX,
|
||||
|
||||
// MagicBot configuration.
|
||||
|
||||
MB_MAGICBOT_SERVERID,
|
||||
MB_MAGICBOT_BOTTOKEN,
|
||||
MB_MAGICBOT_ROLEID,
|
||||
MB_MAGICBOT_ANNOUNCE,
|
||||
MB_MAGICBOT_SEPTIC,
|
||||
MB_MAGICBOT_CHANGELOG,
|
||||
MB_MAGICBOT_POLITICAL,
|
||||
MB_MAGICBOT_GENERAL,
|
||||
MB_MAGICBOT_FORTOFIX,
|
||||
MB_MAGICBOT_RECRUIT,
|
||||
MB_MAGICBOT_BOTVERSION,
|
||||
MB_MAGICBOT_GAMEVERSION;
|
||||
|
||||
// Map to hold our config pulled in from the environment
|
||||
// We also use the config to point to the current message pump
|
||||
// and determine the server type at runtime.
|
||||
|
||||
public static Map<String, String> configMap = new HashMap(System.getenv());
|
||||
public static Enum.ServerType serverType = Enum.ServerType.NONE;
|
||||
public static NetMsgHandler handler;
|
||||
public static WorldServer worldServer;
|
||||
public static LoginServer loginServer;
|
||||
|
||||
// Called at bootstrap: ensures that all config values are loaded.
|
||||
|
||||
public static boolean init() {
|
||||
|
||||
Logger.info("ConfigManager: init()");
|
||||
|
||||
for (ConfigManager configSetting : ConfigManager.values())
|
||||
if (configMap.containsKey(configSetting.name()))
|
||||
Logger.info(configSetting.name() + ":" + configSetting.getValue());
|
||||
else {
|
||||
Logger.error("Missing Config: " + configSetting.name());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the value associated with this enumeration
|
||||
|
||||
public String getValue() {
|
||||
return configMap.get(this.name());
|
||||
}
|
||||
public void setValue(String value) { configMap.put(this.name(), value); }
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.Enum.GameObjectType;
|
||||
import engine.db.handlers.*;
|
||||
import engine.objects.*;
|
||||
import engine.pooling.ConnectionPool;
|
||||
import engine.server.MBServerStatics;
|
||||
import engine.util.Hasher;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.EnumMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public enum DbManager {
|
||||
DBMANAGER;
|
||||
|
||||
private static ConnectionPool connPool;
|
||||
public static Hasher hasher;
|
||||
|
||||
//Local Object Caching
|
||||
|
||||
private static final EnumMap<GameObjectType, ConcurrentHashMap<Integer, AbstractGameObject>> objectCache = new EnumMap<>(GameObjectType.class);
|
||||
|
||||
public static boolean configureDatabaseLayer() {
|
||||
|
||||
boolean worked = true;
|
||||
|
||||
try {
|
||||
DbManager.connPool = new ConnectionPool();
|
||||
DbManager.connPool.fill(10);
|
||||
DBMANAGER.hasher = new Hasher();
|
||||
} catch (Exception e ) {
|
||||
e.printStackTrace();
|
||||
worked = false;
|
||||
}
|
||||
return worked;
|
||||
}
|
||||
|
||||
public static AbstractGameObject getObject(GameObjectType objectType, int objectUUID) {
|
||||
|
||||
AbstractGameObject outObject = null;
|
||||
|
||||
switch (objectType) {
|
||||
case PlayerCharacter:
|
||||
outObject = PlayerCharacter.getPlayerCharacter(objectUUID);
|
||||
break;
|
||||
case NPC:
|
||||
outObject = NPC.getNPC(objectUUID);
|
||||
break;
|
||||
case Mob:
|
||||
outObject = Mob.getFromCache(objectUUID);
|
||||
break;
|
||||
case Building:
|
||||
outObject = BuildingManager.getBuilding(objectUUID);
|
||||
break;
|
||||
case Guild:
|
||||
outObject = Guild.getGuild(objectUUID);
|
||||
break;
|
||||
case Item:
|
||||
outObject = Item.getFromCache(objectUUID);
|
||||
break;
|
||||
case MobLoot:
|
||||
outObject = MobLoot.getFromCache(objectUUID);
|
||||
break;
|
||||
case City:
|
||||
outObject = City.getCity(objectUUID);
|
||||
break;
|
||||
default:
|
||||
Logger.error("Attempt to retrieve nonexistant " + objectType +
|
||||
" from object cache." );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return outObject;
|
||||
}
|
||||
|
||||
public static int getPoolSize(){
|
||||
return connPool.getPoolSize();
|
||||
}
|
||||
|
||||
public static boolean inCache(GameObjectType gameObjectType, int uuid) {
|
||||
|
||||
if (objectCache.get(gameObjectType) == null)
|
||||
return false;
|
||||
|
||||
return (objectCache.get(gameObjectType).containsKey(uuid));
|
||||
|
||||
}
|
||||
|
||||
public static AbstractGameObject getFromCache(GameObjectType gameObjectType, int uuid) {
|
||||
|
||||
if (objectCache.get(gameObjectType) == null)
|
||||
return null;
|
||||
|
||||
return objectCache.get(gameObjectType).get(uuid);
|
||||
|
||||
}
|
||||
|
||||
public static void removeFromCache(GameObjectType gameObjectType, int uuid) {
|
||||
|
||||
AbstractGameObject abstractGameObject;
|
||||
|
||||
if (objectCache.get(gameObjectType) == null)
|
||||
return;
|
||||
|
||||
abstractGameObject = objectCache.get(gameObjectType).get(uuid);
|
||||
|
||||
if (abstractGameObject == null)
|
||||
return;
|
||||
|
||||
removeFromCache(abstractGameObject);
|
||||
|
||||
}
|
||||
|
||||
public static void removeFromCache(AbstractGameObject abstractGameObject) {
|
||||
|
||||
if (abstractGameObject == null)
|
||||
return;
|
||||
|
||||
if (objectCache.get(abstractGameObject.getObjectType()) == null)
|
||||
return;
|
||||
|
||||
// Remove object from game cache
|
||||
|
||||
objectCache.get(abstractGameObject.getObjectType()).remove(abstractGameObject.getObjectUUID());
|
||||
|
||||
// Release bounds as we're dispensing with this object.
|
||||
|
||||
if (abstractGameObject instanceof AbstractWorldObject) {
|
||||
AbstractWorldObject abstractWorldObject = (AbstractWorldObject)abstractGameObject;
|
||||
|
||||
if (abstractWorldObject.getBounds() != null) {
|
||||
abstractWorldObject.getBounds().release();
|
||||
abstractWorldObject.setBounds(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean addToCache(AbstractGameObject gameObject) {
|
||||
|
||||
boolean isWorldServer = ConfigManager.serverType.equals(Enum.ServerType.WORLDSERVER);
|
||||
|
||||
if (!isWorldServer) {
|
||||
if (MBServerStatics.SKIP_CACHE_LOGIN)
|
||||
return true;
|
||||
if (MBServerStatics.SKIP_CACHE_LOGIN_PLAYER
|
||||
&& (gameObject.getObjectType() == GameObjectType.PlayerCharacter))
|
||||
return true;
|
||||
if (MBServerStatics.SKIP_CACHE_LOGIN_ITEM &&
|
||||
(gameObject.getObjectType() == GameObjectType.Item))
|
||||
return true;
|
||||
}
|
||||
|
||||
// First time this object type has been cached. Create the hashmap.
|
||||
|
||||
if (objectCache.get(gameObject.getObjectType()) == null) {
|
||||
|
||||
int initialCapacity;
|
||||
|
||||
// Provide initial sizing hints
|
||||
|
||||
switch (gameObject.getObjectType()) {
|
||||
case Building:
|
||||
initialCapacity = 46900;
|
||||
break;
|
||||
case Mob:
|
||||
initialCapacity = 11700;
|
||||
break;
|
||||
case NPC:
|
||||
initialCapacity = 900;
|
||||
break;
|
||||
case Zone:
|
||||
initialCapacity = 1070;
|
||||
break;
|
||||
case Account:
|
||||
initialCapacity = 10000;
|
||||
break;
|
||||
case Guild:
|
||||
initialCapacity = 100;
|
||||
break;
|
||||
case ItemContainer:
|
||||
initialCapacity = 100;
|
||||
break;
|
||||
case Item:
|
||||
initialCapacity = 1000;
|
||||
break;
|
||||
case MobLoot:
|
||||
initialCapacity = 10000;
|
||||
break;
|
||||
case PlayerCharacter:
|
||||
initialCapacity = 100;
|
||||
break;
|
||||
default:
|
||||
initialCapacity = 100; // Lookup api default should be ok for small maps
|
||||
break;
|
||||
}
|
||||
objectCache.put(gameObject.getObjectType(), new ConcurrentHashMap<>(initialCapacity));
|
||||
}
|
||||
|
||||
// Add the object to the cache. This will overwrite the current map entry.
|
||||
|
||||
objectCache.get(gameObject.getObjectType()).put(gameObject.getObjectUUID(), gameObject);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static java.util.Collection<AbstractGameObject> getList(GameObjectType gameObjectType) {
|
||||
|
||||
if (objectCache.get(gameObjectType) == null)
|
||||
return null;
|
||||
|
||||
return objectCache.get(gameObjectType).values();
|
||||
}
|
||||
|
||||
public static PreparedStatement prepareStatement(String sql) throws SQLException {
|
||||
return getConn().prepareStatement(sql, 1);
|
||||
}
|
||||
|
||||
// Omg refactor this out, somebody!
|
||||
|
||||
public static ConcurrentHashMap<Integer, AbstractGameObject> getMap(
|
||||
GameObjectType gameObjectType) {
|
||||
|
||||
if (objectCache.get(gameObjectType) == null)
|
||||
return null;
|
||||
|
||||
return objectCache.get(gameObjectType);
|
||||
|
||||
}
|
||||
|
||||
public static void printCacheCount(PlayerCharacter pc) {
|
||||
ChatManager.chatSystemInfo(pc, "Cache Lists");
|
||||
|
||||
for (GameObjectType gameObjectType : GameObjectType.values()) {
|
||||
|
||||
if (objectCache.get(gameObjectType) == null)
|
||||
continue;
|
||||
|
||||
String ret = gameObjectType.name() + ": " + objectCache.get(gameObjectType).size();
|
||||
ChatManager.chatSystemInfo(pc, ret + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the conn
|
||||
*/
|
||||
//XXX I think we have a severe resource leak here! No one is putting the connections back!
|
||||
public static Connection getConn() {
|
||||
Connection conn = DbManager.connPool.get();
|
||||
try {
|
||||
if (!conn.isClosed())
|
||||
DbManager.connPool.put(conn);
|
||||
} catch (SQLException e) {
|
||||
Logger.error( e.toString());
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
public static final dbAccountHandler AccountQueries = new dbAccountHandler();
|
||||
public static final dbBaneHandler BaneQueries = new dbBaneHandler();
|
||||
public static final dbBaseClassHandler BaseClassQueries = new dbBaseClassHandler();
|
||||
public static final dbBuildingHandler BuildingQueries = new dbBuildingHandler();
|
||||
public static final dbBuildingLocationHandler BuildingLocationQueries = new dbBuildingLocationHandler();
|
||||
public static final dbCharacterPowerHandler CharacterPowerQueries = new dbCharacterPowerHandler();
|
||||
public static final dbCharacterRuneHandler CharacterRuneQueries = new dbCharacterRuneHandler();
|
||||
public static final dbCharacterSkillHandler CharacterSkillQueries = new dbCharacterSkillHandler();
|
||||
public static final dbCityHandler CityQueries = new dbCityHandler();
|
||||
public static final dbContractHandler ContractQueries = new dbContractHandler();
|
||||
public static final dbWarehouseHandler WarehouseQueries = new dbWarehouseHandler();
|
||||
public static final dbCSSessionHandler CSSessionQueries = new dbCSSessionHandler();
|
||||
public static final dbEnchantmentHandler EnchantmentQueries = new dbEnchantmentHandler();
|
||||
public static final dbEffectsResourceCostHandler EffectsResourceCostsQueries = new dbEffectsResourceCostHandler();
|
||||
public static final dbGuildHandler GuildQueries = new dbGuildHandler();
|
||||
public static final dbItemHandler ItemQueries = new dbItemHandler();
|
||||
public static final dbItemBaseHandler ItemBaseQueries = new dbItemBaseHandler();
|
||||
public static final dbKitHandler KitQueries = new dbKitHandler();
|
||||
public static final dbLootTableHandler LootQueries = new dbLootTableHandler();
|
||||
public static final dbMenuHandler MenuQueries = new dbMenuHandler();
|
||||
public static final dbMineHandler MineQueries = new dbMineHandler();
|
||||
public static final dbMobHandler MobQueries = new dbMobHandler();
|
||||
public static final dbMobBaseHandler MobBaseQueries = new dbMobBaseHandler();
|
||||
public static final dbNPCHandler NPCQueries = new dbNPCHandler();
|
||||
public static final dbPlayerCharacterHandler PlayerCharacterQueries = new dbPlayerCharacterHandler();
|
||||
public static final dbPromotionClassHandler PromotionQueries = new dbPromotionClassHandler();
|
||||
public static final dbRaceHandler RaceQueries = new dbRaceHandler();
|
||||
public static final dbResistHandler ResistQueries = new dbResistHandler();
|
||||
public static final dbRuneBaseAttributeHandler RuneBaseAttributeQueries = new dbRuneBaseAttributeHandler();
|
||||
public static final dbRuneBaseEffectHandler RuneBaseEffectQueries = new dbRuneBaseEffectHandler();
|
||||
public static final dbRuneBaseHandler RuneBaseQueries = new dbRuneBaseHandler();
|
||||
public static final dbSkillBaseHandler SkillsBaseQueries = new dbSkillBaseHandler();
|
||||
public static final dbSkillReqHandler SkillReqQueries = new dbSkillReqHandler();
|
||||
public static final dbSpecialLootHandler SpecialLootQueries = new dbSpecialLootHandler();
|
||||
public static final dbVendorDialogHandler VendorDialogQueries = new dbVendorDialogHandler();
|
||||
public static final dbZoneHandler ZoneQueries = new dbZoneHandler();
|
||||
public static final dbRealmHandler RealmQueries = new dbRealmHandler();
|
||||
public static final dbBlueprintHandler BlueprintQueries = new dbBlueprintHandler();
|
||||
public static final dbBoonHandler BoonQueries = new dbBoonHandler();
|
||||
public static final dbShrineHandler ShrineQueries = new dbShrineHandler();
|
||||
public static final dbHeightMapHandler HeightMapQueries = new dbHeightMapHandler();
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.devcmd.AbstractDevCmd;
|
||||
import engine.devcmd.cmds.*;
|
||||
import engine.objects.AbstractGameObject;
|
||||
import engine.objects.Account;
|
||||
import engine.objects.PlayerCharacter;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public enum DevCmdManager {
|
||||
DEV_CMD_MANAGER;
|
||||
|
||||
public static ConcurrentHashMap<String, AbstractDevCmd> devCmds;
|
||||
|
||||
DevCmdManager() {
|
||||
init();
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
DevCmdManager.devCmds = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_LOW);
|
||||
DevCmdManager.registerCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static void registerCommands() {
|
||||
|
||||
// Player
|
||||
DevCmdManager.registerDevCmd(new DistanceCmd());;
|
||||
DevCmdManager.registerDevCmd(new HelpCmd());
|
||||
DevCmdManager.registerDevCmd(new GetZoneCmd());
|
||||
DevCmdManager.registerDevCmd(new GetZoneMobsCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintBankCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintEquipCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintInventoryCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintVaultCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintStatsCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintSkillsCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintPowersCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintBonusesCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintResistsCmd());
|
||||
DevCmdManager.registerDevCmd(new PrintLocationCmd());
|
||||
DevCmdManager.registerDevCmd(new InfoCmd());
|
||||
DevCmdManager.registerDevCmd(new GetHeightCmd());
|
||||
|
||||
// Tester
|
||||
DevCmdManager.registerDevCmd(new JumpCmd());
|
||||
DevCmdManager.registerDevCmd(new GotoCmd());
|
||||
DevCmdManager.registerDevCmd(new SummonCmd());
|
||||
DevCmdManager.registerDevCmd(new SetHealthCmd());
|
||||
DevCmdManager.registerDevCmd(new SetManaCmd());
|
||||
DevCmdManager.registerDevCmd(new SetStaminaCmd());
|
||||
DevCmdManager.registerDevCmd(new FindBuildingsCmd());
|
||||
DevCmdManager.registerDevCmd(new TeleportModeCmd());
|
||||
DevCmdManager.registerDevCmd(new SetLevelCmd());
|
||||
DevCmdManager.registerDevCmd(new SetBaseClassCmd());
|
||||
DevCmdManager.registerDevCmd(new SetPromotionClassCmd());
|
||||
DevCmdManager.registerDevCmd(new EffectCmd());
|
||||
DevCmdManager.registerDevCmd(new SetRuneCmd());
|
||||
DevCmdManager.registerDevCmd(new GetOffsetCmd());
|
||||
DevCmdManager.registerDevCmd(new DebugCmd());
|
||||
DevCmdManager.registerDevCmd(new AddGoldCmd());
|
||||
DevCmdManager.registerDevCmd(new ZoneInfoCmd());
|
||||
DevCmdManager.registerDevCmd(new DebugMeleeSyncCmd());
|
||||
DevCmdManager.registerDevCmd(new HotzoneCmd());
|
||||
DevCmdManager.registerDevCmd(new SetActivateMineCmd());
|
||||
// Dev
|
||||
DevCmdManager.registerDevCmd(new ApplyStatModCmd());
|
||||
DevCmdManager.registerDevCmd(new AddBuildingCmd());
|
||||
DevCmdManager.registerDevCmd(new AddNPCCmd());
|
||||
DevCmdManager.registerDevCmd(new AddMobCmd());
|
||||
DevCmdManager.registerDevCmd(new CopyMobCmd());
|
||||
DevCmdManager.registerDevCmd(new RemoveObjectCmd());
|
||||
DevCmdManager.registerDevCmd(new RotateCmd());
|
||||
DevCmdManager.registerDevCmd(new FlashMsgCmd());
|
||||
DevCmdManager.registerDevCmd(new SysMsgCmd());
|
||||
DevCmdManager.registerDevCmd(new GetBankCmd());
|
||||
DevCmdManager.registerDevCmd(new GetVaultCmd());
|
||||
DevCmdManager.registerDevCmd(new CombatMessageCmd());
|
||||
DevCmdManager.registerDevCmd(new RenameMobCmd());
|
||||
DevCmdManager.registerDevCmd(new RenameCmd());
|
||||
DevCmdManager.registerDevCmd(new CreateItemCmd());
|
||||
DevCmdManager.registerDevCmd(new GetMemoryCmd());
|
||||
DevCmdManager.registerDevCmd(new SetRankCmd());
|
||||
DevCmdManager.registerDevCmd(new MakeBaneCmd());
|
||||
DevCmdManager.registerDevCmd(new RemoveBaneCmd());
|
||||
DevCmdManager.registerDevCmd(new SetBaneActiveCmd());
|
||||
DevCmdManager.registerDevCmd(new SetAdminRuneCmd());
|
||||
DevCmdManager.registerDevCmd(new SetInvulCmd());
|
||||
DevCmdManager.registerDevCmd(new MakeItemCmd());
|
||||
DevCmdManager.registerDevCmd(new EnchantCmd());
|
||||
DevCmdManager.registerDevCmd(new SetSubRaceCmd());
|
||||
// Admin
|
||||
DevCmdManager.registerDevCmd(new GetCacheCountCmd());
|
||||
DevCmdManager.registerDevCmd(new GetRuneDropRateCmd());
|
||||
DevCmdManager.registerDevCmd(new DecachePlayerCmd());
|
||||
DevCmdManager.registerDevCmd(new SetRateCmd());
|
||||
DevCmdManager.registerDevCmd(new AuditMobsCmd());
|
||||
DevCmdManager.registerDevCmd(new ChangeNameCmd());
|
||||
DevCmdManager.registerDevCmd(new GuildListCmd());
|
||||
DevCmdManager.registerDevCmd(new SetGuildCmd());
|
||||
DevCmdManager.registerDevCmd(new SetOwnerCmd());
|
||||
DevCmdManager.registerDevCmd(new NetDebugCmd());
|
||||
DevCmdManager.registerDevCmd(new SqlDebugCmd());
|
||||
DevCmdManager.registerDevCmd(new PullCmd());
|
||||
DevCmdManager.registerDevCmd(new PurgeObjectsCmd());
|
||||
DevCmdManager.registerDevCmd(new SplatMobCmd());
|
||||
DevCmdManager.registerDevCmd(new SlotNpcCmd());
|
||||
DevCmdManager.registerDevCmd(new SetAICmd());
|
||||
DevCmdManager.registerDevCmd(new GateInfoCmd());
|
||||
DevCmdManager.registerDevCmd(new ShowOffsetCmd());
|
||||
DevCmdManager.registerDevCmd(new RealmInfoCmd());
|
||||
DevCmdManager.registerDevCmd(new RebootCmd());
|
||||
DevCmdManager.registerDevCmd(new AddMobPowerCmd());
|
||||
DevCmdManager.registerDevCmd(new AddMobRuneCmd());
|
||||
DevCmdManager.registerDevCmd(new SetMineTypeCmd());
|
||||
DevCmdManager.registerDevCmd(new SetMineExpansion());
|
||||
DevCmdManager.registerDevCmd(new SetForceRenameCityCmd());
|
||||
DevCmdManager.registerDevCmd(new GotoObj());
|
||||
DevCmdManager.registerDevCmd(new convertLoc());
|
||||
DevCmdManager.registerDevCmd(new GetMobBaseLoot());
|
||||
DevCmdManager.registerDevCmd(new MBDropCmd());
|
||||
DevCmdManager.registerDevCmd(new GetDisciplineLocCmd());
|
||||
DevCmdManager.registerDevCmd(new AuditHeightMapCmd());
|
||||
DevCmdManager.registerDevCmd(new UnloadFurnitureCmd());
|
||||
DevCmdManager.registerDevCmd(new SetNPCSlotCmd());
|
||||
DevCmdManager.registerDevCmd(new SetNpcEquipSetCmd());
|
||||
DevCmdManager.registerDevCmd(new SetBuildingAltitudeCmd());
|
||||
DevCmdManager.registerDevCmd(new ResetLevelCmd());
|
||||
DevCmdManager.registerDevCmd(new HeartbeatCmd());
|
||||
DevCmdManager.registerDevCmd(new SetNpcNameCmd());
|
||||
DevCmdManager.registerDevCmd(new SetNpcMobbaseCmd());
|
||||
DevCmdManager.registerDevCmd(new DespawnCmd());
|
||||
DevCmdManager.registerDevCmd(new BoundsCmd());
|
||||
DevCmdManager.registerDevCmd(new GotoBoundsCmd());
|
||||
DevCmdManager.registerDevCmd(new RegionCmd());
|
||||
DevCmdManager.registerDevCmd(new SetMaintCmd());
|
||||
DevCmdManager.registerDevCmd(new ApplyBonusCmd());
|
||||
DevCmdManager.registerDevCmd(new setOpenDateCmd());
|
||||
DevCmdManager.registerDevCmd(new AuditFailedItemsCmd());
|
||||
|
||||
}
|
||||
|
||||
private static void registerDevCmd(AbstractDevCmd cmd) {
|
||||
ArrayList<String> cmdStrings = cmd.getCmdStrings();
|
||||
for (String cmdString : cmdStrings) {
|
||||
DevCmdManager.devCmds.put(cmdString, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public static AbstractDevCmd getDevCmd(String cmd) {
|
||||
String lowercase = cmd.toLowerCase();
|
||||
return DevCmdManager.devCmds.get(lowercase);
|
||||
}
|
||||
|
||||
public static boolean handleDevCmd(PlayerCharacter pcSender, String cmd,
|
||||
String argString, AbstractGameObject target) {
|
||||
|
||||
if (pcSender == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Account a = SessionManager.getAccount(pcSender);
|
||||
|
||||
if (a == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractDevCmd adc = DevCmdManager.getDevCmd(cmd);
|
||||
|
||||
if (adc == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//kill any commands not available to everyone on production server
|
||||
//only admin level can run dev commands on production
|
||||
|
||||
if (a.status.equals(Enum.AccountStatus.ADMIN) == false) {
|
||||
Logger.info("Account " + a.getUname() + "attempted to use dev command " + cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO add a job here to separate calling thread form executing thread?
|
||||
// Log
|
||||
|
||||
String accName = a.getUname();
|
||||
String pcName = pcSender.getCombinedName();
|
||||
String logString = pcName + '(' + accName
|
||||
+ ") '";
|
||||
logString += cmd + ' ' + argString + '\'';
|
||||
Logger.info( logString);
|
||||
|
||||
// execute command;
|
||||
try {
|
||||
adc.doCmd(pcSender, argString, target);
|
||||
} catch (Exception e) {
|
||||
Logger.error(e.toString());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String getCmdsForAccessLevel() {
|
||||
String out = "";
|
||||
|
||||
for (Entry<String, AbstractDevCmd> e : DevCmdManager.devCmds.entrySet())
|
||||
out += e.getKey() + ", ";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.exception.MsgSendException;
|
||||
import engine.net.Dispatch;
|
||||
import engine.net.DispatchMessage;
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.net.client.msg.UpdateGoldMsg;
|
||||
import engine.net.client.msg.group.GroupUpdateMsg;
|
||||
import engine.objects.*;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public enum GroupManager {
|
||||
|
||||
GROUPMANAGER;
|
||||
|
||||
// used for quick lookup of groups by the ID of the group sent in the msg
|
||||
private static final ConcurrentHashMap<Integer, Group> groupsByID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_HIGH);
|
||||
|
||||
// an index for playercharacters to group membership
|
||||
private static final ConcurrentHashMap<AbstractCharacter, Group> groupsByAC = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_HIGH);
|
||||
private static int groupCount = 0;
|
||||
|
||||
/*
|
||||
* Class Implementation
|
||||
*/
|
||||
public static void removeFromGroups(AbstractCharacter ac) {
|
||||
Group gr = null;
|
||||
|
||||
synchronized (GroupManager.groupsByAC) {
|
||||
gr = GroupManager.groupsByAC.remove(ac);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void LeaveGroup(ClientConnection origin) throws MsgSendException {
|
||||
PlayerCharacter source = SessionManager.getPlayerCharacter(origin);
|
||||
LeaveGroup(source);
|
||||
}
|
||||
|
||||
public static void LeaveGroup(PlayerCharacter source) throws MsgSendException {
|
||||
|
||||
if (source == null)
|
||||
return;
|
||||
|
||||
Group group = GroupManager.groupsByAC.get(source);
|
||||
|
||||
if (group == null) // source is not in a group
|
||||
return;
|
||||
|
||||
// Cleanup group window for player quiting
|
||||
GroupUpdateMsg groupUpdateMsg = new GroupUpdateMsg();
|
||||
groupUpdateMsg.setGroup(group);
|
||||
groupUpdateMsg.setPlayer(source);
|
||||
groupUpdateMsg.setMessageType(3);
|
||||
|
||||
Set<PlayerCharacter> groupMembers = group.getMembers();
|
||||
|
||||
for (PlayerCharacter groupMember : groupMembers) {
|
||||
|
||||
if (groupMember == null)
|
||||
continue;
|
||||
|
||||
groupUpdateMsg = new GroupUpdateMsg();
|
||||
groupUpdateMsg.setGroup(group);
|
||||
groupUpdateMsg.setPlayer(source);
|
||||
groupUpdateMsg.setMessageType(3);
|
||||
groupUpdateMsg.setPlayer(groupMember);
|
||||
Dispatch dispatch = Dispatch.borrow(source, groupUpdateMsg);
|
||||
DispatchMessage.dispatchMsgDispatch(dispatch, engine.Enum.DispatchChannel.SECONDARY);
|
||||
|
||||
}
|
||||
|
||||
// Remove from group
|
||||
int size = group.removeGroupMember(source);
|
||||
// remove from the group -> ac mapping list
|
||||
GroupManager.groupsByAC.remove(source);
|
||||
|
||||
if (size == 0) {
|
||||
GroupManager.deleteGroup(group);
|
||||
return; // group empty so cleanup group and we're done
|
||||
}
|
||||
|
||||
// set new group lead if needed
|
||||
if (group.getGroupLead() == source) {
|
||||
PlayerCharacter newLead = group.getMembers().iterator().next();
|
||||
group.setGroupLead(newLead.getObjectUUID());
|
||||
groupUpdateMsg = new GroupUpdateMsg();
|
||||
groupUpdateMsg.setGroup(group);
|
||||
groupUpdateMsg.setPlayer(newLead);
|
||||
groupUpdateMsg.addPlayer(source);
|
||||
groupUpdateMsg.setMessageType(2);
|
||||
group.sendUpdate(groupUpdateMsg);
|
||||
|
||||
// Disable Formation
|
||||
newLead.setFollow(false);
|
||||
groupUpdateMsg = new GroupUpdateMsg();
|
||||
groupUpdateMsg.setGroup(group);
|
||||
groupUpdateMsg.setPlayer(newLead);
|
||||
groupUpdateMsg.setMessageType(8);
|
||||
group.sendUpdate(groupUpdateMsg);
|
||||
}
|
||||
|
||||
//send message to group
|
||||
PlayerCharacter pc = group.getGroupLead();
|
||||
//Fixed
|
||||
String text = source.getFirstName() + " has left the group.";
|
||||
ChatManager.chatGroupInfo(pc, text);
|
||||
|
||||
// cleanup other group members screens
|
||||
groupUpdateMsg = new GroupUpdateMsg();
|
||||
groupUpdateMsg.setGroup(group);
|
||||
groupUpdateMsg.setPlayer(source);
|
||||
groupUpdateMsg.setMessageType(3);
|
||||
group.sendUpdate(groupUpdateMsg);
|
||||
|
||||
}
|
||||
|
||||
//This updates health/stamina/mana and loc of all players in group
|
||||
|
||||
public static void RefreshWholeGroupList(PlayerCharacter source, ClientConnection origin, Group gexp) {
|
||||
|
||||
if (source == null || origin == null)
|
||||
return;
|
||||
|
||||
Group group = GroupManager.groupsByAC.get(source);
|
||||
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
if (gexp.getObjectUUID() != group.getObjectUUID())
|
||||
return;
|
||||
|
||||
Set<PlayerCharacter> groupMembers = group.getMembers();
|
||||
|
||||
if (groupMembers.size() < 2)
|
||||
return;
|
||||
|
||||
// Send all group members health/mana/stamina/loc.
|
||||
|
||||
for (PlayerCharacter groupMember : groupMembers) {
|
||||
|
||||
if (groupMember == null)
|
||||
continue;
|
||||
|
||||
GroupUpdateMsg gum = new GroupUpdateMsg(5, 1, groupMembers, group);
|
||||
gum.setPlayerUUID(groupMember.getObjectUUID());
|
||||
|
||||
Dispatch dispatch = Dispatch.borrow(groupMember, gum);
|
||||
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void RefreshMyGroupList(PlayerCharacter source, ClientConnection origin) {
|
||||
|
||||
if (source == null || origin == null)
|
||||
return;
|
||||
|
||||
Group group = GroupManager.groupsByAC.get(source);
|
||||
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
Set<PlayerCharacter> members = group.getMembers();
|
||||
|
||||
|
||||
// Send all group members to player added
|
||||
for (PlayerCharacter groupMember : members) {
|
||||
|
||||
if (groupMember == null)
|
||||
continue;
|
||||
|
||||
GroupUpdateMsg gum = new GroupUpdateMsg();
|
||||
gum.setGroup(group);
|
||||
gum.setMessageType(1);
|
||||
gum.setPlayer(groupMember);
|
||||
Dispatch dispatch = Dispatch.borrow(groupMember, gum);
|
||||
DispatchMessage.dispatchMsgDispatch(dispatch, engine.Enum.DispatchChannel.SECONDARY);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void RefreshMyGroupListSinglePlayer(PlayerCharacter source, ClientConnection origin, PlayerCharacter playerToRefresh) {
|
||||
|
||||
// send msg type 1 to the source player on this connection to update the group
|
||||
// list stats for the player that has just been loaded
|
||||
|
||||
if (source == null || origin == null || playerToRefresh == null)
|
||||
return;
|
||||
|
||||
Group group = GroupManager.groupsByAC.get(source);
|
||||
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
// only send if the 2 players are in the same group
|
||||
if (group != GroupManager.groupsByAC.get(playerToRefresh))
|
||||
return;
|
||||
|
||||
GroupUpdateMsg gum = new GroupUpdateMsg();
|
||||
gum.setGroup(group);
|
||||
gum.setMessageType(1);
|
||||
gum.setPlayer(playerToRefresh);
|
||||
|
||||
Dispatch dispatch = Dispatch.borrow(source, gum);
|
||||
DispatchMessage.dispatchMsgDispatch(dispatch, engine.Enum.DispatchChannel.SECONDARY);
|
||||
}
|
||||
|
||||
public static void RefreshOthersGroupList(PlayerCharacter source) {
|
||||
|
||||
// refresh my stats on everyone elses group list
|
||||
|
||||
if (source == null)
|
||||
return;
|
||||
|
||||
Group group = GroupManager.groupsByAC.get(source);
|
||||
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
//construct message
|
||||
GroupUpdateMsg gim = new GroupUpdateMsg();
|
||||
gim.setGroup(group);
|
||||
gim.setMessageType(1);
|
||||
gim.setPlayer(source);
|
||||
group.sendUpdate(gim);
|
||||
|
||||
}
|
||||
|
||||
public static int incrGroupCount() {
|
||||
GroupManager.groupCount++;
|
||||
return GroupManager.groupCount;
|
||||
}
|
||||
|
||||
public static boolean deleteGroup(Group g) {
|
||||
|
||||
// remove all players from the mapping
|
||||
Set<PlayerCharacter> members = g.getMembers();
|
||||
|
||||
for (PlayerCharacter pc : members) {
|
||||
if (pc != null) {
|
||||
GroupManager.removeFromGroups(pc);
|
||||
}
|
||||
}
|
||||
// remove the group ID from the list
|
||||
GroupManager.groupsByID.remove(g.getObjectUUID());
|
||||
g.clearMembers();
|
||||
|
||||
g.removeUpdateGroupJob();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Group addNewGroup(Group group) {
|
||||
|
||||
PlayerCharacter pc = group.getGroupLead();
|
||||
|
||||
GroupManager.addGroup(group);
|
||||
|
||||
if (pc != null) {
|
||||
GroupManager.addPlayerGroupMapping(pc, group);
|
||||
return group;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private static Group addGroup(Group group) {
|
||||
|
||||
if (GroupManager.groupsByID.containsKey(group.getObjectUUID())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
GroupManager.groupsByID.put(group.getObjectUUID(), group);
|
||||
return group;
|
||||
}
|
||||
|
||||
public static Group getGroup(int groupID) {
|
||||
return GroupManager.groupsByID.get(groupID);
|
||||
}
|
||||
|
||||
public static Group getGroup(PlayerCharacter pc) {
|
||||
|
||||
return GroupManager.groupsByAC.get(pc);
|
||||
}
|
||||
|
||||
public static void addPlayerGroupMapping(PlayerCharacter pc, Group grp) {
|
||||
GroupManager.groupsByAC.put(pc, grp);
|
||||
}
|
||||
|
||||
public static boolean goldSplit(PlayerCharacter pc, Item item, ClientConnection origin, AbstractWorldObject tar) {
|
||||
if (item == null || pc == null || tar == null || item.getItemBase() == null) {
|
||||
Logger.error( "null something");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.getItemBase().getUUID() != 7) //only split goldItem
|
||||
return false;
|
||||
|
||||
Group group = getGroup(pc);
|
||||
|
||||
if (group == null || !group.getSplitGold()) //make sure player is grouped and split is on
|
||||
return false;
|
||||
|
||||
|
||||
ArrayList<PlayerCharacter> playersSplit = new ArrayList<>();
|
||||
|
||||
//get group members
|
||||
|
||||
for (PlayerCharacter groupMember: group.getMembers()){
|
||||
if (pc.getLoc().distanceSquared2D(groupMember.getLoc()) > MBServerStatics.CHARACTER_LOAD_RANGE * MBServerStatics.CHARACTER_LOAD_RANGE)
|
||||
continue;
|
||||
|
||||
if (!groupMember.isAlive())
|
||||
continue;
|
||||
|
||||
playersSplit.add(groupMember);
|
||||
}
|
||||
|
||||
|
||||
//make sure more then one group member in loot range
|
||||
int size = playersSplit.size();
|
||||
|
||||
if (size < 2)
|
||||
return false;
|
||||
|
||||
int total = item.getNumOfItems();
|
||||
int amount = total / size;
|
||||
int dif = total - (size * amount);
|
||||
|
||||
if (AbstractWorldObject.IsAbstractCharacter(tar)) {
|
||||
}
|
||||
else if (tar.getObjectType().equals(Enum.GameObjectType.Corpse)) {
|
||||
Corpse corpse = (Corpse) tar;
|
||||
corpse.getInventory().remove(item);
|
||||
}
|
||||
else {
|
||||
Logger.error("target not corpse or character");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item.getObjectType() == Enum.GameObjectType.MobLoot){
|
||||
if (tar.getObjectType() == Enum.GameObjectType.Mob){
|
||||
((Mob)tar).getCharItemManager().delete(item);
|
||||
}else
|
||||
item.setNumOfItems(0);
|
||||
}else
|
||||
item.setNumOfItems(0);
|
||||
for (PlayerCharacter splitPlayer : playersSplit) {
|
||||
|
||||
|
||||
|
||||
int amt = (group.isGroupLead(splitPlayer)) ? (amount + dif) : amount;
|
||||
if (amt > 0)
|
||||
splitPlayer.getCharItemManager().addGoldToInventory(amt, false);
|
||||
}
|
||||
|
||||
for (PlayerCharacter splitPlayer : playersSplit) {
|
||||
|
||||
|
||||
UpdateGoldMsg ugm = new UpdateGoldMsg(splitPlayer);
|
||||
ugm.configure();
|
||||
|
||||
Dispatch dispatch = Dispatch.borrow(splitPlayer, ugm);
|
||||
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
|
||||
}
|
||||
|
||||
UpdateGoldMsg updateTargetGold = new UpdateGoldMsg(tar);
|
||||
updateTargetGold.configure();
|
||||
DispatchMessage.dispatchMsgToInterestArea(tar, updateTargetGold, Enum.DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
|
||||
|
||||
// //TODO send group split message
|
||||
String text = "Group Split: " + amount;
|
||||
ChatManager.chatGroupInfo(pc, text);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.Enum.BuildingGroup;
|
||||
import engine.Enum.GuildHistoryType;
|
||||
import engine.net.Dispatch;
|
||||
import engine.net.DispatchMessage;
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.net.client.msg.guild.AcceptInviteToGuildMsg;
|
||||
import engine.net.client.msg.guild.GuildInfoMsg;
|
||||
import engine.objects.*;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
public enum GuildManager {
|
||||
|
||||
GUILDMANAGER;
|
||||
|
||||
//Guild Error Message
|
||||
public static final int FAILURE_TO_SWEAR_GUILD = 45; //45: Failure to swear guild
|
||||
public static final int MUST_LEAVE_GUILD = 75;//75: You must leave your current guild before you can repledge
|
||||
public static final int NO_CHARTER_FOUND = 148; //148: Unable to find a matching petition to complete guild creation
|
||||
public static final int PROFANE_NAME = 149; //149: Guild name fails profanity check
|
||||
public static final int PROFANE_MOTTO = 150; //150: Guild motto fails profanity check
|
||||
public static final int UNIQUE_NAME = 151;//151: Guild name is not unique
|
||||
public static final int UNIQUE_CREST = 152;//152: Guild crest is not unique
|
||||
public static final int CREST_RESERVED = 153; //153: Guild crest is reserved
|
||||
public static final int CREST_COLOR_ERROR = 154; //154: All three crest colors cannot be the same
|
||||
|
||||
public static boolean joinGuild(PlayerCharacter pc, Guild guild, GuildHistoryType historyType) {
|
||||
return joinGuild(pc, guild, 0, historyType);
|
||||
}
|
||||
|
||||
//Used when repledging
|
||||
public static boolean joinGuild(PlayerCharacter pc, Guild guild, int cityID, GuildHistoryType historyType) {
|
||||
return joinGuild(pc, guild, cityID, true,historyType);
|
||||
}
|
||||
|
||||
public static boolean joinGuild(PlayerCharacter playerCharacter, Guild guild, int cityID, boolean fromTeleportScreen, GuildHistoryType historyType) {
|
||||
|
||||
// Member variable delcaration
|
||||
|
||||
ClientConnection origin;
|
||||
AcceptInviteToGuildMsg msg;
|
||||
Dispatch dispatch;
|
||||
|
||||
if (playerCharacter == null || guild == null)
|
||||
return false;
|
||||
|
||||
// Member variable assignment
|
||||
|
||||
origin = SessionManager.getClientConnection(playerCharacter);
|
||||
|
||||
if (origin == null)
|
||||
return false;
|
||||
|
||||
if (playerCharacter.getGuild().isErrant() == false && GuildStatusController.isGuildLeader(playerCharacter.getGuildStatus()))
|
||||
return false;
|
||||
|
||||
if (playerCharacter.getGuild() != null && playerCharacter.getGuild().isGuildLeader(playerCharacter.getObjectUUID()))
|
||||
return false;
|
||||
|
||||
if (playerCharacter.getGuild() != null && !playerCharacter.getGuild().isErrant()){
|
||||
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(playerCharacter.getGuildUUID(), playerCharacter, DateTime.now(), GuildHistoryType.LEAVE)){
|
||||
GuildHistory guildHistory = new GuildHistory(playerCharacter.getGuildUUID(),playerCharacter.getGuild().getName(),DateTime.now(), GuildHistoryType.LEAVE) ;
|
||||
playerCharacter.getGuildHistory().add(guildHistory);
|
||||
}
|
||||
}
|
||||
|
||||
playerCharacter.setInnerCouncil(false);
|
||||
playerCharacter.setGuildLeader(false);
|
||||
playerCharacter.setGuild(guild);
|
||||
|
||||
// Cleanup guild stuff
|
||||
playerCharacter.resetGuildStatuses();
|
||||
|
||||
// send success message to client
|
||||
if (fromTeleportScreen && guild.isNPCGuild())
|
||||
playerCharacter.setFullMember(true);
|
||||
|
||||
msg = new AcceptInviteToGuildMsg(guild.getObjectUUID(), 1, 0);
|
||||
|
||||
if (fromTeleportScreen) {
|
||||
dispatch = Dispatch.borrow(playerCharacter, msg);
|
||||
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
|
||||
}
|
||||
if (DbManager.GuildQueries.ADD_TO_GUILDHISTORY(guild.getObjectUUID(), playerCharacter, DateTime.now(), historyType)){
|
||||
GuildHistory guildHistory = new GuildHistory(guild.getObjectUUID(),guild.getName(),DateTime.now(), historyType) ;
|
||||
playerCharacter.getGuildHistory().add(guildHistory);
|
||||
}
|
||||
|
||||
DispatchMessage.sendToAllInRange(playerCharacter, new GuildInfoMsg(playerCharacter, guild, 2));
|
||||
|
||||
// Send guild join message
|
||||
ChatManager.chatGuildInfo(playerCharacter,
|
||||
playerCharacter.getFirstName() + " has joined the guild");
|
||||
|
||||
playerCharacter.incVer();
|
||||
|
||||
return true;
|
||||
// TODO update player to world
|
||||
}
|
||||
|
||||
public static void enterWorldMOTD(PlayerCharacter pc) {
|
||||
|
||||
Guild guild;
|
||||
Guild nation;
|
||||
|
||||
if (pc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
guild = pc.getGuild();
|
||||
|
||||
if (guild == null || guild.getObjectUUID() == 0) // Don't send to errant
|
||||
return;
|
||||
|
||||
// Send Guild MOTD
|
||||
String motd = guild.getMOTD();
|
||||
if (motd.length() > 0) {
|
||||
ChatManager.chatGuildMOTD(pc, motd);
|
||||
}
|
||||
|
||||
// Send Nation MOTD
|
||||
nation = guild.getNation();
|
||||
|
||||
if (nation != null) {
|
||||
if (nation.getObjectUUID() != 0) { // Don't send to errant nation
|
||||
motd = nation.getMOTD();
|
||||
if (motd.length() > 0) {
|
||||
ChatManager.chatNationMOTD(pc, motd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send IC MOTD if player is IC
|
||||
if (GuildStatusController.isInnerCouncil(pc.getGuildStatus())) {
|
||||
motd = guild.getICMOTD();
|
||||
if (motd.length() > 0) {
|
||||
ChatManager.chatICMOTD(pc, motd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Updates the bind point for everyone in guild
|
||||
|
||||
public static void updateAllGuildBinds(Guild guild, City city) {
|
||||
|
||||
if (guild == null)
|
||||
return;
|
||||
|
||||
int cityID = (city != null) ? city.getObjectUUID() : 0;
|
||||
|
||||
|
||||
|
||||
//update binds ingame
|
||||
|
||||
|
||||
for (PlayerCharacter playerCharacter : Guild.GuildRoster(guild)) {
|
||||
boolean updateBindBuilding = false;
|
||||
|
||||
Building oldBoundBuilding = BuildingManager.getBuildingFromCache(playerCharacter.getBindBuildingID());
|
||||
|
||||
if (oldBoundBuilding == null || oldBoundBuilding.getBlueprint() == null || oldBoundBuilding.getBlueprint().getBuildingGroup().equals(BuildingGroup.TOL))
|
||||
updateBindBuilding = true;
|
||||
|
||||
|
||||
|
||||
if (updateBindBuilding){
|
||||
Building bindBuilding = null;
|
||||
if (city != null)
|
||||
if (city.getTOL() != null)
|
||||
bindBuilding = city.getTOL();
|
||||
|
||||
if (bindBuilding == null)
|
||||
bindBuilding = PlayerCharacter.getBindBuildingForGuild(playerCharacter);
|
||||
|
||||
playerCharacter.setBindBuildingID(bindBuilding != null ? bindBuilding.getObjectUUID() : 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//This updates tags for all online players in a guild.
|
||||
public static void updateAllGuildTags(Guild guild) {
|
||||
|
||||
if (guild == null)
|
||||
return;
|
||||
|
||||
for (PlayerCharacter player : SessionManager.getAllActivePlayerCharacters()) {
|
||||
|
||||
if (player.getGuild().equals(guild))
|
||||
DispatchMessage.sendToAllInRange(player, new GuildInfoMsg(player , guild, 2));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
// Defines static methods which comprise the magicbane
|
||||
// building maintenance system.
|
||||
|
||||
import engine.Enum;
|
||||
import engine.objects.*;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public enum MaintenanceManager {
|
||||
|
||||
MAINTENANCEMANAGER;
|
||||
|
||||
public static void setMaintDateTime(Building building, LocalDateTime maintDate) {
|
||||
|
||||
building.maintDateTime = maintDate;
|
||||
DbManager.BuildingQueries.updateMaintDate(building);
|
||||
|
||||
}
|
||||
|
||||
public static void processBuildingMaintenance() {
|
||||
|
||||
ArrayList<AbstractGameObject> buildingList;
|
||||
ArrayList<Building> maintList;
|
||||
ArrayList<Building> derankList = new ArrayList<>();
|
||||
|
||||
Logger.info("Starting Maintenance on Player Buildings");
|
||||
|
||||
// Build list of buildings to apply maintenance on.
|
||||
|
||||
buildingList = new ArrayList(DbManager.getList(Enum.GameObjectType.Building));
|
||||
maintList = buildMaintList(buildingList);
|
||||
|
||||
// Deduct upkeep and build list of buildings
|
||||
// which did not have funds available
|
||||
|
||||
for (Building building : maintList) {
|
||||
|
||||
if (chargeUpkeep(building) == false)
|
||||
derankList.add(building);
|
||||
}
|
||||
|
||||
// Reset maintenance dates for these buildings
|
||||
|
||||
for (Building building : maintList)
|
||||
setMaintDateTime(building, building.maintDateTime.plusDays(7));
|
||||
|
||||
// Derak or destroy buildings that did not
|
||||
// have funds available.
|
||||
|
||||
for (Building building : derankList)
|
||||
building.destroyOrDerank(null);
|
||||
|
||||
Logger.info("Structures: " + buildingList.size() + " Maint: " + maintList.size() + " Derank: " + derankList.size());
|
||||
}
|
||||
|
||||
// Iterate over all buildings in game and apply exclusion rules
|
||||
// returning a list of building for which maintenance is due.
|
||||
|
||||
private static ArrayList<Building> buildMaintList(ArrayList<AbstractGameObject> buildingList) {
|
||||
|
||||
ArrayList<Building> maintList = new ArrayList<>();
|
||||
|
||||
for (AbstractGameObject gameObject : buildingList) {
|
||||
|
||||
Building building = (Building) gameObject;
|
||||
|
||||
// No Maintenance on fidelity structures
|
||||
|
||||
if (building.getProtectionState() == Enum.ProtectionState.NPC)
|
||||
continue;
|
||||
|
||||
// No maintenance on constructing meshes
|
||||
|
||||
if (building.getRank() < 1)
|
||||
continue;
|
||||
|
||||
// No Maintenance on furniture
|
||||
|
||||
if (building.parentBuildingID != 0)
|
||||
continue;
|
||||
|
||||
// No Blueprint?
|
||||
|
||||
if (building.getBlueprint() == null) {
|
||||
Logger.error("Blueprint missing for uuid: " + building.getObjectUUID());
|
||||
continue;
|
||||
}
|
||||
|
||||
// No maintenance on banestones omfg
|
||||
|
||||
if (building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.BANESTONE))
|
||||
continue;
|
||||
|
||||
// no maintenance on Mines omfg
|
||||
|
||||
if (building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.MINE))
|
||||
continue;
|
||||
|
||||
// Null Maintenance date?
|
||||
|
||||
if (building.maintDateTime == null) {
|
||||
Logger.error("Null maint date for building UUID: " + building.getObjectUUID());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Maintenance date is in the future
|
||||
|
||||
if (building.maintDateTime.isAfter(LocalDateTime.now()))
|
||||
continue;
|
||||
|
||||
// Add building to maintenance queue
|
||||
|
||||
maintList.add(building);
|
||||
}
|
||||
|
||||
return maintList;
|
||||
}
|
||||
|
||||
// Method removes the appropriate amount of gold/resources from
|
||||
// a building according to it's maintenance schedule. True/False
|
||||
// is returned indicating if the building had enough funds to cover.
|
||||
|
||||
public static boolean chargeUpkeep(Building building) {
|
||||
|
||||
City city = null;
|
||||
Warehouse warehouse = null;
|
||||
int maintCost = 0;
|
||||
int overDraft = 0;
|
||||
boolean hasFunds = false;
|
||||
boolean hasResources = false;
|
||||
int resourceValue = 0;
|
||||
|
||||
city = building.getCity();
|
||||
|
||||
if (city != null)
|
||||
warehouse = city.getWarehouse();
|
||||
|
||||
// Cache maintenance cost value
|
||||
|
||||
maintCost = building.getMaintCost();
|
||||
|
||||
// Something went wrong. Missing buildinggroup from switch?
|
||||
|
||||
if (maintCost == 0) {
|
||||
Logger.error("chargeUpkeep", "Error retrieving rankcost for " + building.getName() + " uuid:" + building.getObjectUUID() + "buildinggroup:" + building.getBlueprint().getBuildingGroup().name());
|
||||
// check if there is enough gold on the building
|
||||
return true;
|
||||
}
|
||||
|
||||
if (building.getStrongboxValue() >= maintCost)
|
||||
hasFunds = true;
|
||||
|
||||
// If we cannot cover with just the strongbox
|
||||
// see if there is a warehouse that will cover
|
||||
// the overdraft for us.
|
||||
|
||||
|
||||
if (hasFunds == false && (building.assetIsProtected() || building.getBlueprint().getBuildingGroup() == Enum.BuildingGroup.WAREHOUSE)) {
|
||||
overDraft = maintCost - building.getStrongboxValue();
|
||||
}
|
||||
|
||||
if ((overDraft > 0))
|
||||
if ((building.getBlueprint().getBuildingGroup().equals(Enum.BuildingGroup.SHRINE) == false) &&
|
||||
(warehouse != null) && building.assetIsProtected() == true &&
|
||||
(warehouse.getResources().get(ItemBase.GOLD_ITEM_BASE)) >= overDraft) {
|
||||
hasFunds = true;
|
||||
}
|
||||
|
||||
// If this is an R8 tree, validate that we can
|
||||
// cover the resources required
|
||||
|
||||
if (building.getRank() == 8) {
|
||||
|
||||
hasResources = true;
|
||||
|
||||
if (warehouse == null)
|
||||
hasResources = false;
|
||||
else {
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.stoneIB);
|
||||
|
||||
if (resourceValue < 1500)
|
||||
hasResources = false;
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.lumberIB);
|
||||
|
||||
if (resourceValue < 1500)
|
||||
hasResources = false;
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.galvorIB);
|
||||
|
||||
if (resourceValue < 5)
|
||||
hasResources = false;
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.wormwoodIB);
|
||||
|
||||
if (resourceValue < 5)
|
||||
hasResources = false;
|
||||
|
||||
}
|
||||
}
|
||||
// Validation completed but has failed. We can derank
|
||||
// the target building and early exit
|
||||
|
||||
if ((hasFunds == false) ||
|
||||
((building.getRank() == 8) && !hasResources)) {
|
||||
|
||||
// Add cash back to strongbox for lost rank if the building isn't being destroyed
|
||||
// and it's not an R8 deranking
|
||||
|
||||
if ((building.getRank() > 1) && (building.getRank() < 8)) {
|
||||
building.setStrongboxValue(building.getStrongboxValue() + building.getBlueprint().getRankCost(Math.min(building.getRank(), 7)));
|
||||
}
|
||||
|
||||
return false; // Early exit for having failed to meet maintenance
|
||||
}
|
||||
|
||||
// Remove cash and resources
|
||||
|
||||
// withdraw what we can from the building
|
||||
|
||||
building.setStrongboxValue(building.getStrongboxValue() - (maintCost - overDraft));
|
||||
|
||||
// withdraw overdraft from the whorehouse
|
||||
|
||||
if (overDraft > 0) {
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.goldIB);
|
||||
|
||||
if (DbManager.WarehouseQueries.updateGold(warehouse, resourceValue - overDraft) == true) {
|
||||
warehouse.getResources().put(Warehouse.goldIB, resourceValue - overDraft);
|
||||
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.GOLD, overDraft);
|
||||
} else {
|
||||
Logger.error("gold update failed for warehouse of UUID:" + warehouse.getObjectUUID());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Early exit as we're done if we're not an R8 tree
|
||||
|
||||
if (building.getRank() < 8)
|
||||
return true;
|
||||
|
||||
// Now for the resources if it's an R8 tree
|
||||
|
||||
// Withdraw Stone
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.stoneIB);
|
||||
|
||||
if (DbManager.WarehouseQueries.updateStone(warehouse, resourceValue - 1500) == true) {
|
||||
warehouse.getResources().put(Warehouse.stoneIB, resourceValue - 1500);
|
||||
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.STONE, 1500);
|
||||
} else {
|
||||
Logger.error("stone update failed for warehouse of UUID:" + warehouse.getObjectUUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Withdraw Lumber
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.lumberIB);
|
||||
|
||||
if (DbManager.WarehouseQueries.updateLumber(warehouse, resourceValue - 1500) == true) {
|
||||
warehouse.getResources().put(Warehouse.lumberIB, resourceValue - 1500);
|
||||
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.LUMBER, 1500);
|
||||
} else {
|
||||
Logger.error("lumber update failed for warehouse of UUID:" + warehouse.getObjectUUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Withdraw Galvor
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.galvorIB);
|
||||
|
||||
if (DbManager.WarehouseQueries.updateGalvor(warehouse, resourceValue - 5) == true) {
|
||||
warehouse.getResources().put(Warehouse.galvorIB, resourceValue - 5);
|
||||
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.GALVOR, 5);
|
||||
} else {
|
||||
Logger.error("galvor update failed for warehouse of UUID:" + warehouse.getObjectUUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
resourceValue = warehouse.getResources().get(Warehouse.wormwoodIB);
|
||||
|
||||
if (DbManager.WarehouseQueries.updateWormwood(warehouse, resourceValue - 5) == true) {
|
||||
warehouse.getResources().put(Warehouse.wormwoodIB, resourceValue - 5);
|
||||
warehouse.AddTransactionToWarehouse(Enum.GameObjectType.Building, building.getObjectUUID(), Enum.TransactionType.WITHDRAWL, Resource.WORMWOOD, 5);
|
||||
} else {
|
||||
Logger.error("wyrmwood update failed for warehouse of UUID:" + warehouse.getObjectUUID());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void dailyMaintenance() {
|
||||
|
||||
ArrayList<Shrine> shrineList = new ArrayList<>();
|
||||
|
||||
Logger.info("Maintenance has started");
|
||||
|
||||
// Update shrines to proper city owner
|
||||
|
||||
for (Shrine shrine : Shrine.shrinesByBuildingUUID.values()) {
|
||||
try {
|
||||
Building shrineBuilding = (Building) DbManager.getObject(Enum.GameObjectType.Building, shrine.getBuildingID());
|
||||
|
||||
if (shrineBuilding == null)
|
||||
continue;
|
||||
|
||||
|
||||
if (shrineBuilding.getOwner().equals(shrineBuilding.getCity().getOwner()) == false)
|
||||
shrineBuilding.claim(shrineBuilding.getCity().getOwner());
|
||||
} catch (Exception e) {
|
||||
Logger.info("Shrine " + shrine.getBuildingID() + " Error " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Grab list of top two shrines of each type
|
||||
|
||||
for (Shrine shrine : Shrine.shrinesByBuildingUUID.values()) {
|
||||
|
||||
if (shrine.getRank() == 0 || shrine.getRank() == 1)
|
||||
shrineList.add(shrine);
|
||||
}
|
||||
|
||||
Logger.info("Decaying " + shrineList.size() + " shrines...");
|
||||
|
||||
// Top 2 shrines decay by 10% a day
|
||||
|
||||
for (Shrine shrine : shrineList) {
|
||||
|
||||
try {
|
||||
shrine.decay();
|
||||
} catch (Exception e) {
|
||||
Logger.info("Shrine " + shrine.getBuildingID() + " Error " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Run maintenance on player buildings
|
||||
|
||||
if ((boolean) ConfigManager.MB_WORLD_MAINTENANCE.getValue().equals("true"))
|
||||
processBuildingMaintenance();
|
||||
else
|
||||
Logger.info("Maintenance Costings: DISABLED");
|
||||
|
||||
Logger.info("process has completed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,650 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum.DispatchChannel;
|
||||
import engine.Enum.GameObjectType;
|
||||
import engine.Enum.ModType;
|
||||
import engine.Enum.SourceType;
|
||||
import engine.InterestManagement.InterestManager;
|
||||
import engine.InterestManagement.WorldGrid;
|
||||
import engine.exception.MsgSendException;
|
||||
import engine.job.JobContainer;
|
||||
import engine.job.JobScheduler;
|
||||
import engine.jobs.ChangeAltitudeJob;
|
||||
import engine.jobs.FlightJob;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.net.DispatchMessage;
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.net.client.msg.ChangeAltitudeMsg;
|
||||
import engine.net.client.msg.MoveToPointMsg;
|
||||
import engine.net.client.msg.TeleportToPointMsg;
|
||||
import engine.net.client.msg.UpdateStateMsg;
|
||||
import engine.objects.*;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static engine.math.FastMath.sqr;
|
||||
|
||||
public enum MovementManager {
|
||||
|
||||
MOVEMENTMANAGER;
|
||||
|
||||
private static final String changeAltitudeTimerJobName = "ChangeHeight";
|
||||
private static final String flightTimerJobName = "Flight";
|
||||
|
||||
public static void sendOOS(PlayerCharacter pc) {
|
||||
pc.setWalkMode(true);
|
||||
MovementManager.sendRWSSMsg(pc);
|
||||
}
|
||||
|
||||
public static void sendRWSSMsg(AbstractCharacter ac) {
|
||||
|
||||
if (!ac.isAlive())
|
||||
return;
|
||||
UpdateStateMsg rssm = new UpdateStateMsg();
|
||||
rssm.setPlayer(ac);
|
||||
if (ac.getObjectType() == GameObjectType.PlayerCharacter)
|
||||
DispatchMessage.dispatchMsgToInterestArea(ac, rssm, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
else
|
||||
DispatchMessage.sendToAllInRange(ac, rssm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the first combat target for the AbstractCharacter. Used to clear the
|
||||
* combat
|
||||
* target upon each move, unless something has set the firstHitCombatTarget
|
||||
* Also used to determine the size of a monster's hitbox
|
||||
*/
|
||||
public static void movement(MoveToPointMsg msg, AbstractCharacter toMove) throws MsgSendException {
|
||||
|
||||
// check for stun/root
|
||||
if (!toMove.isAlive())
|
||||
return;
|
||||
|
||||
if (toMove.getObjectType().equals(GameObjectType.PlayerCharacter)){
|
||||
if (((PlayerCharacter)toMove).isCasting())
|
||||
((PlayerCharacter)toMove).update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
toMove.setIsCasting(false);
|
||||
toMove.setItemCasting(false);
|
||||
|
||||
if (toMove.getBonuses().getBool(ModType.Stunned, SourceType.None) || toMove.getBonuses().getBool(ModType.CannotMove, SourceType.None)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.getEndLat() > MBServerStatics.MAX_WORLD_WIDTH)
|
||||
msg.setEndLat((float) MBServerStatics.MAX_WORLD_WIDTH);
|
||||
|
||||
if (msg.getEndLon() < MBServerStatics.MAX_WORLD_HEIGHT){
|
||||
msg.setEndLon((float) MBServerStatics.MAX_WORLD_HEIGHT);
|
||||
}
|
||||
|
||||
// if (msg.getEndLat() < 0)
|
||||
// msg.setEndLat(0);
|
||||
//
|
||||
// if (msg.getEndLon() > 0)
|
||||
// msg.setEndLon(0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!toMove.isMoving())
|
||||
toMove.resetLastSetLocUpdate();
|
||||
else
|
||||
toMove.update();
|
||||
|
||||
// Update movement for the player
|
||||
|
||||
|
||||
// else if (toMove.getObjectType() == GameObjectType.Mob)
|
||||
// ((Mob)toMove).updateLocation();
|
||||
// get start and end locations for the move
|
||||
Vector3fImmutable startLocation = new Vector3fImmutable(msg.getStartLat(), msg.getStartAlt(), msg.getStartLon());
|
||||
Vector3fImmutable endLocation = new Vector3fImmutable(msg.getEndLat(), msg.getEndAlt(), msg.getEndLon());
|
||||
|
||||
// if (toMove.getObjectType() == GameObjectType.PlayerCharacter)
|
||||
// if (msg.getEndAlt() == 0 && msg.getTargetID() == 0){
|
||||
// MovementManager.sendRWSSMsg(toMove);
|
||||
// }
|
||||
|
||||
//If in Building, let's see if we need to Fix
|
||||
|
||||
// if inside a building, convert both locations from the building local reference frame to the world reference frame
|
||||
|
||||
if (msg.getTargetID() > 0) {
|
||||
Building building = BuildingManager.getBuildingFromCache(msg.getTargetID());
|
||||
if (building != null) {
|
||||
|
||||
Vector3fImmutable convertLocEnd = new Vector3fImmutable(ZoneManager.convertLocalToWorld(building, endLocation));
|
||||
// if (!Bounds.collide(convertLocEnd, b) || !b.loadObjectsInside()) {
|
||||
// toMove.setInBuilding(-1);
|
||||
// toMove.setInFloorID(-1);
|
||||
// toMove.setInBuildingID(0);
|
||||
// }
|
||||
// else {
|
||||
toMove.setInBuilding(msg.getInBuilding());
|
||||
toMove.setInFloorID(msg.getUnknown01());
|
||||
toMove.setInBuildingID(msg.getTargetID());
|
||||
msg.setStartCoord(ZoneManager.convertWorldToLocal(building, toMove.getLoc()));
|
||||
|
||||
if (toMove.getObjectType() == GameObjectType.PlayerCharacter) {
|
||||
if (convertLocEnd.distanceSquared2D(toMove.getLoc()) > 6000 * 6000) {
|
||||
|
||||
Logger.info( "ENDLOC:" + convertLocEnd.x + ',' + convertLocEnd.y + ',' + convertLocEnd.z +
|
||||
',' + "GETLOC:" + toMove.getLoc().x + ',' + toMove.getLoc().y + ',' + toMove.getLoc().z + " Name " + ((PlayerCharacter) toMove).getCombinedName());
|
||||
toMove.teleport(toMove.getLoc());
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
startLocation = toMove.getLoc();
|
||||
endLocation = convertLocEnd;
|
||||
|
||||
} else {
|
||||
|
||||
toMove.setInBuilding(-1);
|
||||
toMove.setInFloorID(-1);
|
||||
toMove.setInBuildingID(0);
|
||||
//SYNC PLAYER
|
||||
toMove.teleport(toMove.getLoc());
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
toMove.setInBuildingID(0);
|
||||
toMove.setInFloorID(-1);
|
||||
toMove.setInBuilding(-1);
|
||||
msg.setStartCoord(toMove.getLoc());
|
||||
}
|
||||
|
||||
//make sure we set the correct player.
|
||||
msg.setSourceType(toMove.getObjectType().ordinal());
|
||||
msg.setSourceID(toMove.getObjectUUID());
|
||||
|
||||
//if player in region, modify location to local location of building. set target to building.
|
||||
if (toMove.getRegion() != null){
|
||||
Building regionBuilding = Regions.GetBuildingForRegion(toMove.getRegion());
|
||||
if (regionBuilding != null){
|
||||
msg.setStartCoord(ZoneManager.convertWorldToLocal(Regions.GetBuildingForRegion(toMove.getRegion()), toMove.getLoc()));
|
||||
msg.setEndCoord(ZoneManager.convertWorldToLocal(regionBuilding, endLocation));
|
||||
msg.setInBuilding(toMove.getRegion().level);
|
||||
msg.setUnknown01(toMove.getRegion().room);
|
||||
msg.setTargetType(GameObjectType.Building.ordinal());
|
||||
msg.setTargetID(regionBuilding.getObjectUUID());
|
||||
}
|
||||
|
||||
}else{
|
||||
toMove.setInBuildingID(0);
|
||||
toMove.setInFloorID(-1);
|
||||
toMove.setInBuilding(-1);
|
||||
msg.setStartCoord(toMove.getLoc());
|
||||
msg.setEndCoord(endLocation);
|
||||
msg.setTargetType(0);
|
||||
msg.setTargetID(0);
|
||||
}
|
||||
|
||||
//checks sync between character and server, if out of sync, teleport player to original position and return.
|
||||
if (toMove.getObjectType() == GameObjectType.PlayerCharacter) {
|
||||
boolean startLocInSync = checkSync(toMove, startLocation, toMove.getLoc());
|
||||
|
||||
if (!startLocInSync){
|
||||
syncLoc(toMove, toMove.getLoc(), startLocInSync);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// set direction, based on the current location which has just been sync'd
|
||||
// with the client and the calc'd destination
|
||||
toMove.setFaceDir(endLocation.subtract2D(toMove.getLoc()).normalize());
|
||||
|
||||
boolean collide = false;
|
||||
if (toMove.getObjectType().equals(GameObjectType.PlayerCharacter)) {
|
||||
Vector3fImmutable collidePoint = Bounds.PlayerBuildingCollisionPoint((PlayerCharacter)toMove, toMove.getLoc(), endLocation);
|
||||
|
||||
if (collidePoint != null) {
|
||||
msg.setEndCoord(collidePoint);
|
||||
endLocation = collidePoint;
|
||||
collide = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (toMove.getObjectType() == GameObjectType.PlayerCharacter && ((PlayerCharacter) toMove).isTeleportMode()) {
|
||||
toMove.teleport(endLocation);
|
||||
return;
|
||||
}
|
||||
|
||||
// move to end location, this can interrupt the current move
|
||||
toMove.setEndLoc(endLocation);
|
||||
|
||||
// ChatManager.chatSystemInfo((PlayerCharacter)toMove, "Moving to " + Vector3fImmutable.toString(endLocation));
|
||||
|
||||
// make sure server knows player is not sitting
|
||||
toMove.setSit(false);
|
||||
|
||||
// cancel any effects that break upon movement
|
||||
toMove.cancelOnMove();
|
||||
|
||||
//cancel any attacks for manual move.
|
||||
if ((toMove.getObjectType() == GameObjectType.PlayerCharacter) && msg.getUnknown02() == 0)
|
||||
toMove.setCombatTarget(null);
|
||||
|
||||
|
||||
// If it's not a player moving just send the message
|
||||
|
||||
if ((toMove.getObjectType() == GameObjectType.PlayerCharacter) == false) {
|
||||
DispatchMessage.sendToAllInRange(toMove, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a player who is moving then we need to handle characters
|
||||
// who should see the message via group follow
|
||||
|
||||
PlayerCharacter player = (PlayerCharacter) toMove;
|
||||
|
||||
player.setTimeStamp("lastMoveGate", System.currentTimeMillis());
|
||||
|
||||
if (collide)
|
||||
DispatchMessage.dispatchMsgToInterestArea(player, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
else
|
||||
DispatchMessage.dispatchMsgToInterestArea(player, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
||||
|
||||
|
||||
// Handle formation movement if needed
|
||||
|
||||
if (player.getFollow() == false)
|
||||
return;
|
||||
|
||||
|
||||
City cityObject = null;
|
||||
Zone serverZone = null;
|
||||
|
||||
serverZone = ZoneManager.findSmallestZone(player.getLoc());
|
||||
cityObject = (City) DbManager.getFromCache(GameObjectType.City, serverZone.getPlayerCityUUID());
|
||||
|
||||
// Do not send group messages if player is on grid
|
||||
|
||||
if (cityObject != null)
|
||||
return;
|
||||
|
||||
// If player is not in a group we can exit here
|
||||
|
||||
Group group = GroupManager.getGroup(player);
|
||||
|
||||
if (group == null)
|
||||
return;
|
||||
|
||||
// Echo group movement messages
|
||||
|
||||
if (group.getGroupLead().getObjectUUID() == player.getObjectUUID())
|
||||
moveGroup(player, player.getClientConnection(), msg);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* compare client and server location to verify that the two are in sync
|
||||
*
|
||||
* @param ac the player character
|
||||
* @param clientLoc location as reported by the client
|
||||
* @param serverLoc location known to the server
|
||||
* @return true if the two are in sync
|
||||
*/
|
||||
private static boolean checkSync(AbstractCharacter ac, Vector3fImmutable clientLoc, Vector3fImmutable serverLoc) {
|
||||
|
||||
float desyncDist = clientLoc.distanceSquared2D(serverLoc);
|
||||
|
||||
// desync logging
|
||||
if (MBServerStatics.MOVEMENT_SYNC_DEBUG)
|
||||
if (desyncDist > MBServerStatics.MOVEMENT_DESYNC_TOLERANCE * MBServerStatics.MOVEMENT_DESYNC_TOLERANCE)
|
||||
// our current location server side is a calc of last known loc + direction + speed and known time of last update
|
||||
Logger.debug("Movement out of sync for " + ac.getFirstName()
|
||||
+ ", Server Loc: " + serverLoc.getX() + ' ' + serverLoc.getZ()
|
||||
+ " , Client loc: " + clientLoc.getX() + ' ' + clientLoc.getZ()
|
||||
+ " desync distance " + desyncDist
|
||||
+ " moving=" + ac.isMoving());
|
||||
else
|
||||
Logger.debug( "Movement sync is good - desyncDist = " + desyncDist);
|
||||
|
||||
if (ac.getDebug(1) && ac.getObjectType().equals(GameObjectType.PlayerCharacter))
|
||||
if (desyncDist > MBServerStatics.MOVEMENT_DESYNC_TOLERANCE * MBServerStatics.MOVEMENT_DESYNC_TOLERANCE) {
|
||||
PlayerCharacter pc = (PlayerCharacter) ac;
|
||||
ChatManager.chatSystemInfo(pc,
|
||||
"Movement out of sync for " + ac.getFirstName()
|
||||
+ ", Server Loc: " + serverLoc.getX() + ' ' + serverLoc.getZ()
|
||||
+ " , Client loc: " + clientLoc.getX() + ' ' + clientLoc.getZ()
|
||||
+ " desync distance " + desyncDist
|
||||
+ " moving=" + ac.isMoving());
|
||||
}
|
||||
|
||||
// return indicator that the two are in sync or not
|
||||
return (desyncDist < 100f * 100f);
|
||||
|
||||
}
|
||||
|
||||
//Update for when the character is in flight
|
||||
public static void updateFlight(PlayerCharacter pc, ChangeAltitudeMsg msg, int duration) {
|
||||
if (pc == null)
|
||||
return;
|
||||
|
||||
// clear flight timer job as we are about to update stuff and submit a new job
|
||||
pc.clearTimer(flightTimerJobName);
|
||||
|
||||
if (!pc.isActive()) {
|
||||
pc.setAltitude(0);
|
||||
pc.setDesiredAltitude(0);
|
||||
pc.setTakeOffTime(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if we are mid height change
|
||||
JobContainer cjc = pc.getTimers().get(changeAltitudeTimerJobName);
|
||||
if (cjc != null) {
|
||||
addFlightTimer(pc, msg, MBServerStatics.FLY_FREQUENCY_MS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Altitude is zero, do nothing
|
||||
if (pc.getAltitude() < 1)
|
||||
return;
|
||||
|
||||
//make sure player is still allowed to fly
|
||||
boolean canFly = false;
|
||||
PlayerBonuses bonus = pc.getBonuses();
|
||||
|
||||
if (bonus != null && !bonus.getBool(ModType.NoMod, SourceType.Fly) && bonus.getBool(ModType.Fly, SourceType.None) && pc.isAlive())
|
||||
canFly = true;
|
||||
|
||||
// if stam less that 2 - time to force a landing
|
||||
if (pc.getStamina() < 10f || !canFly) {
|
||||
|
||||
// dont call stop movement here as we want to
|
||||
// preserve endloc
|
||||
//pc.stopMovement();
|
||||
// sync world location
|
||||
pc.setLoc(pc.getLoc());
|
||||
// force a landing
|
||||
msg.setStartAlt(pc.getAltitude());
|
||||
msg.setTargetAlt(0);
|
||||
msg.setAmountToMove(pc.getAltitude());
|
||||
msg.setUp(false);
|
||||
DispatchMessage.dispatchMsgToInterestArea(pc, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
MovementManager.addChangeAltitudeTimer(pc, msg.getStartAlt(), msg.getTargetAlt(), (int) (MBServerStatics.HEIGHT_CHANGE_TIMER_MS * pc.getAltitude()));
|
||||
pc.setAltitude(msg.getStartAlt() - 10);
|
||||
|
||||
} else //Add a new flight timer to check stam / force land
|
||||
if (pc.getAltitude() > 0)
|
||||
addFlightTimer(pc, msg, MBServerStatics.FLY_FREQUENCY_MS);
|
||||
|
||||
}
|
||||
|
||||
public static void finishChangeAltitude(AbstractCharacter ac, float targetAlt) {
|
||||
|
||||
if (ac.getObjectType().equals(GameObjectType.PlayerCharacter) == false)
|
||||
return;
|
||||
|
||||
//reset the getLoc timer before we clear other timers
|
||||
// otherwise the next call to getLoc will not be correct
|
||||
ac.resetLastSetLocUpdate();
|
||||
|
||||
// call getLoc once as it processes loc to the ms
|
||||
Vector3fImmutable curLoc = ac.getLoc();
|
||||
|
||||
if (MBServerStatics.MOVEMENT_SYNC_DEBUG)
|
||||
Logger.info("Finished Alt change, setting the end location to "
|
||||
+ ac.getEndLoc().getX() + ' ' + ac.getEndLoc().getZ()
|
||||
+ " moving=" + ac.isMoving()
|
||||
+ " and current location is " + curLoc.getX() + ' ' + curLoc.getZ());
|
||||
|
||||
if (ac.getDebug(1) && ac.getObjectType().equals(GameObjectType.PlayerCharacter))
|
||||
ChatManager.chatSystemInfo((PlayerCharacter) ac, "Finished Alt change, setting the end location to " + ac.getEndLoc().getX() + ' ' + ac.getEndLoc().getZ() + " moving=" + ac.isMoving() + " and current location is " + curLoc.getX() + ' ' + curLoc.getZ());
|
||||
|
||||
//Send run/walk/sit/stand to tell the client we are flying / landing etc
|
||||
ac.update();
|
||||
ac.stopMovement(ac.getLoc());
|
||||
if (ac.isAlive())
|
||||
MovementManager.sendRWSSMsg(ac);
|
||||
|
||||
//Check collision again
|
||||
}
|
||||
|
||||
|
||||
// Handle formation movement in group
|
||||
|
||||
public static void moveGroup(PlayerCharacter pc, ClientConnection origin, MoveToPointMsg msg) throws MsgSendException {
|
||||
// get forward vector
|
||||
Vector3f faceDir = new Vector3f(pc.getFaceDir().x, 0, pc.getFaceDir().z).normalize();
|
||||
// get perpendicular vector
|
||||
Vector3f crossDir = new Vector3f(faceDir.z, 0, -faceDir.x);
|
||||
|
||||
//get source loc with altitude
|
||||
Vector3f sLoc = new Vector3f(pc.getLoc().x, pc.getAltitude(), pc.getLoc().z);
|
||||
|
||||
Group group = GroupManager.getGroup(pc);
|
||||
Set<PlayerCharacter> members = group.getMembers();
|
||||
int pos = 0;
|
||||
for (PlayerCharacter member : members) {
|
||||
|
||||
if (member == null)
|
||||
continue;
|
||||
if (member.getObjectUUID() == pc.getObjectUUID())
|
||||
continue;
|
||||
|
||||
MoveToPointMsg groupMsg = new MoveToPointMsg(msg);
|
||||
|
||||
// Verify group member should be moved
|
||||
|
||||
pos++;
|
||||
if (member.getFollow() != true)
|
||||
continue;
|
||||
|
||||
//get member loc with altitude, then range against source loc
|
||||
Vector3f mLoc = new Vector3f(member.getLoc().x, member.getAltitude(), member.getLoc().z);
|
||||
|
||||
if (sLoc.distanceSquared2D(mLoc) > sqr(MBServerStatics.FORMATION_RANGE))
|
||||
continue;
|
||||
|
||||
//don't move if player has taken damage from another player in last 60 seconds
|
||||
long lastAttacked = System.currentTimeMillis() - pc.getLastPlayerAttackTime();
|
||||
if (lastAttacked < 60000)
|
||||
continue;
|
||||
|
||||
if (!member.isAlive())
|
||||
continue;
|
||||
|
||||
//don't move if player is stunned or rooted
|
||||
PlayerBonuses bonus = member.getBonuses();
|
||||
if (bonus.getBool(ModType.Stunned, SourceType.None) || bonus.getBool(ModType.CannotMove, SourceType.None))
|
||||
continue;
|
||||
|
||||
member.update();
|
||||
|
||||
|
||||
// All checks passed, let's move the player
|
||||
// First get the offset position
|
||||
Vector3f offset = Formation.getOffset(group.getFormation(), pos);
|
||||
Vector3fImmutable destination = pc.getEndLoc();
|
||||
// offset forwards or backwards
|
||||
destination = destination.add(faceDir.mult(offset.z));
|
||||
// offset left or right
|
||||
destination = destination.add(crossDir.mult(offset.x));
|
||||
// ArrayList<AbstractWorldObject> awoList = WorldGrid.INSTANCE.getObjectsInRangePartial(member, member.getLoc().distance2D(destination) +1000, MBServerStatics.MASK_BUILDING);
|
||||
//
|
||||
// boolean skip = false;
|
||||
//
|
||||
// for (AbstractWorldObject awo: awoList){
|
||||
// Building building = (Building)awo;
|
||||
//
|
||||
// if (building.getBounds() != null){
|
||||
// if (Bounds.collide(building, member.getLoc(), destination)){
|
||||
// skip = true;
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// if (skip)
|
||||
// continue;
|
||||
// if (member.isMoving())
|
||||
// member.stopMovement();
|
||||
|
||||
// Update player speed to match group lead speed and make standing
|
||||
if (member.isSit() || (member.isWalk() != pc.isWalk())) {
|
||||
member.setSit(false);
|
||||
member.setWalkMode(pc.isWalk());
|
||||
MovementManager.sendRWSSMsg(member);
|
||||
}
|
||||
|
||||
//cancel any effects that break upon movement
|
||||
member.cancelOnMove();
|
||||
|
||||
// send movement for other players to see
|
||||
groupMsg.setSourceID(member.getObjectUUID());
|
||||
groupMsg.setStartCoord(member.getLoc());
|
||||
groupMsg.setEndCoord(destination);
|
||||
groupMsg.clearTarget();
|
||||
DispatchMessage.sendToAllInRange(member, groupMsg);
|
||||
|
||||
// update group member
|
||||
member.setFaceDir(destination.subtract2D(member.getLoc()).normalize());
|
||||
member.setEndLoc(destination);
|
||||
}
|
||||
}
|
||||
|
||||
//Getting rid of flgith timer.
|
||||
|
||||
public static void addFlightTimer(PlayerCharacter pc, ChangeAltitudeMsg msg, int duration) {
|
||||
if (pc == null || pc.getTimers() == null)
|
||||
return;
|
||||
if (!pc.getTimers().containsKey(flightTimerJobName)) {
|
||||
FlightJob ftj = new FlightJob(pc, msg, duration);
|
||||
JobContainer jc = JobScheduler.getInstance().scheduleJob(ftj, duration);
|
||||
pc.getTimers().put(flightTimerJobName, jc);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addChangeAltitudeTimer(PlayerCharacter pc, float startAlt, float targetAlt, int duration) {
|
||||
if (pc == null || pc.getTimers() == null)
|
||||
return;
|
||||
ChangeAltitudeJob catj = new ChangeAltitudeJob(pc, startAlt, targetAlt);
|
||||
JobContainer jc = JobScheduler.getInstance().scheduleJob(catj, duration);
|
||||
pc.getTimers().put(changeAltitudeTimerJobName, jc);
|
||||
}
|
||||
|
||||
|
||||
public static void translocate(AbstractCharacter teleporter, Vector3fImmutable targetLoc, Regions region) {
|
||||
|
||||
|
||||
if (targetLoc == null)
|
||||
return;
|
||||
|
||||
|
||||
Vector3fImmutable oldLoc = new Vector3fImmutable(teleporter.getLoc());
|
||||
|
||||
|
||||
teleporter.stopMovement(targetLoc);
|
||||
|
||||
teleporter.setRegion(region);
|
||||
|
||||
|
||||
|
||||
//mobs ignore region sets for now.
|
||||
if (teleporter.getObjectType().equals(GameObjectType.Mob)){
|
||||
teleporter.setInBuildingID(0);
|
||||
teleporter.setInBuilding(-1);
|
||||
teleporter.setInFloorID(-1);
|
||||
TeleportToPointMsg msg = new TeleportToPointMsg(teleporter, targetLoc.getX(), targetLoc.getY(), targetLoc.getZ(), 0, -1, -1);
|
||||
DispatchMessage.dispatchMsgToInterestArea(oldLoc, teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
||||
return;
|
||||
}
|
||||
TeleportToPointMsg msg = new TeleportToPointMsg(teleporter, targetLoc.getX(), targetLoc.getY(), targetLoc.getZ(), 0, -1, -1);
|
||||
//we shouldnt need to send teleport message to new area, as loadjob should pick it up.
|
||||
// DispatchMessage.dispatchMsgToInterestArea(teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
DispatchMessage.dispatchMsgToInterestArea(oldLoc, teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
|
||||
if (teleporter.getObjectType().equals(GameObjectType.PlayerCharacter))
|
||||
InterestManager.INTERESTMANAGER.HandleLoadForTeleport((PlayerCharacter)teleporter);
|
||||
|
||||
}
|
||||
|
||||
public static void translocateToObject(AbstractCharacter teleporter, AbstractWorldObject worldObject) {
|
||||
|
||||
|
||||
|
||||
Vector3fImmutable targetLoc = teleporter.getLoc();
|
||||
|
||||
Vector3fImmutable oldLoc = new Vector3fImmutable(teleporter.getLoc());
|
||||
|
||||
teleporter.stopMovement(teleporter.getLoc());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//mobs ignore region sets for now.
|
||||
if (teleporter.getObjectType().equals(GameObjectType.Mob)){
|
||||
teleporter.setInBuildingID(0);
|
||||
teleporter.setInBuilding(-1);
|
||||
teleporter.setInFloorID(-1);
|
||||
TeleportToPointMsg msg = new TeleportToPointMsg(teleporter, targetLoc.getX(), targetLoc.getY(), targetLoc.getZ(), 0, -1, -1);
|
||||
DispatchMessage.dispatchMsgToInterestArea(oldLoc, teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false);
|
||||
return;
|
||||
}
|
||||
boolean collide = false;
|
||||
int maxFloor = -1;
|
||||
int buildingID = 0;
|
||||
boolean isGroundLevel = false;
|
||||
HashSet<AbstractWorldObject> buildings = WorldGrid.getObjectsInRangePartial(teleporter, 200, MBServerStatics.MASK_BUILDING);
|
||||
for (AbstractWorldObject awo : buildings) {
|
||||
Building building = (Building) awo;
|
||||
if (collide)
|
||||
break;
|
||||
}
|
||||
if (!collide) {
|
||||
teleporter.setInBuildingID(0);
|
||||
teleporter.setInBuilding(-1);
|
||||
teleporter.setInFloorID(-1);
|
||||
} else {
|
||||
if (isGroundLevel) {
|
||||
teleporter.setInBuilding(0);
|
||||
teleporter.setInFloorID(-1);
|
||||
} else {
|
||||
teleporter.setInBuilding(maxFloor - 1);
|
||||
teleporter.setInFloorID(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TeleportToPointMsg msg = new TeleportToPointMsg(teleporter, targetLoc.getX(), targetLoc.getY(), targetLoc.getZ(), 0, -1, -1);
|
||||
//we shouldnt need to send teleport message to new area, as loadjob should pick it up.
|
||||
// DispatchMessage.dispatchMsgToInterestArea(teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
DispatchMessage.dispatchMsgToInterestArea(oldLoc, teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false);
|
||||
|
||||
if (teleporter.getObjectType().equals(GameObjectType.PlayerCharacter))
|
||||
InterestManager.INTERESTMANAGER.HandleLoadForTeleport((PlayerCharacter)teleporter);
|
||||
|
||||
}
|
||||
|
||||
private static void syncLoc(AbstractCharacter ac, Vector3fImmutable clientLoc, boolean useClientLoc) {
|
||||
ac.teleport(ac.getLoc());
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,289 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.objects.Account;
|
||||
import engine.objects.Guild;
|
||||
import engine.objects.PlayerCharacter;
|
||||
import engine.server.MBServerStatics;
|
||||
import engine.session.CSSession;
|
||||
import engine.session.Session;
|
||||
import engine.session.SessionID;
|
||||
import engine.util.ByteUtils;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public enum SessionManager {
|
||||
|
||||
SESSIONMANAGER;
|
||||
|
||||
// TODO add session activity timestamping & timeout monitors
|
||||
|
||||
private static ConcurrentHashMap<SessionID, Session> sessionIDtoSession = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_HIGH);
|
||||
private static ConcurrentHashMap<PlayerCharacter, Session> pcToSession = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_HIGH);
|
||||
private static ConcurrentHashMap<Account, Session> accountToSession = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_HIGH);
|
||||
private static ConcurrentHashMap<ClientConnection, Session> connToSession = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_HIGH);
|
||||
public static int _maxPopulation = 0;
|
||||
|
||||
// 0 = login server
|
||||
// 1 = gateway server
|
||||
// 2 = all other servers
|
||||
private static int crossServerBehavior = 2;
|
||||
|
||||
public static Session getNewSession(SessionID sesID, Account a, ClientConnection c) {
|
||||
Session ses = new Session(sesID, a, c);
|
||||
|
||||
SessionManager.sessionIDtoSession.put(sesID, ses);
|
||||
SessionManager.accountToSession.put(a, ses);
|
||||
SessionManager.connToSession.put(c, ses);
|
||||
|
||||
if (crossServerBehavior == 0)
|
||||
if (!CSSession.addCrossServerSession(ByteUtils.byteArrayToSafeStringHex(c.getSecretKeyBytes()), a, c.getSocketChannel()
|
||||
.socket().getInetAddress(), c.machineID))
|
||||
Logger.warn("Failed to create cross server session: " + a.getUname());
|
||||
|
||||
return ses;
|
||||
}
|
||||
|
||||
public static Session getNewSession(Account a, ClientConnection c) {
|
||||
SessionID sesID = c.getSessionID();
|
||||
return SessionManager.getNewSession(sesID, a, c);
|
||||
}
|
||||
|
||||
|
||||
public static void cSessionCleanup(String key) {
|
||||
if (!CSSession.deleteCrossServerSession(key))
|
||||
Logger.warn(
|
||||
"Failed to remove cross server session for key: " + key);
|
||||
}
|
||||
|
||||
public static void remSession(Session s) {
|
||||
|
||||
if (s == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SessionManager.remSessionID(s);
|
||||
SessionManager.remAccount(s);
|
||||
SessionManager.remClientConnection(s);
|
||||
SessionManager.remPlayerCharacter(s);
|
||||
|
||||
//TODO LATER fix
|
||||
s.setAccount(null);
|
||||
s.setConn(null);
|
||||
s.setPlayerCharacter(null);
|
||||
s.setSessionID(null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Sessions
|
||||
*/
|
||||
public static Session getSession(SessionID id) {
|
||||
return SessionManager.sessionIDtoSession.get(id);
|
||||
}
|
||||
|
||||
public static Session getSession(PlayerCharacter pc) {
|
||||
return SessionManager.pcToSession.get(pc);
|
||||
}
|
||||
|
||||
public static Session getSession(Account a) {
|
||||
return SessionManager.accountToSession.get(a);
|
||||
}
|
||||
|
||||
public static Session getSession(ClientConnection cc) {
|
||||
return SessionManager.connToSession.get(cc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Connections
|
||||
*/
|
||||
public static ClientConnection getClientConnection(SessionID id) {
|
||||
Session s = SessionManager.getSession(id);
|
||||
return (s == null) ? null : s.getConn();
|
||||
}
|
||||
|
||||
public static ClientConnection getClientConnection(PlayerCharacter pc) {
|
||||
Session s = SessionManager.getSession(pc);
|
||||
return (s == null) ? null : s.getConn();
|
||||
}
|
||||
|
||||
public static ClientConnection getClientConnection(Account a) {
|
||||
Session s = SessionManager.getSession(a);
|
||||
return (s == null) ? null : s.getConn();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get PlayerCharacter
|
||||
*/
|
||||
public static PlayerCharacter getPlayerCharacter(SessionID id) {
|
||||
Session s = SessionManager.getSession(id);
|
||||
return (s == null) ? null : s.getPlayerCharacter();
|
||||
}
|
||||
|
||||
public static PlayerCharacter getPlayerCharacter(ClientConnection conn) {
|
||||
Session s = SessionManager.getSession(conn);
|
||||
return (s == null) ? null : s.getPlayerCharacter();
|
||||
}
|
||||
|
||||
public static PlayerCharacter getPlayerCharacter(Account a) {
|
||||
Session s = SessionManager.getSession(a);
|
||||
return (s == null) ? null : s.getPlayerCharacter();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Account
|
||||
*/
|
||||
public static Account getAccount(SessionID id) {
|
||||
Session s = SessionManager.getSession(id);
|
||||
return (s == null) ? null : s.getAccount();
|
||||
}
|
||||
|
||||
public static Account getAccount(ClientConnection conn) {
|
||||
Session s = SessionManager.getSession(conn);
|
||||
return (s == null) ? null : s.getAccount();
|
||||
}
|
||||
|
||||
public static Account getAccount(PlayerCharacter pc) {
|
||||
Session s = SessionManager.getSession(pc);
|
||||
return (s == null) ? null : s.getAccount();
|
||||
}
|
||||
|
||||
public static void setPlayerCharacter(Session s, PlayerCharacter pc) {
|
||||
SessionManager.pcToSession.put(pc, s);
|
||||
s.setPlayerCharacter(pc);
|
||||
|
||||
// Update max player
|
||||
SessionManager._maxPopulation = Math.max(_maxPopulation, SessionManager.pcToSession.size());
|
||||
|
||||
}
|
||||
|
||||
public static void remPlayerCharacter(Session s) {
|
||||
if (s.getPlayerCharacter() != null) {
|
||||
SessionManager.pcToSession.remove(s.getPlayerCharacter());
|
||||
s.setPlayerCharacter(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void remAccount(Session s) {
|
||||
if (s.getAccount() != null) {
|
||||
SessionManager.accountToSession.remove(s.getAccount());
|
||||
s.setAccount(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void remSessionID(Session s) {
|
||||
|
||||
if (s.getSessionID() != null) {
|
||||
SessionManager.sessionIDtoSession.remove(s.getSessionID());
|
||||
s.setSessionID(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void remClientConnection(Session s) {
|
||||
if (s.getConn() != null) {
|
||||
SessionManager.connToSession.remove(s.getConn());
|
||||
s.setConn(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Utils
|
||||
*/
|
||||
|
||||
public static void setCrossServerBehavior(int type) {
|
||||
crossServerBehavior = type;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a new HashSet<ClientConnection> object so the caller cannot
|
||||
* modify the internal Set
|
||||
*/
|
||||
public static Collection<ClientConnection> getAllActiveClientConnections() {
|
||||
return SessionManager.connToSession.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a new HashSet<PlayerCharacter> object so the caller cannot modify
|
||||
* the internal Set
|
||||
*/
|
||||
public static Collection<PlayerCharacter> getAllActivePlayerCharacters() {
|
||||
|
||||
return SessionManager.pcToSession.keySet();
|
||||
}
|
||||
|
||||
public static Collection<PlayerCharacter> getAllActivePlayers() {
|
||||
|
||||
return SessionManager.pcToSession.keySet();
|
||||
}
|
||||
|
||||
public static int getActivePlayerCharacterCount() {
|
||||
|
||||
return SessionManager.pcToSession.keySet().size();
|
||||
}
|
||||
|
||||
public static ArrayList<PlayerCharacter> getActivePCsInGuildID(int id) {
|
||||
ArrayList<PlayerCharacter> pcs = new ArrayList<>();
|
||||
|
||||
for (PlayerCharacter pc : SessionManager.getAllActivePlayerCharacters()) {
|
||||
Guild g = pc.getGuild();
|
||||
if (g != null && g.getObjectUUID() == id) {
|
||||
pcs.add(pc);
|
||||
}
|
||||
}
|
||||
|
||||
return pcs;
|
||||
}
|
||||
|
||||
public static PlayerCharacter getPlayerCharacterByLowerCaseName(String name) {
|
||||
|
||||
String queryName = name.toLowerCase();
|
||||
|
||||
for (PlayerCharacter playerCharacter : SessionManager.getAllActivePlayerCharacters()) {
|
||||
|
||||
if ((playerCharacter.getFirstName().toLowerCase()).equals(queryName)) {
|
||||
return playerCharacter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PlayerCharacter getPlayerCharacterByID(int UUID) {
|
||||
|
||||
for (PlayerCharacter playerCharacter : SessionManager.getAllActivePlayerCharacters()) {
|
||||
|
||||
if (playerCharacter.getObjectUUID() == UUID) {
|
||||
return playerCharacter;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Collection<Account> getAllActiveAccounts() {
|
||||
return SessionManager.accountToSession.keySet();
|
||||
}
|
||||
|
||||
public static Account getAccountByID(int UUID) {
|
||||
|
||||
for (Account acc : SessionManager.getAllActiveAccounts()) {
|
||||
|
||||
if (acc.getObjectUUID() == UUID)
|
||||
return acc;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.Enum.GameObjectType;
|
||||
import engine.objects.AbstractGameObject;
|
||||
import engine.objects.City;
|
||||
import engine.objects.PlayerCharacter;
|
||||
import engine.objects.Runegate;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/*
|
||||
* This class contains all methods necessary to drive periodic
|
||||
* updates of the game simulation from the main _exec loop.
|
||||
*/
|
||||
public enum SimulationManager {
|
||||
|
||||
SERVERHEARTBEAT;
|
||||
|
||||
private static SimulationManager instance = null;
|
||||
|
||||
private static final long CITY_PULSE = 2000;
|
||||
private static final long RUNEGATE_PULSE = 3000;
|
||||
private static final long UPDATE_PULSE = 1000;
|
||||
private static final long FlIGHT_PULSE = 100;
|
||||
|
||||
private long _cityPulseTime = System.currentTimeMillis() + CITY_PULSE;
|
||||
private long _runegatePulseTime = System.currentTimeMillis()
|
||||
+ RUNEGATE_PULSE;
|
||||
private long _updatePulseTime = System.currentTimeMillis() + UPDATE_PULSE;
|
||||
private long _flightPulseTime = System.currentTimeMillis() + FlIGHT_PULSE;
|
||||
|
||||
public static long HeartbeatDelta = 0;
|
||||
public static long currentHeartBeatDelta = 0;
|
||||
|
||||
private SimulationManager() {
|
||||
|
||||
// don't allow instantiation.
|
||||
}
|
||||
|
||||
public static String getPopulationString() {
|
||||
String outString;
|
||||
String newLine = System.getProperty("line.separator");
|
||||
outString = "[LUA_POPULATION()]" + newLine;
|
||||
outString += DbManager.CSSessionQueries.GET_POPULATION_STRING();
|
||||
return outString;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the simulation. *** Important: Whatever you do in here, do it damn
|
||||
* quick!
|
||||
*/
|
||||
public void tick() {
|
||||
|
||||
/*
|
||||
* As we're on the main thread we must be sure to catch any possible
|
||||
* errors.
|
||||
*
|
||||
* IF something does occur, disable that particular heartbeat. Better
|
||||
* runegates stop working than the game itself!
|
||||
*/
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
if ((_flightPulseTime != 0)
|
||||
&& (System.currentTimeMillis() > _flightPulseTime))
|
||||
pulseFlight();
|
||||
} catch (Exception e) {
|
||||
Logger.error(
|
||||
"Fatal error in City Pulse: DISABLED. Error Message : "
|
||||
+ e.getMessage());
|
||||
}
|
||||
try {
|
||||
|
||||
if ((_updatePulseTime != 0)
|
||||
&& (System.currentTimeMillis() > _updatePulseTime))
|
||||
pulseUpdate();
|
||||
} catch (Exception e) {
|
||||
Logger.error(
|
||||
"Fatal error in Update Pulse: DISABLED");
|
||||
// _runegatePulseTime = 0;
|
||||
}
|
||||
|
||||
try {
|
||||
if ((_runegatePulseTime != 0)
|
||||
&& (System.currentTimeMillis() > _runegatePulseTime))
|
||||
pulseRunegates();
|
||||
} catch (Exception e) {
|
||||
Logger.error(
|
||||
"Fatal error in Runegate Pulse: DISABLED");
|
||||
_runegatePulseTime = 0;
|
||||
}
|
||||
|
||||
try {
|
||||
if ((_cityPulseTime != 0)
|
||||
&& (System.currentTimeMillis() > _cityPulseTime))
|
||||
pulseCities();
|
||||
} catch (Exception e) {
|
||||
Logger.error(
|
||||
"Fatal error in City Pulse: DISABLED. Error Message : "
|
||||
+ e.getMessage());
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
long delta = end - start;
|
||||
|
||||
if (delta > SimulationManager.HeartbeatDelta)
|
||||
SimulationManager.HeartbeatDelta = delta;
|
||||
|
||||
SimulationManager.currentHeartBeatDelta = delta;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Mainline simulation update method: handles movement and regen for all
|
||||
* player characters
|
||||
*/
|
||||
|
||||
private void pulseUpdate() {
|
||||
|
||||
Collection<AbstractGameObject> playerList;
|
||||
|
||||
playerList = DbManager.getList(GameObjectType.PlayerCharacter);
|
||||
|
||||
// Call update() on each player in game
|
||||
|
||||
if (playerList == null)
|
||||
return;
|
||||
|
||||
for (AbstractGameObject ago : playerList) {
|
||||
PlayerCharacter player = (PlayerCharacter)ago;
|
||||
|
||||
if (player == null)
|
||||
continue;
|
||||
player.update();
|
||||
}
|
||||
|
||||
_updatePulseTime = System.currentTimeMillis() + 500;
|
||||
}
|
||||
|
||||
private void pulseFlight() {
|
||||
|
||||
Collection<AbstractGameObject> playerList;
|
||||
|
||||
playerList = DbManager.getList(GameObjectType.PlayerCharacter);
|
||||
|
||||
// Call update() on each player in game
|
||||
|
||||
if (playerList == null)
|
||||
return;
|
||||
|
||||
for (AbstractGameObject ago : playerList) {
|
||||
PlayerCharacter player = (PlayerCharacter)ago;
|
||||
|
||||
if (player == null)
|
||||
continue;
|
||||
|
||||
|
||||
player.updateFlight();
|
||||
}
|
||||
|
||||
_flightPulseTime = System.currentTimeMillis() + FlIGHT_PULSE;
|
||||
}
|
||||
|
||||
private void pulseCities() {
|
||||
|
||||
City city;
|
||||
|
||||
// *** Refactor: Need a list cached somewhere as it doesn't change very
|
||||
// often at all. Have a cityListIsDirty boolean that gets set if it
|
||||
// needs an update. Will speed up this method a great deal.
|
||||
|
||||
Collection<AbstractGameObject> cityList = DbManager.getList(Enum.GameObjectType.City);
|
||||
|
||||
if (cityList == null) {
|
||||
Logger.info( "City List null");
|
||||
return;
|
||||
}
|
||||
|
||||
for (AbstractGameObject cityObject : cityList) {
|
||||
city = (City) cityObject;
|
||||
city.onEnter();
|
||||
}
|
||||
|
||||
_cityPulseTime = System.currentTimeMillis() + CITY_PULSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Method runs proximity collision detection for all active portals on the
|
||||
* game's Runegates
|
||||
*/
|
||||
private void pulseRunegates() {
|
||||
|
||||
for (Runegate runegate : Runegate.getRunegates()) {
|
||||
runegate.collidePortals();
|
||||
}
|
||||
|
||||
_runegatePulseTime = System.currentTimeMillis() + RUNEGATE_PULSE;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.net.Dispatch;
|
||||
import engine.net.DispatchMessage;
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.net.client.msg.*;
|
||||
import engine.objects.CharacterItemManager;
|
||||
import engine.objects.PlayerCharacter;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
public enum TradeManager {
|
||||
|
||||
TRADEMANAGER;
|
||||
|
||||
public static void tradeRequest(TradeRequestMsg msg, ClientConnection origin) {
|
||||
|
||||
PlayerCharacter source = origin.getPlayerCharacter();
|
||||
|
||||
if (source == null)
|
||||
return;
|
||||
|
||||
source.getCharItemManager().tradeRequest(msg);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void acceptTradeRequest(AcceptTradeRequestMsg msg, ClientConnection origin) {
|
||||
|
||||
PlayerCharacter source = origin.getPlayerCharacter();
|
||||
|
||||
if (source == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
source.getCharItemManager().acceptTradeRequest(msg);
|
||||
} catch (Exception e) {
|
||||
Logger.error(e);
|
||||
// TODO Auto-generated catch block
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void rejectTradeRequest(RejectTradeRequestMsg msg, ClientConnection origin) {
|
||||
// TODO Do nothing? If so, delete this method & case above
|
||||
}
|
||||
|
||||
public static void addItemToTradeWindow(AddItemToTradeWindowMsg msg, ClientConnection origin) {
|
||||
|
||||
|
||||
PlayerCharacter source = origin.getPlayerCharacter();
|
||||
if (source == null || !source.isAlive())
|
||||
return;
|
||||
try{
|
||||
source.getCharItemManager().addItemToTradeWindow(msg);
|
||||
|
||||
}catch(Exception e){
|
||||
Logger.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void addGoldToTradeWindow(AddGoldToTradeWindowMsg msg, ClientConnection origin) {
|
||||
|
||||
PlayerCharacter source = origin.getPlayerCharacter();
|
||||
|
||||
if (source == null || !source.isAlive())
|
||||
return;
|
||||
|
||||
|
||||
|
||||
CharacterItemManager sourceItemMan = source.getCharItemManager();
|
||||
|
||||
if (sourceItemMan == null)
|
||||
return;
|
||||
|
||||
try{
|
||||
sourceItemMan.addGoldToTradeWindow(msg);
|
||||
}catch(Exception e){
|
||||
Logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void commitToTrade(CommitToTradeMsg msg, ClientConnection origin) {
|
||||
|
||||
PlayerCharacter source = origin.getPlayerCharacter();
|
||||
|
||||
if (source == null || !source.isAlive())
|
||||
return;
|
||||
|
||||
CharacterItemManager sourceItemMan = source.getCharItemManager();
|
||||
|
||||
if (sourceItemMan == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
sourceItemMan.commitToTrade(msg);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
Logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void uncommitToTrade(UncommitToTradeMsg msg, ClientConnection origin) {
|
||||
|
||||
PlayerCharacter source = origin.getPlayerCharacter();
|
||||
|
||||
if (source == null || !source.isAlive())
|
||||
return;
|
||||
|
||||
CharacterItemManager sourceItemMan = source.getCharItemManager();
|
||||
|
||||
if (sourceItemMan == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
sourceItemMan.uncommitToTrade(msg);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
Logger.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void closeTradeWindow(CloseTradeWindowMsg msg, ClientConnection origin) {
|
||||
|
||||
PlayerCharacter source = origin.getPlayerCharacter();
|
||||
|
||||
if (source == null)
|
||||
return;
|
||||
|
||||
CharacterItemManager sourceItemMan = source.getCharItemManager();
|
||||
|
||||
if (sourceItemMan == null)
|
||||
return;
|
||||
|
||||
try {
|
||||
sourceItemMan.closeTradeWindow(msg, true);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
Logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void invalidTradeRequest(InvalidTradeRequestMsg msg) {
|
||||
PlayerCharacter requester = PlayerCharacter.getFromCache(msg.getRequesterID());
|
||||
Dispatch dispatch;
|
||||
|
||||
dispatch = Dispatch.borrow(requester, msg);
|
||||
DispatchMessage.dispatchMsgDispatch(dispatch, Enum.DispatchChannel.SECONDARY);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.Vector2f;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.objects.Building;
|
||||
import engine.objects.City;
|
||||
import engine.objects.Zone;
|
||||
import engine.server.MBServerStatics;
|
||||
import engine.server.world.WorldServer;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/*
|
||||
* Class contains methods and structures which
|
||||
* track in-game Zones
|
||||
*/
|
||||
public enum ZoneManager {
|
||||
|
||||
ZONEMANAGER;
|
||||
|
||||
/* Instance variables */
|
||||
private static Zone seaFloor = null;
|
||||
private static Zone hotzone = null;
|
||||
private static ConcurrentHashMap<Integer, Zone> zonesByID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD);
|
||||
private static ConcurrentHashMap<Integer, Zone> zonesByUUID = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD);
|
||||
private static ConcurrentHashMap<String, Zone> zonesByName = new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD);
|
||||
private static Set<Zone> macroZones = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private static Set<Zone> npcCityZones = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private static Set<Zone> playerCityZones = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
// Find all zones coordinates fit into, starting with Sea Floor
|
||||
|
||||
public static ArrayList<Zone> getAllZonesIn(final Vector3fImmutable loc) {
|
||||
|
||||
ArrayList<Zone> allIn = new ArrayList<>();
|
||||
Zone zone;
|
||||
|
||||
zone = ZoneManager.findSmallestZone(loc);
|
||||
|
||||
if (zone != null) {
|
||||
allIn.add(zone);
|
||||
while (zone.getParent() != null) {
|
||||
zone = zone.getParent();
|
||||
allIn.add(zone);
|
||||
}
|
||||
}
|
||||
return allIn;
|
||||
}
|
||||
|
||||
// Find smallest zone coordinates fit into.
|
||||
|
||||
public static final Zone findSmallestZone(final Vector3fImmutable loc) {
|
||||
|
||||
Zone zone = ZoneManager.seaFloor;
|
||||
|
||||
if (zone == null)
|
||||
return null;
|
||||
|
||||
boolean childFound = true;
|
||||
|
||||
while (childFound) {
|
||||
|
||||
childFound = false;
|
||||
|
||||
ArrayList<Zone> nodes = zone.getNodes();
|
||||
|
||||
// Logger.info("soze", "" + nodes.size());
|
||||
if (nodes != null)
|
||||
for (Zone child : nodes) {
|
||||
|
||||
if (Bounds.collide(loc, child.getBounds()) == true) {
|
||||
zone = child;
|
||||
childFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return zone;
|
||||
}
|
||||
|
||||
public static void addZone(final int zoneID, final Zone zone) {
|
||||
|
||||
ZoneManager.zonesByID.put(zoneID, zone);
|
||||
|
||||
if (zone != null)
|
||||
ZoneManager.zonesByUUID.put(zone.getObjectUUID(), zone);
|
||||
|
||||
ZoneManager.zonesByName.put(zone.getName().toLowerCase(), zone);
|
||||
|
||||
}
|
||||
|
||||
public static Zone getZoneByUUID(final int zoneUUID) {
|
||||
return ZoneManager.zonesByUUID.get(zoneUUID);
|
||||
}
|
||||
|
||||
public static Zone getZoneByZoneID(final int zoneID) {
|
||||
|
||||
return ZoneManager.zonesByID.get(zoneID);
|
||||
}
|
||||
|
||||
public static final Collection<Zone> getAllZones() {
|
||||
return ZoneManager.zonesByUUID.values();
|
||||
}
|
||||
|
||||
public static final Zone getHotZone() {
|
||||
return ZoneManager.hotzone;
|
||||
}
|
||||
|
||||
public static final void setHotZone(final Zone zone) {
|
||||
if (!zone.isMacroZone())
|
||||
return;
|
||||
ZoneManager.hotzone = zone;
|
||||
}
|
||||
|
||||
public static boolean inHotZone(final Vector3fImmutable loc) {
|
||||
|
||||
if (ZoneManager.hotzone == null)
|
||||
return false;
|
||||
|
||||
return (Bounds.collide(loc, ZoneManager.hotzone.getBounds()) == true);
|
||||
}
|
||||
|
||||
public static void setSeaFloor(final Zone value) {
|
||||
ZoneManager.seaFloor = value;
|
||||
}
|
||||
|
||||
public static Zone getSeaFloor() {
|
||||
return ZoneManager.seaFloor;
|
||||
}
|
||||
|
||||
public static final void populateWorldZones(final Zone zone) {
|
||||
|
||||
int loadNum = zone.getLoadNum();
|
||||
|
||||
// Zones are added to separate
|
||||
// collections for quick access
|
||||
// based upon their type.
|
||||
|
||||
if (zone.isMacroZone()) {
|
||||
addMacroZone(zone);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (zone.isPlayerCity()) {
|
||||
addPlayerCityZone(zone);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zone.isNPCCity())
|
||||
addNPCCityZone(zone);
|
||||
|
||||
}
|
||||
|
||||
private static void addMacroZone(final Zone zone) {
|
||||
ZoneManager.macroZones.add(zone);
|
||||
}
|
||||
|
||||
private static void addNPCCityZone(final Zone zone) {
|
||||
zone.setNPCCity(true);
|
||||
ZoneManager.npcCityZones.add(zone);
|
||||
}
|
||||
|
||||
public static final void addPlayerCityZone(final Zone zone) {
|
||||
zone.setPlayerCity(true);
|
||||
ZoneManager.playerCityZones.add(zone);
|
||||
}
|
||||
|
||||
public static final void generateAndSetRandomHotzone() {
|
||||
|
||||
Zone hotzone;
|
||||
ArrayList<Integer> zoneArray = new ArrayList<>();
|
||||
|
||||
if (ZoneManager.macroZones.isEmpty())
|
||||
return;
|
||||
|
||||
for (Zone zone : ZoneManager.macroZones) {
|
||||
|
||||
if (validHotZone(zone))
|
||||
zoneArray.add(zone.getObjectUUID());
|
||||
|
||||
}
|
||||
|
||||
int entryIndex = ThreadLocalRandom.current().nextInt(zoneArray.size());
|
||||
|
||||
hotzone = ZoneManager.getZoneByUUID(zoneArray.get(entryIndex));
|
||||
|
||||
|
||||
if (hotzone == null){
|
||||
Logger.error( "Hotzone is null");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ZoneManager.setHotZone(hotzone);
|
||||
WorldServer.setLastHZChange(System.currentTimeMillis());
|
||||
|
||||
}
|
||||
|
||||
public static final boolean validHotZone(Zone zone) {
|
||||
|
||||
if (zone.getSafeZone() == (byte) 1)
|
||||
return false; // no safe zone hotzones// if (this.hotzone == null)
|
||||
|
||||
if (zone.getNodes().isEmpty())
|
||||
return false;
|
||||
|
||||
if (zone.equals(ZoneManager.seaFloor))
|
||||
return false;
|
||||
|
||||
// return false; //first time setting, accept it
|
||||
// if (this.hotzone.getUUID() == zone.getUUID())
|
||||
// return true; //no same hotzone
|
||||
|
||||
if (ZoneManager.hotzone != null)
|
||||
return ZoneManager.hotzone.getObjectUUID() != zone.getObjectUUID();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a MacroZone by name.
|
||||
*
|
||||
* @param inputName
|
||||
* MacroZone name to search for
|
||||
* @return Zone of the MacroZone, or Null
|
||||
*/
|
||||
|
||||
public static Zone findMacroZoneByName(String inputName) {
|
||||
synchronized (ZoneManager.macroZones) {
|
||||
for (Zone zone : ZoneManager.macroZones) {
|
||||
String zoneName = zone.getName();
|
||||
if (zoneName.equalsIgnoreCase(inputName))
|
||||
return zone;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Converts world coordinates to coordinates local to a given zone.
|
||||
|
||||
public static Vector3fImmutable worldToLocal(Vector3fImmutable worldVector,
|
||||
Zone serverZone) {
|
||||
|
||||
Vector3fImmutable localCoords;
|
||||
|
||||
localCoords = new Vector3fImmutable(worldVector.x - serverZone.absX,
|
||||
worldVector.y - serverZone.absY, worldVector.z
|
||||
- serverZone.absZ);
|
||||
|
||||
return localCoords;
|
||||
}
|
||||
|
||||
public static Vector2f worldToZoneSpace(Vector3fImmutable worldVector,
|
||||
Zone serverZone) {
|
||||
|
||||
Vector2f localCoords;
|
||||
Vector2f zoneOrigin;
|
||||
|
||||
// Top left corner of zone is calculated in world space by the center and it's extents.
|
||||
|
||||
zoneOrigin = new Vector2f(serverZone.getLoc().x, serverZone.getLoc().z);
|
||||
zoneOrigin = zoneOrigin.subtract(new Vector2f(serverZone.getBounds().getHalfExtents().x, serverZone.getBounds().getHalfExtents().y));
|
||||
|
||||
// Local coordinate in world space translated to an offset from the calculated zone origin.
|
||||
|
||||
localCoords = new Vector2f(worldVector.x, worldVector.z);
|
||||
localCoords = localCoords.subtract(zoneOrigin);
|
||||
|
||||
localCoords.setY((serverZone.getBounds().getHalfExtents().y * 2) - localCoords.y);
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO : Make sure this value does not go outside the zone's bounds.
|
||||
|
||||
return localCoords;
|
||||
}
|
||||
|
||||
// Converts local zone coordinates to world coordinates
|
||||
|
||||
public static Vector3fImmutable localToWorld(Vector3fImmutable worldVector,
|
||||
Zone serverZone) {
|
||||
|
||||
Vector3fImmutable worldCoords;
|
||||
|
||||
worldCoords = new Vector3fImmutable(worldVector.x + serverZone.absX,
|
||||
worldVector.y + serverZone.absY, worldVector.z
|
||||
+ serverZone.absZ);
|
||||
|
||||
return worldCoords;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts from local (relative to this building) to world.
|
||||
*
|
||||
* @param localPos position in local reference (relative to this building)
|
||||
* @return position relative to world
|
||||
*/
|
||||
|
||||
public static Vector3fImmutable convertLocalToWorld(Building building, Vector3fImmutable localPos) {
|
||||
|
||||
// convert from SB rotation value to radians
|
||||
|
||||
|
||||
if (building.getBounds().getQuaternion() == null)
|
||||
return building.getLoc();
|
||||
Vector3fImmutable rotatedLocal = Vector3fImmutable.rotateAroundPoint(Vector3fImmutable.ZERO, localPos, building.getBounds().getQuaternion());
|
||||
// handle building rotation
|
||||
// handle building translation
|
||||
|
||||
return building.getLoc().add(rotatedLocal.x, rotatedLocal.y,rotatedLocal.z);
|
||||
}
|
||||
|
||||
|
||||
//used for regions, Building bounds not set yet.
|
||||
public static Vector3f convertLocalToWorld(Building building, Vector3f localPos, Bounds bounds) {
|
||||
|
||||
// convert from SB rotation value to radians
|
||||
|
||||
|
||||
Vector3f rotatedLocal = Vector3f.rotateAroundPoint(Vector3f.ZERO, localPos, bounds.getQuaternion());
|
||||
// handle building rotation
|
||||
// handle building translation
|
||||
|
||||
return new Vector3f(building.getLoc().add(rotatedLocal.x, rotatedLocal.y,rotatedLocal.z));
|
||||
}
|
||||
|
||||
public static Vector3fImmutable convertWorldToLocal(Building building, Vector3fImmutable WorldPos) {
|
||||
Vector3fImmutable convertLoc = Vector3fImmutable.rotateAroundPoint(building.getLoc(),WorldPos,-building.getBounds().getQuaternion().angleY);
|
||||
|
||||
|
||||
convertLoc = convertLoc.subtract(building.getLoc());
|
||||
|
||||
// convert from SB rotation value to radians
|
||||
|
||||
return convertLoc;
|
||||
|
||||
}
|
||||
|
||||
public static Vector3fImmutable convertNPCLoc(Building building, Vector3fImmutable npcLoc) {
|
||||
|
||||
return Vector3fImmutable.rotateAroundPoint(Vector3fImmutable.ZERO, npcLoc, -building.getBounds().getQuaternion().angleY);
|
||||
|
||||
}
|
||||
|
||||
// Method returns a city if the given location is within
|
||||
// a city siege radius.
|
||||
|
||||
public static City getCityAtLocation(Vector3fImmutable worldLoc) {
|
||||
|
||||
Zone currentZone;
|
||||
ArrayList<Zone> zoneList;
|
||||
City city;
|
||||
|
||||
currentZone = ZoneManager.findSmallestZone(worldLoc);
|
||||
|
||||
if (currentZone.isPlayerCity())
|
||||
return City.getCity(currentZone.getPlayerCityUUID());
|
||||
|
||||
// Not currently on a city grid. Test nearby cities
|
||||
// to see if we are on one of their seige bounds.
|
||||
|
||||
zoneList = currentZone.getNodes();
|
||||
|
||||
for (Zone zone : zoneList) {
|
||||
|
||||
if (zone == currentZone)
|
||||
continue;
|
||||
|
||||
if (zone.isPlayerCity() == false)
|
||||
continue;
|
||||
|
||||
city = City.getCity(zone.getPlayerCityUUID());
|
||||
|
||||
if (worldLoc.isInsideCircle(city.getLoc(), Enum.CityBoundsType.SIEGE.extents))
|
||||
return city;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Method is called when creating a new player city to
|
||||
* validate that the new zone does not overlap any other
|
||||
* zone that might currently exist
|
||||
*/
|
||||
|
||||
public static boolean validTreePlacementLoc(Zone currentZone, float positionX, float positionZ) {
|
||||
|
||||
// Member Variable declaration
|
||||
|
||||
ArrayList<Zone> zoneList;
|
||||
boolean validLocation = true;
|
||||
Bounds treeBounds;
|
||||
|
||||
if (currentZone.isContininent() == false)
|
||||
return false;
|
||||
|
||||
|
||||
treeBounds = Bounds.borrow();
|
||||
treeBounds.setBounds(new Vector2f(positionX, positionZ), new Vector2f(Enum.CityBoundsType.SIEGE.extents, Enum.CityBoundsType.SIEGE.extents), 0.0f);
|
||||
|
||||
zoneList = currentZone.getNodes();
|
||||
|
||||
|
||||
|
||||
for (Zone zone : zoneList) {
|
||||
|
||||
if (zone.isContininent())
|
||||
continue;
|
||||
|
||||
if (Bounds.collide(treeBounds, zone.getBounds(), 0.0f))
|
||||
validLocation = false;
|
||||
}
|
||||
|
||||
treeBounds.release();
|
||||
return validLocation;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user