Initial Repository Push

This commit is contained in:
2022-04-30 09:41:17 -04:00
parent d4eef9097a
commit bbfdde57a3
835 changed files with 168392 additions and 0 deletions
+636
View File
@@ -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
+113
View File
@@ -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); }
}
+314
View File
@@ -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();
}
+228
View File
@@ -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;
}
}
+393
View File
@@ -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;
}
}
+206
View File
@@ -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!");
}
}
+650
View File
@@ -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
+289
View File
@@ -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;
}
}
+163
View File
@@ -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);
}
}
+437
View File
@@ -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;
}
}