forked from MagicBane/Server
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a0e8782af | |||
| 63fa98486b | |||
| 2ca54f3cfa | |||
| dad615db2b | |||
| 134838072d | |||
| 6484e7eb93 | |||
| 32d71d72d1 | |||
| db015f7007 | |||
| a0066bce20 | |||
| 8c2adb760c | |||
| 8aca1a1810 | |||
| 2d4a604709 | |||
| 7b3741fc60 | |||
| 903470e7ae | |||
| 0e190b21e1 | |||
| b6be8815a3 | |||
| d8235954d2 | |||
| 37ca8c90e2 | |||
| b70a076cb2 |
@@ -25,7 +25,6 @@ public class Terrain {
|
||||
public Vector2f cell_size = new Vector2f();
|
||||
public Vector2f cell_count = new Vector2f();
|
||||
public float terrain_scale;
|
||||
public Vector2f blend_values = new Vector2f();
|
||||
public Vector2f blend_ratio = new Vector2f();
|
||||
public int heightmap;
|
||||
Zone zone;
|
||||
@@ -63,14 +62,22 @@ public class Terrain {
|
||||
// the blending area between child and parent terrains when
|
||||
// they are stitched together.
|
||||
|
||||
this.blend_values.x = this.zone.template.max_blend;
|
||||
this.blend_values.y = this.zone.template.min_blend;
|
||||
float max_blend = this.zone.template.max_blend;
|
||||
float min_blend = this.zone.template.min_blend;
|
||||
|
||||
Vector2f major_blend = new Vector2f(this.blend_values.x / this.zone.major_radius,
|
||||
this.blend_values.y / this.zone.major_radius);
|
||||
// Zones with a zero blend inherit from their parent terrain
|
||||
|
||||
Vector2f minor_blend = new Vector2f(this.blend_values.x / this.zone.minor_radius,
|
||||
this.blend_values.y / this.zone.minor_radius);
|
||||
if (this.zone.template.max_blend == 0) {
|
||||
Zone parentZone = this.getNextZoneWithTerrain(this.zone.parent);
|
||||
max_blend = parentZone.template.max_blend;
|
||||
min_blend = parentZone.template.min_blend;
|
||||
}
|
||||
|
||||
Vector2f major_blend = new Vector2f(max_blend / this.zone.major_radius,
|
||||
min_blend / this.zone.major_radius);
|
||||
|
||||
Vector2f minor_blend = new Vector2f(max_blend / this.zone.minor_radius,
|
||||
min_blend / this.zone.minor_radius);
|
||||
|
||||
if (major_blend.y > 0.4f)
|
||||
blend_ratio.x = major_blend.y;
|
||||
|
||||
@@ -20,7 +20,6 @@ import engine.objects.*;
|
||||
import org.joda.time.DateTime;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.awt.geom.Path2D;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
@@ -549,51 +548,6 @@ public class dbBuildingHandler extends dbHandlerBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void LOAD_MESH_HULLS() {
|
||||
|
||||
int recordsRead = 0;
|
||||
|
||||
try (Connection connection = DbManager.getConnection();
|
||||
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM static_convex_hulls")) {
|
||||
|
||||
ResultSet rs = preparedStatement.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
|
||||
recordsRead++;
|
||||
|
||||
int propID = rs.getInt("propID");
|
||||
String[] HullStrings = rs.getString("vertices").split(";");
|
||||
|
||||
// Filter things that couldn't be wrapped
|
||||
|
||||
if (HullStrings.length < 3) {
|
||||
Logger.error("Prop : " + propID + " has less than 3 vertices.");
|
||||
continue;
|
||||
}
|
||||
|
||||
Path2D.Float prop_path = BuildingManager.hullToPath2d(HullStrings);
|
||||
|
||||
ArrayList<Path2D.Float> meshList;
|
||||
|
||||
if (BuildingManager._hull_data.get(propID) == null) {
|
||||
meshList = new ArrayList<>();
|
||||
meshList.add(prop_path);
|
||||
BuildingManager._hull_data.put(propID, meshList);
|
||||
|
||||
} else {
|
||||
meshList = BuildingManager._hull_data.get(propID);
|
||||
meshList.add(prop_path);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
Logger.error(e);
|
||||
}
|
||||
|
||||
Logger.info("read: " + recordsRead + " cached: " + BuildingManager._hull_data.size());
|
||||
}
|
||||
|
||||
public HashMap<Integer, ArrayList<BuildingRegions>> LOAD_BUILDING_REGIONS() {
|
||||
|
||||
HashMap<Integer, ArrayList<BuildingRegions>> regionList = new HashMap<>();
|
||||
|
||||
@@ -49,33 +49,19 @@ public class GetHeightCmd extends AbstractDevCmd {
|
||||
|
||||
float blendedHeight = Terrain.getWorldHeight(currentZone, playerCharacter.getLoc());
|
||||
|
||||
Vector2f terrainCell = heightmapZone.terrain.getTerrainCell(childZoneLoc);
|
||||
Vector2f cell_offset = new Vector2f(terrainCell.x % 1, terrainCell.y % 1);
|
||||
|
||||
terrainCell.x = (float) Math.floor(terrainCell.x);
|
||||
terrainCell.y = (float) Math.floor(terrainCell.y);
|
||||
|
||||
|
||||
short top_left_pixel = heightmapZone.terrain.terrain_pixel_data[(int) terrainCell.x][(int) terrainCell.y];
|
||||
short top_right_pixel = heightmapZone.terrain.terrain_pixel_data[(int) terrainCell.x + 1][(int) terrainCell.y];
|
||||
short bottom_left_pixel = heightmapZone.terrain.terrain_pixel_data[(int) terrainCell.x][(int) terrainCell.y + 1];
|
||||
short bottom_right_pixel = heightmapZone.terrain.terrain_pixel_data[(int) terrainCell.x + 1][(int) terrainCell.y + 1];
|
||||
Vector2f gridSquare = heightmapZone.terrain.getTerrainCell(childZoneLoc);
|
||||
gridSquare.x = (float) Math.floor(gridSquare.x);
|
||||
gridSquare.y = (float) Math.floor(gridSquare.y);
|
||||
|
||||
this.throwbackInfo(playerCharacter, "Current Zone : " + currentZone.zoneName);
|
||||
this.throwbackInfo(playerCharacter, "Heightmap Zone : " + heightmapZone.zoneName);
|
||||
this.throwbackInfo(playerCharacter, "Parent Zone: " + parentZone.zoneName);
|
||||
|
||||
this.throwbackInfo(playerCharacter, "Player loc: " + "[" + playerCharacter.loc.x + "]" + "[" + playerCharacter.loc.y + "]" + "[" + playerCharacter.loc.z + "]");
|
||||
|
||||
this.throwbackInfo(playerCharacter, "Terrain Cell : " + "[" + terrainCell.x + "]" + "[" + terrainCell.y + "]");
|
||||
this.throwbackInfo(playerCharacter, "Cell Offset : " + "[" + cell_offset.x + "]" + "[" + cell_offset.y + "]");
|
||||
this.throwbackInfo(playerCharacter, "Pixels : " + "[" + top_left_pixel + "]" + "[" + top_right_pixel + "]");
|
||||
this.throwbackInfo(playerCharacter, "Pixels : " + "[" + bottom_left_pixel + "]" + "[" + bottom_right_pixel + "]");
|
||||
|
||||
this.throwbackInfo(playerCharacter, "Child Zone Offset: " + "[" + childZoneOffset.x + "]" + "[" + childZoneOffset.y + "]");
|
||||
this.throwbackInfo(playerCharacter, "Grid : " + "[" + gridSquare.x + "]" + "[" + gridSquare.y + "]");
|
||||
this.throwbackInfo(playerCharacter, "offset: " + "[" + childZoneOffset.x + "]" + "[" + childZoneOffset.y + "]");
|
||||
this.throwbackInfo(playerCharacter, "Normalized offset: " + "[" + normalizedOffset.x + "]" + "[" + normalizedOffset.y + "]");
|
||||
this.throwbackInfo(playerCharacter, "template blend Values: (max/min): " + heightmapZone.template.max_blend + " /" + heightmapZone.template.min_blend);
|
||||
this.throwbackInfo(playerCharacter, "terrain values (max/min): " + heightmapZone.terrain.blend_values.x + " /" + heightmapZone.terrain.blend_values.y);
|
||||
this.throwbackInfo(playerCharacter, "Heightmap blend Values: max/min" + heightmapZone.template.min_blend + " /" + heightmapZone.template.max_blend);
|
||||
this.throwbackInfo(playerCharacter, "Parent blend Values: nax/min" + parentZone.template.min_blend + " /" + parentZone.template.max_blend);
|
||||
this.throwbackInfo(playerCharacter, "Blend coefficient: " + heightmapZone.terrain.getTerrainBlendCoefficient(childZoneOffset));
|
||||
|
||||
this.throwbackInfo(playerCharacter, "------------");
|
||||
|
||||
@@ -12,22 +12,10 @@ package engine.devcmd.cmds;
|
||||
import engine.Enum;
|
||||
import engine.devcmd.AbstractDevCmd;
|
||||
import engine.gameManager.BuildingManager;
|
||||
import engine.gameManager.NavigationManager;
|
||||
import engine.gameManager.ZoneManager;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.objects.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static java.awt.geom.Path2D.WIND_EVEN_ODD;
|
||||
import static java.awt.geom.Path2D.WIND_NON_ZERO;
|
||||
|
||||
public class RegionCmd extends AbstractDevCmd {
|
||||
|
||||
public RegionCmd() {
|
||||
@@ -47,28 +35,20 @@ public class RegionCmd extends AbstractDevCmd {
|
||||
this.throwbackInfo(pc, "No Building At This Location.") ;
|
||||
}
|
||||
Regions region = ((AbstractCharacter)target).region;
|
||||
output += "In Floor: " + ((AbstractCharacter) target).getInFloorID() + newline;
|
||||
output += "In Building: " + ((AbstractCharacter) target).getInBuilding() + newline;
|
||||
if (region == null) {
|
||||
output += "No Region Found." + newline;
|
||||
}else{
|
||||
this.throwbackInfo(pc, "No Region Found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(region != null) {
|
||||
output += "Player Info: " + ((AbstractCharacter) target).getName() + newline;
|
||||
output += "Region Building: " + building.getName() + newline;
|
||||
output += "Region Height: " + region.lerpY(((AbstractCharacter)target).loc) + newline;
|
||||
output += "Region Height: " + region.lerpY((AbstractCharacter)target) + newline;
|
||||
output += "is Stairs: " + region.isStairs() + newline;
|
||||
output += "is Outside: " + region.isOutside() + newline;
|
||||
output += "is Entrance: " + region.isExit() + newline;
|
||||
for(Vector3f point : region.regionPoints)
|
||||
output += point + newline;
|
||||
output += "NavMesh Data" + newline;
|
||||
output += "is Outside: " + region.isOutside();
|
||||
this.throwbackInfo(pc, output);
|
||||
}
|
||||
output += "pointBlocked: " + NavigationManager.pointIsBlocked(((AbstractCharacter)target).loc);
|
||||
|
||||
|
||||
|
||||
|
||||
this.throwbackInfo(pc, output);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,9 +13,7 @@ import engine.Enum;
|
||||
import engine.Enum.GameObjectType;
|
||||
import engine.devcmd.AbstractDevCmd;
|
||||
import engine.gameManager.PowersManager;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.MobAI;
|
||||
import engine.mobileAI.utilities.PathingUtilities;
|
||||
import engine.objects.AbstractGameObject;
|
||||
import engine.objects.Mob;
|
||||
import engine.objects.PlayerCharacter;
|
||||
@@ -152,10 +150,7 @@ public class aiInfoCmd extends AbstractDevCmd {
|
||||
for (Integer outlawUUID : outlaws)
|
||||
output += outlawUUID + newline;
|
||||
}
|
||||
output += "Walking: " + ((Mob) target).isMoving() + newline;
|
||||
output += "Destination: " + ((Mob) target).destination + newline;
|
||||
output += "is Pathing: " + mob.isPathing + newline;
|
||||
((Mob) target).isPathing = false;
|
||||
|
||||
throwbackInfo(playerCharacter, output);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@ import engine.job.JobContainer;
|
||||
import engine.job.JobScheduler;
|
||||
import engine.jobs.UpgradeBuildingJob;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.Vector2f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.utilities.PathingUtilities;
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.net.client.msg.ErrorPopupMsg;
|
||||
import engine.net.client.msg.ManageCityAssetsMsg;
|
||||
@@ -29,8 +27,6 @@ import engine.objects.*;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
@@ -42,14 +38,12 @@ public enum BuildingManager {
|
||||
|
||||
BUILDINGMANAGER;
|
||||
|
||||
public static HashMap<Integer, ArrayList<Path2D.Float>> _hull_data = new HashMap<>();
|
||||
public static HashMap<Integer, ArrayList<BuildingLocation>> _stuckLocations = new HashMap<>();
|
||||
public static HashMap<Integer, ArrayList<BuildingLocation>> _slotLocations = new HashMap<>();
|
||||
|
||||
public static HashMap<Integer, ConcurrentHashMap<Integer, BuildingFriends>> _buildingFriends = new HashMap<>();
|
||||
public static HashMap<Integer, ConcurrentHashMap<Integer, Condemned>> _buildingCondemned = new HashMap<>();
|
||||
public static HashMap<Integer, ArrayList<Vector3fImmutable>> _buildingPatrolPoints = new HashMap<>();
|
||||
|
||||
public static int getAvailableSlot(Building building) {
|
||||
|
||||
ArrayList<BuildingLocation> slotLocations = _slotLocations.get(building.meshUUID);
|
||||
@@ -146,7 +140,10 @@ public enum BuildingManager {
|
||||
if (Guild.sameGuild(building.getGuild(), player.getGuild()) && GuildStatusController.isInnerCouncil(player.getGuildStatus()))
|
||||
return true;
|
||||
|
||||
return Guild.sameGuild(building.getGuild(), player.getGuild()) && GuildStatusController.isGuildLeader(player.getGuildStatus());
|
||||
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.
|
||||
@@ -963,101 +960,4 @@ public enum BuildingManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void bakeNavMesh(Building building) {
|
||||
|
||||
if (building.parentZone == null) {
|
||||
//Logger.error("Attempt to bake navmesh with no parent: " + building.getObjectUUID());
|
||||
return;
|
||||
}
|
||||
|
||||
// Build up navmesh by stencil of the
|
||||
// convex hull meshes that comprise the prop.
|
||||
|
||||
ArrayList<Path2D.Float> convexHullList;
|
||||
convexHullList = _hull_data.get(building.meshUUID);
|
||||
|
||||
if (convexHullList == null) {
|
||||
//Logger.error("Attempt to bake navmesh with no meshes: " + building.getObjectUUID());
|
||||
return;
|
||||
}
|
||||
|
||||
//add navNodes to parent zone list
|
||||
float X = building.getBounds().getHalfExtents().x;
|
||||
float Y = building.getBounds().getHalfExtents().y;
|
||||
ArrayList<Vector2f> cornersAndFaces = new ArrayList<>();
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x - X, building.loc.z - Y));
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x + X, building.loc.z + Y));
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x + X, building.loc.z - Y));
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x - X, building.loc.z + Y));
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x - X, building.loc.z));
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x + X, building.loc.z));
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x, building.loc.z - Y));
|
||||
cornersAndFaces.add(new Vector2f(building.loc.x, building.loc.z + Y));
|
||||
for (Vector2f point : cornersAndFaces) {
|
||||
if (!NavigationManager.pointIsBlocked(new Vector3fImmutable(point.x, building.loc.y, point.y))) {
|
||||
building.parentZone.navNodes.add(new PathingUtilities.Node(point, null, building));
|
||||
}
|
||||
}
|
||||
|
||||
//add region centers to the zones navNodes list
|
||||
for (Regions region : building.getBounds().getRegions()) {
|
||||
building.parentZone.navNodes.add(new PathingUtilities.Node(new Vector2f(region.center.x, region.center.z), region, building));
|
||||
}
|
||||
}
|
||||
|
||||
public static Path2D.Float hullToPath2d(String[] hullString) {
|
||||
|
||||
// Method builds convex hull from database vertices
|
||||
|
||||
ArrayList<Vector2f> vertices = new ArrayList<>();
|
||||
ArrayList<Float> floats = new ArrayList<>();
|
||||
Path2D.Float outPath = new Path2D.Float();
|
||||
|
||||
// Build Arraylist of vertices
|
||||
|
||||
for (String floatString : hullString) {
|
||||
|
||||
floats.add(Float.parseFloat(floatString));
|
||||
|
||||
if (floats.size() == 2) {
|
||||
vertices.add(new Vector2f(floats.get(0), floats.get(1)));
|
||||
floats.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Build Path from vertices
|
||||
|
||||
for (Vector2f vertex : vertices)
|
||||
if (outPath.getCurrentPoint() == null)
|
||||
outPath.moveTo(vertex.x, vertex.y);
|
||||
else
|
||||
outPath.lineTo(vertex.x, vertex.y);
|
||||
|
||||
outPath.closePath();
|
||||
return outPath;
|
||||
}
|
||||
|
||||
public static void loadColliders(Building building) {
|
||||
|
||||
// Load colliders for this building
|
||||
|
||||
building.meshes = new ArrayList<>();
|
||||
|
||||
if (_hull_data.get(building.meshUUID) == null ||
|
||||
_hull_data.get(building.meshUUID).size() < 1)
|
||||
return;
|
||||
|
||||
for (Path2D.Float path : _hull_data.get(building.meshUUID)) {
|
||||
|
||||
Path2D.Float translatedPath = new Path2D.Float(path);
|
||||
AffineTransform offset = AffineTransform.getTranslateInstance(building.loc.x, building.loc.y);
|
||||
|
||||
translatedPath.transform(offset);
|
||||
|
||||
AffineTransform rotate = AffineTransform.getRotateInstance(Math.toRadians(building.getBounds().getQuaternion().angleY), building.loc.x, building.loc.z);
|
||||
translatedPath.transform(rotate);
|
||||
|
||||
building.meshes.add(translatedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.loot.WorkOrder;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.DelayQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public enum ForgeManager implements Runnable {
|
||||
|
||||
FORGE_MANAGER;
|
||||
|
||||
private final BlockingQueue<WorkOrder> workQueue = new DelayQueue();
|
||||
public static final AtomicInteger workOrder = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
while (true) {
|
||||
|
||||
try {
|
||||
|
||||
WorkOrder workOrder = workQueue.take();
|
||||
|
||||
// Fulfill workOrder
|
||||
|
||||
for (int i = 0; i < workOrder.slotCount; ++i) {
|
||||
|
||||
// Create workOrder items; one for each slot
|
||||
// assigned to this workOrder.
|
||||
|
||||
// if Prefix and suffix are null random roll item
|
||||
// otherwise roll what was asked for
|
||||
|
||||
workOrder.itemCount = workOrder.itemCount - 1;
|
||||
|
||||
}
|
||||
|
||||
if (workOrder.itemCount == 0) {
|
||||
|
||||
workOrder.runCompleted = true;
|
||||
|
||||
// Remove this workOrder from any slots on vendor
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Resubmit workOrder
|
||||
|
||||
workOrder.completionTime = System.currentTimeMillis() + 10000;
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package engine.gameManager;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.MobAI;
|
||||
import engine.net.client.msg.MoveToPointMsg;
|
||||
import engine.objects.*;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class NavigationManager {
|
||||
|
||||
private static final int cellGap = 1;
|
||||
private static final int stepHeight = 2;
|
||||
|
||||
public static void pathfind(AbstractCharacter character, Vector3fImmutable goal) {
|
||||
if(!pathBlocked(character.loc,goal)){
|
||||
character.destination = goal;
|
||||
MobAI.directMove((Mob)character,character.combatTarget != null);
|
||||
}
|
||||
try {
|
||||
ArrayList<Vector3fImmutable> path = getPath(character.loc, goal);//getOptimizedPath(getPath(character.loc, goal), getPath(goal, character.loc));
|
||||
if (path.isEmpty()) {
|
||||
MobAI.directMove((Mob)character,character.combatTarget != null);
|
||||
return; //no points to walk to
|
||||
}
|
||||
//character.navPath = path;
|
||||
|
||||
} catch (Exception e) {
|
||||
//something failed
|
||||
}
|
||||
}
|
||||
|
||||
public static ArrayList<Vector3fImmutable> getOptimizedPath(ArrayList<Vector3fImmutable> startToGoal, ArrayList<Vector3fImmutable> goalToStart) {
|
||||
ArrayList<Vector3fImmutable> optimalPath = new ArrayList<>();
|
||||
optimalPath.add(startToGoal.get(0));
|
||||
for (Vector3fImmutable point : startToGoal) {
|
||||
if (goalToStart.contains(point) && !optimalPath.contains(point)) {
|
||||
optimalPath.add(point);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//optimize the path to its smallest possible amount of points
|
||||
|
||||
|
||||
return optimalPath;
|
||||
}
|
||||
|
||||
private static ArrayList<Vector3fImmutable> getPath(Vector3fImmutable start, Vector3fImmutable goal) {
|
||||
ArrayList<Vector3fImmutable> path = new ArrayList<>();
|
||||
path.add(start);
|
||||
Vector3fImmutable current = start;
|
||||
boolean obstructed = false;
|
||||
int count = 0;
|
||||
while (current.distanceSquared(goal) > 9 && count < 250) {
|
||||
//gather the 8 cells around the player
|
||||
ArrayList<Vector3fImmutable> surroundingCells = new ArrayList<>();
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(cellGap, 0, 0)));
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(cellGap, 0, cellGap)));
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(0, 0, cellGap)));
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(-cellGap, 0, 0)));
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(-cellGap, 0, -cellGap)));
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(0, 0, -cellGap)));
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(-cellGap, 0, cellGap)));
|
||||
surroundingCells.add(current.add(new Vector3fImmutable(cellGap, 0, -cellGap)));
|
||||
Vector3fImmutable cheapest = new Vector3fImmutable(Vector3fImmutable.ZERO);
|
||||
for (Vector3fImmutable point : surroundingCells) {
|
||||
count++;
|
||||
|
||||
if (path.contains(point))
|
||||
continue;
|
||||
|
||||
if (pointIsBlocked(point)) {
|
||||
obstructed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getCost(cheapest, current, goal) > getCost(point, current, goal))
|
||||
cheapest = point;
|
||||
}
|
||||
current = cheapest;
|
||||
path.add(cheapest);
|
||||
}
|
||||
if (obstructed) {
|
||||
return path;
|
||||
} else {
|
||||
ArrayList<Vector3fImmutable> goalPath = new ArrayList<>();
|
||||
goalPath.add(start);
|
||||
goalPath.add(start.moveTowards(goal,32));
|
||||
goalPath.add(goal);
|
||||
return goalPath; //if the path isn't obstructed we can walk directly from start to the goal
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static float getCost(Vector3fImmutable point, Vector3fImmutable start, Vector3fImmutable goal) {
|
||||
float gCost = start.distanceSquared(point);
|
||||
float hCost = goal.distanceSquared(point);
|
||||
return gCost + hCost;
|
||||
}
|
||||
|
||||
public static boolean pathBlocked(Vector3fImmutable start, Vector3fImmutable end){
|
||||
Zone zone = ZoneManager.findSmallestZone(start);
|
||||
if(zone != null) {
|
||||
for (Path2D.Float obstacle : zone.navObstacles)
|
||||
if(obstacle.intersects(start.x,start.z,end.x,end.z))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static boolean pointIsBlocked(Vector3fImmutable point) {
|
||||
|
||||
Building building = BuildingManager.getBuildingAtLocation(point);
|
||||
if(building != null) {
|
||||
for (Path2D.Float mesh : building.meshes) {
|
||||
if (mesh.contains(point.x,point.z)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import engine.math.Bounds;
|
||||
import engine.math.Vector2f;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.utilities.PathingUtilities;
|
||||
import engine.objects.Building;
|
||||
import engine.objects.City;
|
||||
import engine.objects.Zone;
|
||||
@@ -22,7 +21,6 @@ import engine.objects.ZoneTemplate;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.awt.geom.Path2D;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.loot;
|
||||
|
||||
import engine.gameManager.ForgeManager;
|
||||
import engine.objects.NPC;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.lang.Math.toIntExact;
|
||||
|
||||
public class WorkOrder implements Delayed {
|
||||
|
||||
public int workOrder;
|
||||
public NPC vendor;
|
||||
public int slotCount;
|
||||
public int itemCount;
|
||||
public int itemBase;
|
||||
public String itemName;
|
||||
public int prefixToken;
|
||||
public int suffixToken;
|
||||
public boolean isRandom;
|
||||
public long completionTime;
|
||||
public boolean runCompleted;
|
||||
|
||||
public WorkOrder() {
|
||||
|
||||
this.workOrder = ForgeManager.workOrder.incrementAndGet();
|
||||
this.completionTime = System.currentTimeMillis() + 10000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit) {
|
||||
|
||||
long timeRemaining = completionTime - System.currentTimeMillis();
|
||||
return unit.convert(timeRemaining, TimeUnit.MILLISECONDS);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Delayed o) {
|
||||
return toIntExact(this.completionTime - ((WorkOrder) o).completionTime);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ public class Bounds {
|
||||
private boolean flipExtents;
|
||||
|
||||
private ArrayList<Regions> regions = new ArrayList<>();
|
||||
public ArrayList<Colliders> colliders = new ArrayList<>();
|
||||
private ArrayList<Colliders> colliders = new ArrayList<>();
|
||||
|
||||
// Default constructor
|
||||
|
||||
|
||||
+21
-120
@@ -11,16 +11,14 @@ package engine.mobileAI;
|
||||
import engine.Enum;
|
||||
import engine.Enum.DispatchChannel;
|
||||
import engine.InterestManagement.WorldGrid;
|
||||
import engine.exception.MsgSendException;
|
||||
import engine.gameManager.*;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.Threads.MobAIThread;
|
||||
import engine.mobileAI.Threads.Respawner;
|
||||
import engine.mobileAI.utilities.CombatUtilities;
|
||||
import engine.mobileAI.utilities.PathingUtilities;
|
||||
import engine.mobileAI.utilities.MovementUtilities;
|
||||
import engine.net.DispatchMessage;
|
||||
import engine.net.client.msg.MoveToPointMsg;
|
||||
import engine.net.client.msg.PerformActionMsg;
|
||||
import engine.net.client.msg.PowerProjectileMsg;
|
||||
import engine.objects.*;
|
||||
@@ -105,7 +103,7 @@ public class MobAI {
|
||||
if (mob.behaviourType.callsForHelp)
|
||||
MobCallForHelp(mob);
|
||||
|
||||
if (inRangeDropAggro(mob, target)) {
|
||||
if (!MovementUtilities.inRangeDropAggro(mob, target)) {
|
||||
mob.setCombatTarget(null);
|
||||
return;
|
||||
}
|
||||
@@ -305,10 +303,10 @@ public class MobAI {
|
||||
MobAI.Patrol(minion);
|
||||
}
|
||||
|
||||
aiMove(mob, true,0);
|
||||
MovementUtilities.aiMove(mob, mob.destination, true);
|
||||
|
||||
} catch (Exception e) {
|
||||
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: Patrol" + " " + e.getMessage());
|
||||
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,7 +584,7 @@ public class MobAI {
|
||||
if(mob.isPlayerGuard() || mob.isSiege()) {
|
||||
bypassLoadedPlayerCheck = true;
|
||||
if(mob.combatTarget != null && mob.combatTarget.getObjectType().equals(Enum.GameObjectType.PlayerCharacter))
|
||||
if(mob.combatTarget.loc.distanceSquared(mob.loc) > 62500)
|
||||
if(mob.combatTarget.loc.distanceSquared(mob.loc) > 10000)
|
||||
mob.setCombatTarget(null);
|
||||
}
|
||||
|
||||
@@ -691,7 +689,7 @@ public class MobAI {
|
||||
if (aiAgent.enemy.size() > 0 && aiAgent.enemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType()) == false)
|
||||
continue;
|
||||
|
||||
if (inRangeToAggro(aiAgent, loadedPlayer)) {
|
||||
if (MovementUtilities.inRangeToAggro(aiAgent, loadedPlayer)) {
|
||||
aiAgent.setCombatTarget(loadedPlayer);
|
||||
return;
|
||||
}
|
||||
@@ -724,7 +722,7 @@ public class MobAI {
|
||||
|
||||
try {
|
||||
|
||||
if (!canMove(mob))
|
||||
if (!MovementUtilities.canMove(mob))
|
||||
return;
|
||||
|
||||
mob.updateLocation();
|
||||
@@ -751,7 +749,7 @@ public class MobAI {
|
||||
return;
|
||||
|
||||
mob.destination = mob.guardCaptain.getLoc();
|
||||
aiMove(mob, false,5);
|
||||
MovementUtilities.moveToLocation(mob, mob.destination, 5, false);
|
||||
} else
|
||||
chaseTarget(mob);
|
||||
break;
|
||||
@@ -836,7 +834,7 @@ public class MobAI {
|
||||
if (mob.getCombatTarget() == null)
|
||||
return;
|
||||
|
||||
if (mob.getCombatTarget().getObjectType().equals(Enum.GameObjectType.PlayerCharacter) && inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) &&
|
||||
if (mob.getCombatTarget().getObjectType().equals(Enum.GameObjectType.PlayerCharacter) && MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) == false &&
|
||||
mob.agentType.equals(Enum.AIAgentType.PET) == false) {
|
||||
|
||||
mob.setCombatTarget(null);
|
||||
@@ -879,7 +877,7 @@ public class MobAI {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (inRangeOfBindLocation(mob) == false) {
|
||||
} else if (MovementUtilities.inRangeOfBindLocation(mob) == false) {
|
||||
|
||||
PowersBase recall = PowersManager.getPowerByToken(-1994153779);
|
||||
PowersManager.useMobPower(mob, mob, recall, 40);
|
||||
@@ -907,7 +905,7 @@ public class MobAI {
|
||||
if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mob.getRange()) == false) {
|
||||
if (mob.getRange() > 15) {
|
||||
mob.destination = mob.getCombatTarget().getLoc();
|
||||
aiMove(mob, false,0);
|
||||
MovementUtilities.moveToLocation(mob, mob.destination, 0, false);
|
||||
} else {
|
||||
|
||||
//check if building
|
||||
@@ -915,12 +913,12 @@ public class MobAI {
|
||||
switch (mob.getCombatTarget().getObjectType()) {
|
||||
case PlayerCharacter:
|
||||
case Mob:
|
||||
mob.destination = mob.combatTarget.loc;//GetDestinationToCharacter(mob, (AbstractCharacter) mob.getCombatTarget());
|
||||
aiMove(mob, false,mob.getRange() + 1);
|
||||
mob.destination = MovementUtilities.GetDestinationToCharacter(mob, (AbstractCharacter) mob.getCombatTarget());
|
||||
MovementUtilities.moveToLocation(mob, mob.destination, mob.getRange() + 1, false);
|
||||
break;
|
||||
case Building:
|
||||
mob.destination = mob.getCombatTarget().getLoc();
|
||||
aiMove(mob, false,0);
|
||||
MovementUtilities.moveToLocation(mob, mob.getCombatTarget().getLoc(), 0, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1002,7 +1000,7 @@ public class MobAI {
|
||||
if (ZoneManager.seaFloor.zoneMobSet.contains(mob))
|
||||
mob.killCharacter("no owner");
|
||||
|
||||
if (canMove(mob) && mob.behaviourType.canRoam)
|
||||
if (MovementUtilities.canMove(mob) && mob.behaviourType.canRoam)
|
||||
CheckMobMovement(mob);
|
||||
|
||||
CheckForAttack(mob);
|
||||
@@ -1132,7 +1130,7 @@ public class MobAI {
|
||||
if (GuardCanAggro(mob, loadedPlayer) == false)
|
||||
continue;
|
||||
|
||||
if (inRangeToAggro(mob, loadedPlayer) && mob.getCombatTarget() == null) {
|
||||
if (MovementUtilities.inRangeToAggro(mob, loadedPlayer) && mob.getCombatTarget() == null) {
|
||||
mob.setCombatTarget(loadedPlayer);
|
||||
return;
|
||||
}
|
||||
@@ -1242,9 +1240,9 @@ public class MobAI {
|
||||
float xPoint = ThreadLocalRandom.current().nextInt(400) - 200;
|
||||
float zPoint = ThreadLocalRandom.current().nextInt(400) - 200;
|
||||
Vector3fImmutable TreePos = mob.getGuild().getOwnedCity().getLoc();
|
||||
mob.destination = new Vector3fImmutable(TreePos.x + xPoint, TreePos.y, TreePos.z + zPoint);
|
||||
mob.destination = new Vector3fImmutable(TreePos.x + xPoint, TreePos.y, TreePos.z + zPoint);
|
||||
|
||||
aiMove(mob, true,0);
|
||||
MovementUtilities.aiMove(mob, mob.destination, true);
|
||||
|
||||
if (mob.agentType.equals(Enum.AIAgentType.GUARDCAPTAIN)) {
|
||||
for (Integer minionUUID : mob.minions) {
|
||||
@@ -1254,12 +1252,11 @@ public class MobAI {
|
||||
//make sure mob is out of combat stance
|
||||
|
||||
if (minion.despawned == false) {
|
||||
if (canMove(minion)) {
|
||||
if (MovementUtilities.canMove(minion)) {
|
||||
Vector3f minionOffset = Formation.getOffset(2, mob.minions.indexOf(minionUUID) + 3);
|
||||
minion.updateLocation();
|
||||
Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(mob.destination.x + minionOffset.x, mob.destination.y, mob.destination.z + minionOffset.z);
|
||||
minion.destination = formationPatrolPoint;
|
||||
aiMove(minion, true,0);
|
||||
MovementUtilities.aiMove(minion, formationPatrolPoint, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1287,7 +1284,7 @@ public class MobAI {
|
||||
if (potentialTarget.equals(mob.getCombatTarget()))
|
||||
continue;
|
||||
|
||||
if (potentialTarget != null && mob.playerAgroMap.get(potentialTarget.getObjectUUID()).floatValue() > CurrentHateValue && inRangeToAggro(mob, potentialTarget)) {
|
||||
if (potentialTarget != null && mob.playerAgroMap.get(potentialTarget.getObjectUUID()).floatValue() > CurrentHateValue && MovementUtilities.inRangeToAggro(mob, potentialTarget)) {
|
||||
CurrentHateValue = mob.playerAgroMap.get(potentialTarget.getObjectUUID()).floatValue();
|
||||
mostHatedTarget = potentialTarget;
|
||||
}
|
||||
@@ -1299,100 +1296,4 @@ public class MobAI {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean inRangeDropAggro(Mob agent, AbstractCharacter target) {
|
||||
float rangeSquared = MobAIThread.AI_BASE_AGGRO_RANGE * MobAIThread.AI_BASE_AGGRO_RANGE;
|
||||
if(agent.isPlayerGuard())
|
||||
rangeSquared = 62500;
|
||||
if(agent.isSiege())
|
||||
rangeSquared = agent.getRange() * agent.getRange();
|
||||
|
||||
return agent.loc.distanceSquared(target.loc) > rangeSquared;
|
||||
|
||||
}
|
||||
|
||||
public static boolean inRangeToAggro(Mob agent, PlayerCharacter target) {
|
||||
return MobAIThread.AI_BASE_AGGRO_RANGE * MobAIThread.AI_BASE_AGGRO_RANGE > agent.loc.distanceSquared(target.loc) ;
|
||||
}
|
||||
|
||||
public static boolean inRangeOfBindLocation(Mob agent) {
|
||||
if(agent.isPlayerGuard() && agent.guardedCity.isLocationOnCityZone(agent.loc))
|
||||
return true;
|
||||
float bindRangeSquared = (agent.parentZone.getBounds().getHalfExtents().x * agent.parentZone.getBounds().getHalfExtents().x) + (MobAIThread.AI_DROP_AGGRO_RANGE * MobAIThread.AI_DROP_AGGRO_RANGE);
|
||||
return agent.loc.distanceSquared(agent.bindLoc) < bindRangeSquared;
|
||||
}
|
||||
|
||||
public static boolean canMove(Mob agent) {
|
||||
if (!agent.behaviourType.canRoam)
|
||||
return false;
|
||||
|
||||
return (agent.isAlive() && !agent.getBonuses().getBool(Enum.ModType.Stunned, Enum.SourceType.None) && !agent.getBonuses().getBool(Enum.ModType.CannotMove, Enum.SourceType.None));
|
||||
}
|
||||
|
||||
public static Vector3fImmutable GetDestinationToCharacter(Mob aiAgent, AbstractCharacter character) {
|
||||
|
||||
if (!character.isMoving())
|
||||
return character.getLoc();
|
||||
|
||||
|
||||
float agentDistanceEndLoc = aiAgent.getLoc().distanceSquared2D(character.getEndLoc());
|
||||
float characterDistanceEndLoc = character.getLoc().distanceSquared2D(character.getEndLoc());
|
||||
|
||||
if (agentDistanceEndLoc > characterDistanceEndLoc)
|
||||
return character.getEndLoc();
|
||||
|
||||
return character.getLoc();
|
||||
}
|
||||
|
||||
public static void aiMove(Mob mob, boolean isWalking, float offset) {
|
||||
|
||||
if(mob.isMoving()) {
|
||||
return;
|
||||
}
|
||||
//if(!mob.isPathing){
|
||||
// ArrayList<PathingUtilities.Node> path = PathingUtilities.getPath(mob, mob.destination);
|
||||
// if(path != null && path.size() > 0)
|
||||
// PathingUtilities.followPath(mob,path);
|
||||
//}
|
||||
}
|
||||
|
||||
public static void directMove(AbstractCharacter mob,boolean isWalking){
|
||||
//update our walk/run state.
|
||||
if (isWalking && !mob.isWalk()) {
|
||||
mob.setWalkMode(true);
|
||||
MovementManager.sendRWSSMsg(mob);
|
||||
} else if (!isWalking && mob.isWalk()) {
|
||||
mob.setWalkMode(false);
|
||||
MovementManager.sendRWSSMsg(mob);
|
||||
}
|
||||
mob.endLoc = mob.destination;
|
||||
|
||||
MoveToPointMsg msg = new MoveToPointMsg();
|
||||
|
||||
msg.setSourceType(Enum.GameObjectType.Mob.ordinal());
|
||||
msg.setSourceID(mob.getObjectUUID());
|
||||
msg.setStartCoord(mob.loc);
|
||||
msg.setEndCoord(mob.destination);
|
||||
Regions region = Regions.getRegionAtLocation(mob.destination);
|
||||
if(region != null){
|
||||
msg.setInBuildingFloor(region.room);
|
||||
msg.setInBuilding(region.level);
|
||||
msg.setStartLocType(0);
|
||||
msg.setInBuildingUUID(region.parentBuildingID);
|
||||
} else{
|
||||
msg.setInBuildingFloor(-1);
|
||||
msg.setInBuilding(-1);
|
||||
msg.setStartLocType(0);
|
||||
msg.setInBuildingUUID(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
MovementManager.movement(msg, mob);
|
||||
} catch (MsgSendException e) {
|
||||
// TODO Figure out how we want to handle the msg send exception
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,18 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
package engine.mobileAI.Threads;
|
||||
|
||||
import engine.gameManager.ConfigManager;
|
||||
import engine.mobileAI.MobAI;
|
||||
import engine.gameManager.ZoneManager;
|
||||
import engine.mobileAI.MobAI;
|
||||
import engine.objects.Mob;
|
||||
import engine.objects.Zone;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
public class MobAIThread implements Runnable{
|
||||
@@ -14,23 +21,27 @@ public class MobAIThread implements Runnable{
|
||||
public static int AI_PULSE_MOB_THRESHOLD = 200;
|
||||
public static int AI_PATROL_DIVISOR = 15;
|
||||
public static float AI_CAST_FREQUENCY;
|
||||
|
||||
// Thread constructor
|
||||
|
||||
public MobAIThread() {
|
||||
Logger.info(" MobAIThread thread has started!");
|
||||
|
||||
//cache config value for mobile casting delay
|
||||
|
||||
AI_CAST_FREQUENCY = Float.parseFloat(ConfigManager.MB_AI_CAST_FREQUENCY.getValue());
|
||||
AI_BASE_AGGRO_RANGE = (int) (60 * Float.parseFloat(ConfigManager.MB_AI_AGGRO_RANGE.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//cache config value for mobile casting delay
|
||||
AI_CAST_FREQUENCY = Float.parseFloat(ConfigManager.MB_AI_CAST_FREQUENCY.getValue());
|
||||
AI_BASE_AGGRO_RANGE = (int)(60 * Float.parseFloat(ConfigManager.MB_AI_AGGRO_RANGE.getValue()));
|
||||
|
||||
Logger.info(" MobAIThread thread has started!");
|
||||
|
||||
while (true) {
|
||||
for (Zone zone : ZoneManager.getAllZones()) {
|
||||
|
||||
for (Mob mob : zone.zoneMobSet) {
|
||||
|
||||
for (Zone zone : ZoneManager.getAllZones())
|
||||
for (Mob mob : zone.zoneMobSet)
|
||||
try {
|
||||
if (mob != null)
|
||||
MobAI.DetermineAction(mob);
|
||||
@@ -38,10 +49,10 @@ public class MobAIThread implements Runnable{
|
||||
Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void startAIThread() {
|
||||
Thread aiThread;
|
||||
aiThread = new Thread(new MobAIThread());
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.mobileAI.utilities;
|
||||
|
||||
import engine.Enum;
|
||||
import engine.Enum.GameObjectType;
|
||||
import engine.Enum.ModType;
|
||||
import engine.Enum.SourceType;
|
||||
import engine.exception.MsgSendException;
|
||||
import engine.gameManager.MovementManager;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.Threads.MobAIThread;
|
||||
import engine.net.client.msg.MoveToPointMsg;
|
||||
import engine.objects.*;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static engine.math.FastMath.sqr;
|
||||
import static engine.math.FastMath.sqrt;
|
||||
|
||||
public class MovementUtilities {
|
||||
|
||||
|
||||
public static boolean inRangeOfBindLocation(Mob agent) {
|
||||
|
||||
|
||||
if (agent.isPlayerGuard()) {
|
||||
|
||||
Mob guardCaptain = null;
|
||||
if (agent.getContract() != null)
|
||||
guardCaptain = agent;
|
||||
else
|
||||
guardCaptain = (Mob) agent.guardCaptain;
|
||||
|
||||
if (guardCaptain != null) {
|
||||
Building barracks = guardCaptain.building;
|
||||
|
||||
if (barracks != null) {
|
||||
City city = barracks.getCity();
|
||||
|
||||
if (city != null) {
|
||||
Building tol = city.getTOL();
|
||||
|
||||
//Guards recall distance = 814.
|
||||
if (tol != null) {
|
||||
return !(agent.getLoc().distanceSquared2D(tol.getLoc()) > sqr(Enum.CityBoundsType.ZONE.halfExtents));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector3fImmutable sl = new Vector3fImmutable(agent.getLoc().getX(), 0, agent.getLoc().getZ());
|
||||
Vector3fImmutable tl = new Vector3fImmutable(agent.getTrueBindLoc().x, 0, agent.getTrueBindLoc().z);
|
||||
|
||||
float distanceSquaredToTarget = sl.distanceSquared2D(tl); //distance to center of target
|
||||
float zoneRange = 250;
|
||||
|
||||
if (agent.getParentZone() != null) {
|
||||
if (agent.getParentZone().bounds != null)
|
||||
zoneRange = agent.getParentZone().bounds.getHalfExtents().x * 2;
|
||||
}
|
||||
|
||||
if (zoneRange > 300)
|
||||
zoneRange = 300;
|
||||
|
||||
if (agent.getSpawnRadius() > zoneRange)
|
||||
zoneRange = agent.getSpawnRadius();
|
||||
|
||||
|
||||
return distanceSquaredToTarget < sqr(MobAIThread.AI_DROP_AGGRO_RANGE + zoneRange);
|
||||
|
||||
}
|
||||
|
||||
public static boolean inRangeToAggro(Mob agent, PlayerCharacter target) {
|
||||
|
||||
Vector3fImmutable sl = agent.getLoc();
|
||||
Vector3fImmutable tl = target.getLoc();
|
||||
|
||||
float distanceSquaredToTarget = sl.distanceSquared2D(tl) - sqr(agent.calcHitBox() + target.calcHitBox()); //distance to center of target
|
||||
float range = MobAIThread.AI_BASE_AGGRO_RANGE;
|
||||
|
||||
if (agent.isPlayerGuard())
|
||||
range = 150;
|
||||
|
||||
return distanceSquaredToTarget < sqr(range);
|
||||
|
||||
}
|
||||
|
||||
public static boolean inRangeDropAggro(Mob agent, AbstractCharacter target) {
|
||||
|
||||
Vector3fImmutable sl = agent.getLoc();
|
||||
Vector3fImmutable tl = target.getLoc();
|
||||
|
||||
float distanceSquaredToTarget = sl.distanceSquared2D(tl) - sqr(agent.calcHitBox() + target.calcHitBox()); //distance to center of target
|
||||
|
||||
float range = agent.getRange() + 150;
|
||||
|
||||
if (range > 200)
|
||||
range = 200;
|
||||
|
||||
|
||||
return distanceSquaredToTarget < sqr(range);
|
||||
|
||||
}
|
||||
|
||||
public static Vector3fImmutable GetMoveLocation(Mob aiAgent, AbstractCharacter aggroTarget) {
|
||||
|
||||
// Player isnt moving and neither is mob. Just return
|
||||
// the mobile's current location. Ain't goin nowhere!
|
||||
// *** Refactor: Check to ensure methods calling us
|
||||
// all don't sent move messages when not moving.
|
||||
|
||||
if ((aggroTarget.isMoving() == false))
|
||||
return aggroTarget.getLoc();
|
||||
|
||||
if (aggroTarget.getEndLoc().x != 0) {
|
||||
|
||||
float aggroTargetDistanceSquared = aggroTarget.getLoc().distanceSquared2D(aggroTarget.getEndLoc());
|
||||
float aiAgentDistanceSquared = aiAgent.getLoc().distanceSquared2D(aggroTarget.getEndLoc());
|
||||
|
||||
if (aiAgentDistanceSquared >= aggroTargetDistanceSquared)
|
||||
return aggroTarget.getEndLoc();
|
||||
else {
|
||||
float distanceToMove = sqrt(aggroTargetDistanceSquared + aiAgentDistanceSquared) * .5f;
|
||||
|
||||
return aggroTarget.getFaceDir().scaleAdd(distanceToMove, aggroTarget.getLoc());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// One of us is moving so let's calculate our destination loc for this
|
||||
// simulation frame. We will simply project our position onto the
|
||||
// character's movement vector and return the closest point.
|
||||
|
||||
return aiAgent.getLoc().ClosestPointOnLine(aggroTarget.getLoc(), aggroTarget.getEndLoc());
|
||||
}
|
||||
|
||||
public static void moveToLocation(Mob agent, Vector3fImmutable newLocation, float offset, boolean isWalking) {
|
||||
try {
|
||||
|
||||
//don't move farther than 30 units from player.
|
||||
if (offset > 30)
|
||||
offset = 30;
|
||||
Vector3fImmutable newLoc = Vector3fImmutable.getRandomPointInCircle(newLocation, offset);
|
||||
|
||||
|
||||
agent.setFaceDir(newLoc.subtract2D(agent.getLoc()).normalize());
|
||||
|
||||
aiMove(agent, newLoc, isWalking);
|
||||
} catch (Exception e) {
|
||||
Logger.error(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean canMove(Mob agent) {
|
||||
if (agent.getMobBase() != null && Enum.MobFlagType.SENTINEL.elementOf(agent.getMobBase().getFlags()))
|
||||
return false;
|
||||
|
||||
return (agent.isAlive() && !agent.getBonuses().getBool(ModType.Stunned, SourceType.None) && !agent.getBonuses().getBool(ModType.CannotMove, SourceType.None));
|
||||
}
|
||||
|
||||
public static Vector3fImmutable randomPatrolLocation(Mob agent, Vector3fImmutable center, float radius) {
|
||||
|
||||
//Determing where I want to move.
|
||||
return new Vector3fImmutable((center.x - radius) + ((ThreadLocalRandom.current().nextFloat() + .1f * 2) * radius),
|
||||
center.y,
|
||||
(center.z - radius) + ((ThreadLocalRandom.current().nextFloat() + .1f * 2) * radius));
|
||||
}
|
||||
|
||||
public static Long estimateMovementTime(Mob agent) {
|
||||
if (agent.getEndLoc().x == 0 && agent.getEndLoc().y == 0)
|
||||
return 0L;
|
||||
|
||||
return (long) ((agent.getLoc().distance2D(agent.getEndLoc()) * 1000) / agent.getSpeed());
|
||||
}
|
||||
|
||||
public static void aiMove(Mob agent, Vector3fImmutable vect, boolean isWalking) {
|
||||
|
||||
//update our walk/run state.
|
||||
if (isWalking && !agent.isWalk()) {
|
||||
agent.setWalkMode(true);
|
||||
MovementManager.sendRWSSMsg(agent);
|
||||
} else if (!isWalking && agent.isWalk()) {
|
||||
agent.setWalkMode(false);
|
||||
MovementManager.sendRWSSMsg(agent);
|
||||
}
|
||||
|
||||
MoveToPointMsg msg = new MoveToPointMsg();
|
||||
|
||||
|
||||
// Regions currentRegion = Mob.InsideBuildingRegion(agent);
|
||||
//
|
||||
// if (currentRegion != null){
|
||||
//
|
||||
//
|
||||
// if (currentRegion.isGroundLevel()){
|
||||
// agent.setInBuilding(0);
|
||||
// agent.setInFloorID(-1);
|
||||
// }else{
|
||||
// agent.setInBuilding(currentRegion.getLevel());
|
||||
// agent.setInFloorID(currentRegion.getRoom());
|
||||
// }
|
||||
// }else{
|
||||
// agent.setInBuilding(-1);
|
||||
// agent.setInFloorID(-1);
|
||||
// agent.setInBuildingID(0);
|
||||
// }
|
||||
// agent.setLastRegion(currentRegion);
|
||||
|
||||
|
||||
Vector3fImmutable startLoc = null;
|
||||
Vector3fImmutable endLoc = null;
|
||||
|
||||
// if (agent.getLastRegion() != null){
|
||||
// Building inBuilding = Building.getBuildingFromCache(agent.getInBuildingID());
|
||||
// if (inBuilding != null){
|
||||
// startLoc = ZoneManager.convertWorldToLocal(inBuilding, agent.getLoc());
|
||||
// endLoc = ZoneManager.convertWorldToLocal(inBuilding, vect);
|
||||
// }
|
||||
// }else{
|
||||
// agent.setBuildingID(0);
|
||||
// agent.setInBuildingID(0);
|
||||
// startLoc = agent.getLoc();
|
||||
// endLoc = vect;
|
||||
// }
|
||||
|
||||
startLoc = agent.getLoc();
|
||||
endLoc = vect;
|
||||
|
||||
msg.setSourceType(GameObjectType.Mob.ordinal());
|
||||
msg.setSourceID(agent.getObjectUUID());
|
||||
msg.setStartCoord(startLoc);
|
||||
msg.setEndCoord(endLoc);
|
||||
msg.setInBuildingFloor(-1);
|
||||
msg.setInBuilding(-1);
|
||||
msg.setStartLocType(0);
|
||||
msg.setInBuildingUUID(0);
|
||||
|
||||
|
||||
try {
|
||||
MovementManager.movement(msg, agent);
|
||||
} catch (MsgSendException e) {
|
||||
// TODO Figure out how we want to handle the msg send exception
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3fImmutable GetDestinationToCharacter(Mob aiAgent, AbstractCharacter character) {
|
||||
|
||||
if (!character.isMoving())
|
||||
return character.getLoc();
|
||||
|
||||
|
||||
float agentDistanceEndLoc = aiAgent.getLoc().distanceSquared2D(character.getEndLoc());
|
||||
float characterDistanceEndLoc = character.getLoc().distanceSquared2D(character.getEndLoc());
|
||||
|
||||
if (agentDistanceEndLoc > characterDistanceEndLoc)
|
||||
return character.getEndLoc();
|
||||
|
||||
return character.getLoc();
|
||||
}
|
||||
|
||||
public static boolean updateMovementToCharacter(Mob aiAgent, AbstractCharacter aggroTarget) {
|
||||
|
||||
if (aiAgent.destination.equals(Vector3fImmutable.ZERO))
|
||||
return true;
|
||||
|
||||
if (!aiAgent.isMoving())
|
||||
return true;
|
||||
|
||||
|
||||
if (aggroTarget.isMoving()) {
|
||||
return !aiAgent.destination.equals(aggroTarget.getEndLoc()) && !aiAgent.destination.equals(aggroTarget.getLoc());
|
||||
} else {
|
||||
if (aiAgent.destination.equals(aggroTarget.getLoc()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
package engine.mobileAI.utilities;
|
||||
import engine.Enum;
|
||||
import engine.exception.MsgSendException;
|
||||
import engine.gameManager.BuildingManager;
|
||||
import engine.gameManager.MovementManager;
|
||||
import engine.gameManager.ZoneManager;
|
||||
import engine.math.Vector2f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.MobAI;
|
||||
import engine.net.client.msg.MoveToPointMsg;
|
||||
import engine.objects.AbstractCharacter;
|
||||
import engine.objects.Building;
|
||||
import engine.objects.Regions;
|
||||
import engine.objects.Zone;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.awt.geom.Path2D;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PathingUtilities {
|
||||
public static class Node {
|
||||
public Vector2f location;
|
||||
public ArrayList<Node> neighbors;
|
||||
public Regions region;
|
||||
public Building parentBuilding;
|
||||
|
||||
public Node(Vector2f loc, Regions reg, Building parent){
|
||||
this.location = loc;
|
||||
this.region = reg;
|
||||
this.parentBuilding = parent;
|
||||
this.neighbors = new ArrayList<>();
|
||||
}
|
||||
public Node(Node clone){
|
||||
this.location = clone.location;
|
||||
this.region = clone.region;
|
||||
this.parentBuilding = clone.parentBuilding;
|
||||
this.neighbors = (ArrayList<Node>) clone.neighbors.clone();
|
||||
}
|
||||
public ArrayList<Node> getNeighbors(){
|
||||
if(neighbors.size() == 0){
|
||||
Zone zone = ZoneManager.findSmallestZone(new Vector3fImmutable(this.location.x,0,this.location.y));
|
||||
if(zone == null)
|
||||
return null;
|
||||
|
||||
for(Node potentialNeighbor : zone.navNodes){
|
||||
for (Path2D.Float obstacle : zone.navObstacles) {
|
||||
if (!this.equals(potentialNeighbor) && !obstacle.intersects(this.location.x, this.location.y, potentialNeighbor.location.x, potentialNeighbor.location.y) && this.location.distance(potentialNeighbor.location) < 65) {
|
||||
this.neighbors.add(potentialNeighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.neighbors;
|
||||
}
|
||||
}
|
||||
|
||||
public static Node getClosestNode(Vector3fImmutable loc){
|
||||
Zone zone = ZoneManager.findSmallestZone(loc);
|
||||
Regions region = Regions.getRegionAtLocation(loc);
|
||||
if(region != null){
|
||||
for(Node node : zone.navNodes){
|
||||
if(node.location == new Vector2f(region.center.x,region.center.z))
|
||||
return node;
|
||||
}
|
||||
}
|
||||
float disSq = 10000000;
|
||||
Node closest = null;
|
||||
for(Node node : zone.navNodes){
|
||||
if(node.location.distanceSquared(new Vector2f(loc.x,loc.z)) < disSq)
|
||||
closest = node;
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
public static ArrayList<Node> getPath(AbstractCharacter mover, Vector3fImmutable goal){
|
||||
ArrayList<Node> path = new ArrayList<>();
|
||||
Node startNode = getClosestNode(mover.loc);
|
||||
Node goalNode = getClosestNode(goal);
|
||||
if(goalNode == null)
|
||||
move(mover,goal);
|
||||
Node currentNode = new Node(startNode);
|
||||
path.add(startNode);
|
||||
int attempts = 0;
|
||||
while(!currentNode.equals(goalNode) && attempts < 250){
|
||||
attempts ++;
|
||||
currentNode = getCheapestNeighbor(currentNode,new Vector2f(goal.x,goal.z));
|
||||
path.add(currentNode);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
public static Node getCheapestNeighbor(Node node, Vector2f goal){
|
||||
Node cheapest = null;
|
||||
for(Node neighbor : node.getNeighbors()){
|
||||
if(cheapest == null) {
|
||||
cheapest = neighbor;
|
||||
continue;
|
||||
}
|
||||
if(getCost(cheapest.location,node.location,goal) > getCost(neighbor.location,node.location,goal)){
|
||||
cheapest = neighbor;
|
||||
}
|
||||
}
|
||||
return cheapest;
|
||||
}
|
||||
public static float getCost(Vector2f point, Vector2f start, Vector2f goal) {
|
||||
float gCost = start.distanceSquared(point);
|
||||
float hCost = goal.distanceSquared(point);
|
||||
return gCost + hCost;
|
||||
}
|
||||
public static void followPath(AbstractCharacter character, ArrayList<Node> path){
|
||||
character.isPathing = true;
|
||||
while(new Vector2f(character.loc.x,character.loc.z).distanceSquared(path.get(path.size() - 1).location) > 9 && path.size() > 0){
|
||||
if( character.isMoving())
|
||||
continue;
|
||||
if(character.combatTarget != null){
|
||||
//need ot adjust new path for a moving combat target
|
||||
if(character.combatTarget.loc.distanceSquared2D(new Vector3fImmutable(path.get(path.size() - 1).location.x,0,path.get(path.size() - 1).location.y)) > 625){
|
||||
character.isPathing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
move(character,new Vector3fImmutable(path.get(0).location.x,0,path.get(0).location.y));
|
||||
path.remove(0);
|
||||
}
|
||||
character.isPathing = false;
|
||||
}
|
||||
public static void move(AbstractCharacter mob, Vector3fImmutable goal) {
|
||||
mob.destination = goal;
|
||||
if (mob.getObjectType().equals(Enum.GameObjectType.Mob)) {
|
||||
mob.setWalkMode(!(mob.combatTarget == null));
|
||||
MovementManager.sendRWSSMsg(mob);
|
||||
}
|
||||
mob.endLoc = goal;
|
||||
|
||||
MoveToPointMsg msg = new MoveToPointMsg();
|
||||
|
||||
msg.setSourceType(Enum.GameObjectType.Mob.ordinal());
|
||||
msg.setSourceID(mob.getObjectUUID());
|
||||
msg.setStartCoord(mob.loc);
|
||||
msg.setEndCoord(goal);
|
||||
Regions region = Regions.getRegionAtLocation(goal);
|
||||
if (region != null) {
|
||||
msg.setInBuildingFloor(region.room);
|
||||
msg.setInBuilding(region.level);
|
||||
msg.setStartLocType(0);
|
||||
msg.setInBuildingUUID(region.parentBuildingID);
|
||||
} else {
|
||||
msg.setInBuildingFloor(-1);
|
||||
msg.setInBuilding(-1);
|
||||
msg.setStartLocType(0);
|
||||
msg.setInBuildingUUID(0);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
MovementManager.movement(msg, mob);
|
||||
} catch (MsgSendException e) {
|
||||
// TODO Figure out how we want to handle the msg send exception
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class ChangeAltitudeHandler extends AbstractClientMsgHandler {
|
||||
float startAlt = 0;
|
||||
Building regionBuilding = Regions.GetBuildingForRegion(upRegion);
|
||||
if (upRegion != null)
|
||||
startAlt = upRegion.lerpY(pc.loc) - regionBuilding.getLoc().y;
|
||||
startAlt = upRegion.lerpY(pc) - regionBuilding.getLoc().y;
|
||||
float rounded = startAlt * .10f;
|
||||
|
||||
rounded = ((int) rounded) * 10;
|
||||
@@ -143,7 +143,7 @@ public class ChangeAltitudeHandler extends AbstractClientMsgHandler {
|
||||
float landingAltitude = 0;
|
||||
Building building = Regions.GetBuildingForRegion(region);
|
||||
if (building != null)
|
||||
landingAltitude = region.lerpY(pc.loc) - building.getLoc().y;
|
||||
landingAltitude = region.lerpY(pc) - building.getLoc().y;
|
||||
|
||||
if (landingAltitude >= targetAlt) {
|
||||
pc.landingRegion = region;
|
||||
|
||||
@@ -16,6 +16,7 @@ import engine.Enum.ItemType;
|
||||
import engine.exception.MsgSendException;
|
||||
import engine.gameManager.ChatManager;
|
||||
import engine.gameManager.DbManager;
|
||||
import engine.loot.WorkOrder;
|
||||
import engine.net.Dispatch;
|
||||
import engine.net.DispatchMessage;
|
||||
import engine.net.client.ClientConnection;
|
||||
@@ -455,9 +456,18 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
|
||||
switch (msg.getActionType()) {
|
||||
|
||||
case ACTION_PRODUCE:
|
||||
boolean isRandom = false;
|
||||
if (msg.getUnknown03() != 0 && msg.getpToken() == 0 && msg.getsToken() == 0)
|
||||
isRandom = true;
|
||||
|
||||
boolean isRandom = msg.getUnknown03() != 0 && msg.getpToken() == 0 && msg.getsToken() == 0;
|
||||
|
||||
WorkOrder workOrder = new WorkOrder();
|
||||
workOrder.vendor = vendorNPC;
|
||||
workOrder.isRandom = isRandom;
|
||||
workOrder.itemBase = msg.getItemUUID();
|
||||
workOrder.itemCount = msg.getTotalProduction();
|
||||
workOrder.prefixToken = msg.getpToken();
|
||||
workOrder.suffixToken = msg.getsToken();
|
||||
workOrder.itemName = msg.getName();
|
||||
|
||||
//Create Multiple Item Function.. Fill all empty slots
|
||||
if (msg.isMultiple()) {
|
||||
int emptySlots = vendorNPC.getRank() - vendorNPC.getRolling().size();
|
||||
|
||||
@@ -25,7 +25,6 @@ import engine.jobs.TrackJob;
|
||||
import engine.math.AtomicFloat;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.utilities.PathingUtilities;
|
||||
import engine.net.ByteBufferWriter;
|
||||
import engine.net.DispatchMessage;
|
||||
import engine.net.client.msg.ErrorPopupMsg;
|
||||
@@ -121,16 +120,11 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
private long lastHateUpdate = 0;
|
||||
private byte aoecntr = 0;
|
||||
|
||||
public Vector3fImmutable destination = Vector3fImmutable.ZERO;
|
||||
|
||||
public int hidden = 0; // current rank of hide/sneak/invis
|
||||
public CopyOnWriteArrayList<Integer> minions = new CopyOnWriteArrayList();
|
||||
|
||||
public ArrayList<CharacterRune> runes;
|
||||
|
||||
public ArrayList<PathingUtilities.Node> navPath = new ArrayList<>();
|
||||
public boolean isPathing = false;
|
||||
|
||||
public AbstractCharacter() {
|
||||
super();
|
||||
this.firstName = "";
|
||||
@@ -840,10 +834,6 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
if (this.isCasting && this.getObjectType().equals(GameObjectType.PlayerCharacter))
|
||||
return false;
|
||||
|
||||
if(this.getObjectType().equals(GameObjectType.Mob)){
|
||||
if(this.destination.equals(Vector3fImmutable.ZERO))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -997,11 +987,22 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
@Override
|
||||
public final void setLoc(final Vector3fImmutable value) {
|
||||
|
||||
Regions region = Regions.getRegionAtLocation(value);
|
||||
Building building = BuildingManager.getBuildingAtLocation(this.loc);
|
||||
Regions region = null;
|
||||
if(building != null) {
|
||||
//look for region in the building we are in
|
||||
for (Regions regionCycle : building.getBounds().getRegions()) {
|
||||
float regionHeight = regionCycle.highLerp.y - regionCycle.lowLerp.y;
|
||||
if(regionHeight < 10)
|
||||
regionHeight = 10;
|
||||
if (regionCycle.isPointInPolygon(value) && Math.abs(regionCycle.highLerp.y - value.y) < regionHeight)
|
||||
region = regionCycle;
|
||||
}
|
||||
}
|
||||
float regionHeightOffset = 0;
|
||||
if(region != null){
|
||||
this.region = region;
|
||||
regionHeightOffset = region.lerpY(this.loc);
|
||||
regionHeightOffset = region.lerpY(this);
|
||||
this.inBuilding = region.level; // -1 not in building 0 on ground floor, 1 on first floor etc
|
||||
this.inBuildingID = region.parentBuildingID;
|
||||
this.inFloorID = region.room;
|
||||
|
||||
@@ -179,7 +179,7 @@ public abstract class AbstractWorldObject extends AbstractGameObject {
|
||||
if (region.center.y == region.highLerp.y)
|
||||
worldObject.loc = worldObject.loc.setY(region.center.y + worldObject.getAltitude());
|
||||
else
|
||||
worldObject.loc = worldObject.loc.setY(region.lerpY(worldObject.loc) + worldObject.getAltitude());
|
||||
worldObject.loc = worldObject.loc.setY(region.lerpY(worldObject) + worldObject.getAltitude());
|
||||
|
||||
return region;
|
||||
}
|
||||
@@ -504,7 +504,7 @@ public abstract class AbstractWorldObject extends AbstractGameObject {
|
||||
this.loc = loc;
|
||||
|
||||
if(this instanceof AbstractCharacter && this.region != null){
|
||||
this.loc = this.loc.setY(this.region.lerpY(this.loc) + this.getAltitude());
|
||||
this.loc = this.loc.setY(this.region.lerpY(this) + this.getAltitude());
|
||||
} else{
|
||||
this.loc = this.loc.setY(Terrain.getWorldHeight(this.getLoc()) + this.getAltitude());
|
||||
}
|
||||
|
||||
@@ -34,8 +34,6 @@ import engine.net.client.msg.UpdateObjectMsg;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDateTime;
|
||||
@@ -101,8 +99,6 @@ public class Building extends AbstractWorldObject {
|
||||
private ConcurrentHashMap<Integer, Condemned> condemned;
|
||||
private ArrayList<Building> children = null;
|
||||
|
||||
public ArrayList<Path2D.Float> meshes;
|
||||
|
||||
/**
|
||||
* ResultSet Constructor
|
||||
*/
|
||||
@@ -291,30 +287,7 @@ public class Building extends AbstractWorldObject {
|
||||
|
||||
public final City getCity() {
|
||||
|
||||
if (this.parentZone == null)
|
||||
return null;
|
||||
|
||||
if (this.getBlueprint() != null && this.getBlueprint().isSiegeEquip() && this.protectionState.equals(ProtectionState.PROTECTED)) {
|
||||
if (this.getGuild() != null) {
|
||||
if (this.getGuild().getOwnedCity() != null) {
|
||||
if (this.getLoc().isInsideCircle(this.getGuild().getOwnedCity().getLoc(), CityBoundsType.ZONE.halfExtents))
|
||||
return this.getGuild().getOwnedCity();
|
||||
} else {
|
||||
Bane bane = Bane.getBaneByAttackerGuild(this.getGuild());
|
||||
|
||||
if (bane != null) {
|
||||
if (bane.getCity() != null) {
|
||||
if (this.getLoc().isInsideCircle(bane.getCity().getLoc(), CityBoundsType.ZONE.halfExtents))
|
||||
return bane.getCity();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.parentZone.guild_zone == false)
|
||||
return null;
|
||||
|
||||
return City.getCity(this.parentZone.playerCityUUID);
|
||||
return ZoneManager.getCityAtLocation(this.getLoc());
|
||||
|
||||
}
|
||||
|
||||
@@ -1007,9 +980,6 @@ public class Building extends AbstractWorldObject {
|
||||
|
||||
if (this.upgradeDateTime != null)
|
||||
BuildingManager.submitUpgradeJob(this);
|
||||
|
||||
BuildingManager.loadColliders(this); // load building colliders
|
||||
BuildingManager.bakeNavMesh(this); // update the navmesh of the parent zone
|
||||
}
|
||||
|
||||
public synchronized boolean setOwner(AbstractCharacter newOwner) {
|
||||
@@ -1537,5 +1507,4 @@ public class Building extends AbstractWorldObject {
|
||||
public void RemoveFromBarracksList() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ package engine.objects;
|
||||
import engine.gameManager.DbManager;
|
||||
import engine.math.Bounds;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Area;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -47,10 +45,5 @@ public class MeshBounds {
|
||||
Bounds.meshBoundsCache = DbManager.BuildingQueries.LOAD_MESH_BOUNDS();
|
||||
}
|
||||
|
||||
public Area getArea(float x, float z){
|
||||
Polygon area = new Polygon();
|
||||
area.addPoint((int)(x + this.minX), (int) (z + this.minZ));
|
||||
area.addPoint((int)(x + this.maxX), (int)(z + this.maxZ));
|
||||
return new Area(area);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
|
||||
public long nextCallForHelp = 0;
|
||||
public ReentrantReadWriteLock minionLock = new ReentrantReadWriteLock();
|
||||
public boolean despawned = false;
|
||||
|
||||
public Vector3fImmutable destination = Vector3fImmutable.ZERO;
|
||||
public MobBase mobBase;
|
||||
public int spawnDelay;
|
||||
public Zone parentZone;
|
||||
@@ -1899,5 +1899,4 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
|
||||
public int compareTo(@NotNull Delayed o) {
|
||||
return toIntExact(this.respawnTime - ((Mob) o).respawnTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import engine.gameManager.*;
|
||||
import engine.job.JobContainer;
|
||||
import engine.job.JobScheduler;
|
||||
import engine.jobs.UpgradeNPCJob;
|
||||
import engine.loot.WorkOrder;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
@@ -37,6 +38,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup;
|
||||
@@ -52,6 +54,8 @@ public class NPC extends AbstractCharacter {
|
||||
private final ArrayList<MobLoot> rolling = new ArrayList<>();
|
||||
public ReentrantReadWriteLock minionLock = new ReentrantReadWriteLock();
|
||||
public ArrayList<ProducedItem> forgedItems = new ArrayList<>();
|
||||
|
||||
public CopyOnWriteArrayList<WorkOrder> workOrders = new CopyOnWriteArrayList();
|
||||
public HashMap<Integer, MobEquipment> equip = null;
|
||||
public int runeSetID = 0;
|
||||
public int extraRune2 = 0;
|
||||
|
||||
@@ -4828,7 +4828,7 @@ public class PlayerCharacter extends AbstractCharacter {
|
||||
if (this.landingRegion != null) {
|
||||
this.altitude = 0;
|
||||
this.region = this.landingRegion;
|
||||
this.loc = this.loc.setY(this.landingRegion.lerpY(this.loc));
|
||||
this.loc = this.loc.setY(this.landingRegion.lerpY(this));
|
||||
} else
|
||||
this.altitude = this.getDesiredAltitude();
|
||||
|
||||
|
||||
@@ -9,18 +9,14 @@
|
||||
|
||||
package engine.objects;
|
||||
|
||||
import engine.InterestManagement.Terrain;
|
||||
import engine.InterestManagement.WorldGrid;
|
||||
import engine.gameManager.BuildingManager;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.FastMath;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.utilities.PathingUtilities;
|
||||
import engine.server.MBServerStatics;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Area;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -182,7 +178,7 @@ public class Regions {
|
||||
boolean movingUp = false;
|
||||
|
||||
boolean movingDown = false;
|
||||
float yLerp = worldObject.region.lerpY(worldObject.loc);
|
||||
float yLerp = worldObject.region.lerpY(worldObject);
|
||||
|
||||
if (yLerp == (worldObject.region.highLerp.y))
|
||||
movingUp = true;
|
||||
@@ -274,18 +270,32 @@ public class Regions {
|
||||
return BuildingManager.getBuildingFromCache(region.parentBuildingID);
|
||||
}
|
||||
|
||||
public static Regions getRegionAtLocation(Vector3fImmutable location) {
|
||||
public static Regions GetRegionForTeleport(Vector3fImmutable location) {
|
||||
Regions region = null;
|
||||
Building building = BuildingManager.getBuildingAtLocation(location);
|
||||
if(building != null) {
|
||||
//look for region in the building we are in
|
||||
for (Regions regionCycle : building.getBounds().getRegions()) {
|
||||
float regionHeight = regionCycle.highLerp.y - regionCycle.lowLerp.y;
|
||||
if(regionHeight < 10)
|
||||
regionHeight = 10;
|
||||
if (regionCycle.isPointInPolygon(location) && Math.abs(regionCycle.highLerp.y - location.y) < regionHeight)
|
||||
region = regionCycle;
|
||||
|
||||
|
||||
//Find building
|
||||
for (AbstractWorldObject awo : WorldGrid.getObjectsInRangePartial(location, 128, MBServerStatics.MASK_BUILDING)) {
|
||||
Building building = (Building) awo;
|
||||
if (!Bounds.collide(location, building.getBounds()))
|
||||
continue;
|
||||
if(building != null) {
|
||||
region = BuildingManager.GetRegion(building, location.x, location.y, location.z);
|
||||
}
|
||||
//find regions that intersect x and z, check if object can enter.
|
||||
//for (Regions toEnter : building.getBounds().getRegions()) {
|
||||
// if (toEnter.isPointInPolygon(location)) {
|
||||
|
||||
// if (region == null)
|
||||
// region = toEnter;
|
||||
// else // we're using a low level to high level tree structure, database not always in order low to high.
|
||||
//check for highest level index.
|
||||
// if (region != null && toEnter.highLerp.y > region.highLerp.y)
|
||||
// region = toEnter;
|
||||
|
||||
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return region;
|
||||
}
|
||||
@@ -340,10 +350,10 @@ public class Regions {
|
||||
return inside;
|
||||
}
|
||||
|
||||
public float lerpY(Vector3fImmutable lerper) {
|
||||
public float lerpY(AbstractWorldObject lerper) {
|
||||
|
||||
Vector3fImmutable lengthVector = this.highLerp.subtract2D(this.lowLerp);
|
||||
Vector3fImmutable characterVector = lerper.subtract2D(this.lowLerp);
|
||||
Vector3fImmutable characterVector = lerper.getLoc().subtract2D(this.lowLerp);
|
||||
float lengthVectorMagnitude = lengthVector.magnitude();
|
||||
float characterVectorMagnitude = characterVector.magnitude();
|
||||
float percentDistance = characterVectorMagnitude / lengthVectorMagnitude;
|
||||
@@ -364,12 +374,4 @@ public class Regions {
|
||||
public boolean isExit() {
|
||||
return exit;
|
||||
}
|
||||
|
||||
public Area getArea(){
|
||||
Polygon area = new Polygon();
|
||||
for( Vector3f point : this.regionPoints){
|
||||
area.addPoint((int) point.x, (int) point.z);
|
||||
}
|
||||
return new Area(area);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
package engine.objects;
|
||||
|
||||
import java.awt.geom.Area;
|
||||
import engine.Enum;
|
||||
import engine.InterestManagement.Terrain;
|
||||
import engine.db.archive.DataWarehouse;
|
||||
@@ -17,12 +16,10 @@ import engine.gameManager.ZoneManager;
|
||||
import engine.math.Bounds;
|
||||
import engine.math.Vector2f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mobileAI.utilities.PathingUtilities;
|
||||
import engine.net.ByteBufferWriter;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Path2D;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
@@ -67,8 +64,6 @@ public class Zone extends AbstractWorldObject {
|
||||
public float sea_level;
|
||||
|
||||
public Terrain terrain = null;
|
||||
public ArrayList<Path2D.Float> navObstacles = new ArrayList<>();
|
||||
public ArrayList<PathingUtilities.Node> navNodes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* ResultSet Constructor
|
||||
@@ -185,7 +180,9 @@ public class Zone extends AbstractWorldObject {
|
||||
}
|
||||
|
||||
ZoneManager.populateZoneCollections(this);
|
||||
|
||||
}
|
||||
|
||||
/* Method sets a default value for player cities
|
||||
* otherwise using values derived from the loadnum
|
||||
* field in the obj_zone database table.
|
||||
|
||||
@@ -96,7 +96,7 @@ public class TeleportPowerAction extends AbstractPowerAction {
|
||||
|
||||
//TODO verify target loc is valid loc
|
||||
|
||||
Regions region = Regions.getRegionAtLocation(targetLoc);
|
||||
Regions region = Regions.GetRegionForTeleport(targetLoc);
|
||||
|
||||
if (region != null && !region.isOutside())
|
||||
return;
|
||||
|
||||
@@ -403,9 +403,6 @@ public class WorldServer {
|
||||
Logger.info("Loading building slot/stuck location data.");
|
||||
BuildingLocation.loadBuildingLocations();
|
||||
|
||||
Logger.info("Loading mesh hulls.");
|
||||
DbManager.BuildingQueries.LOAD_MESH_HULLS();
|
||||
|
||||
// Starting before loading of structures/guilds/characters
|
||||
// so the database connections are available to write
|
||||
// historical data.
|
||||
|
||||
Reference in New Issue
Block a user