Compare commits

..

55 Commits

Author SHA1 Message Date
FatBoy 6fe4f32302 load mesh data and structure meshes 2024-01-18 19:50:49 -06:00
FatBoy d6ad0ecbd3 load mesh data and structure meshes 2024-01-18 19:43:47 -06:00
FatBoy efdf19f22e load mesh data and structure meshes 2024-01-18 19:15:49 -06:00
FatBoy 76a71b5984 load mesh data and structure meshes 2024-01-18 19:12:52 -06:00
FatBoy cf09f447bd load mesh data and structure meshes 2024-01-18 18:53:57 -06:00
FatBoy 8dc6a0627c load mesh data and structure meshes 2024-01-17 22:03:35 -06:00
FatBoy 8b095976ef load mesh data and structure meshes 2024-01-17 21:47:15 -06:00
FatBoy 83606046ba load mesh data and structure meshes 2024-01-17 20:55:04 -06:00
FatBoy adcf3fd9b6 load mesh data and structure meshes 2024-01-17 20:34:47 -06:00
FatBoy e983a32b5d load mesh data and structure meshes 2024-01-16 20:10:10 -06:00
FatBoy 9d8f800c2a load mesh data and structure meshes 2024-01-16 10:40:07 -06:00
FatBoy 05e90d495f load mesh data and structure meshes 2024-01-16 09:59:41 -06:00
FatBoy 18f70b6d5c load mesh data and structure meshes 2024-01-16 09:51:07 -06:00
FatBoy 86c8e985be load mesh data and structure meshes 2024-01-16 09:25:31 -06:00
FatBoy b6b5db41bd load mesh data and structure meshes 2024-01-15 20:37:33 -06:00
FatBoy d573534f6d load mesh data and structure meshes 2024-01-15 20:36:11 -06:00
FatBoy 06df109a18 load mesh data and structure meshes 2024-01-15 20:28:49 -06:00
FatBoy f077370034 load mesh data and structure meshes 2024-01-15 20:09:05 -06:00
FatBoy 94e16bdf3d load mesh data and structure meshes 2024-01-15 20:07:21 -06:00
FatBoy a52f0941b7 load mesh data and structure meshes 2024-01-15 19:47:33 -06:00
FatBoy 840dc83987 load mesh data and structure meshes 2024-01-15 19:43:08 -06:00
FatBoy 5b9d1dd6eb load mesh data and structure meshes 2024-01-15 19:32:49 -06:00
FatBoy 6215e15e82 load mesh data and structure meshes 2024-01-15 19:15:41 -06:00
FatBoy e8a39e596e load mesh data and structure meshes 2024-01-15 19:08:38 -06:00
FatBoy 90b516bbb9 load mesh data and structure meshes 2024-01-15 18:57:18 -06:00
FatBoy 561170eb44 load mesh data and structure meshes 2024-01-14 19:36:54 -06:00
FatBoy 68920f150d load mesh data and structure meshes 2024-01-14 19:30:28 -06:00
FatBoy a54e8c2176 Merge remote-tracking branch 'origin/feature_mesh_collision' into feature_mesh_collision
# Conflicts:
#	src/engine/db/handlers/dbBuildingHandler.java
2024-01-14 19:10:23 -06:00
FatBoy c77f38dec1 load mesh data and structure meshes 2024-01-14 19:10:07 -06:00
FatBoy 5a57677013 Triangle check 2024-01-13 21:34:36 -06:00
FatBoy 306c64d236 Triangle check 2024-01-13 21:27:26 -06:00
FatBoy 0b05e661c7 cleanup and comment 2024-01-13 19:53:50 -06:00
FatBoy a94a400102 cleanup and comment 2024-01-13 19:51:37 -06:00
FatBoy 4bff36d7bb cleanup and comment 2024-01-07 19:14:18 -06:00
FatBoy 969b36e6fd mesh count to building info command 2024-01-07 19:11:29 -06:00
FatBoy 688553e6c6 invert X axis instead of Z axis 2024-01-07 19:07:55 -06:00
FatBoy 4f057ee851 utilize min and max Y values for meshes 2024-01-05 23:32:32 -06:00
FatBoy fd47c90f4f utilize min and max Y values for meshes 2024-01-05 23:03:51 -06:00
FatBoy 253ca2344e add Y axis of building to mesh height 2024-01-05 22:44:58 -06:00
FatBoy 95f09a255e add Y axis of building to mesh height 2024-01-05 22:41:41 -06:00
FatBoy 31ea74f98c reverse Z axis 2024-01-05 22:38:39 -06:00
FatBoy 67c474dbdf collision work 2024-01-05 20:29:11 -06:00
FatBoy c65a713bae collision work 2024-01-05 20:13:27 -06:00
FatBoy e3641872d0 added COllisionManager 2024-01-05 19:28:43 -06:00
FatBoy c25fdf3823 added COllisionManager 2024-01-05 19:21:24 -06:00
FatBoy 7c28efb47c offset cleanup 2024-01-05 19:06:56 -06:00
FatBoy c92316f03e data load fixes 2024-01-03 20:39:18 -06:00
FatBoy e330f190fe data load fixes 2024-01-03 20:11:28 -06:00
FatBoy ae52735131 data load fixes 2024-01-03 20:08:52 -06:00
FatBoy 59025c2585 collision handler 2024-01-03 19:55:12 -06:00
FatBoy 6354eb2893 collision handler 2024-01-03 19:50:40 -06:00
FatBoy 3ad97a7ce3 collision handler 2024-01-03 19:47:30 -06:00
FatBoy f8cbeb4cc6 debug dev command for collision 2024-01-03 19:33:34 -06:00
FatBoy f1e41e47cf database mesh data loaded into hashmaps 2024-01-03 19:25:59 -06:00
MagicBot 78a0416b19 Updated city planting to conform to class refactor project. 2023-12-24 09:44:01 -05:00
31 changed files with 865 additions and 644 deletions
@@ -0,0 +1,27 @@
package engine.CollisionEngine;
import engine.math.Vector3f;
import engine.objects.Building;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
public class CollisionManager {
public static HashMap<Integer, ArrayList<MeshData>> structure_meshes;
public static HashMap<Integer,ArrayList<Triangle>> mesh_triangles;
public static boolean CollisionDetected(Building building, Line2D travelLine, float charHeight, float charY){
if(building.buildingRect != null)
if(!travelLine.intersects(building.buildingRect) && !building.buildingRect.contains(travelLine.getP1()) && !building.buildingRect.contains(travelLine.getP2()))
return false;
for(Mesh mesh : building.buildingMeshes)
if(mesh.collides(travelLine))
return true;
return false;
}
}
+87
View File
@@ -0,0 +1,87 @@
package engine.CollisionEngine;
import engine.gameManager.BuildingManager;
import engine.math.Vector2f;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.objects.Building;
import org.pmw.tinylog.Logger;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
public class Mesh {
public ArrayList<Triangle> triangles;
public Vector3f mesh_end_point;
public Vector3f mesh_ref_point;
public Vector3f mesh_location;
public float mesh_max_y;
public float mesh_min_y;
public Vector3f mesh_scale;
public int mesh_id;
public int parent_prop_id;
public int parent_structure_id;
public int parentUUID;
public Rectangle2D.Float mesh_bounds;
public MeshData meshData;
public void update(){
this.BakeTriangles();
}
public Vector3f getLocation(){
Building parentBuilding = BuildingManager.getBuilding(this.parentUUID);
int degrees = (int)Math.toDegrees(parentBuilding.getBounds().getQuaternion().angleY);
Vector3f parentLoc = new Vector3f(parentBuilding.loc.x,parentBuilding.loc.y,parentBuilding.loc.z);
Vector3f offsetLoc = parentLoc.add(this.meshData.loc);
Vector3f rotatedPoint = Vector3f.rotateAroundPoint(offsetLoc,parentLoc,degrees);
return rotatedPoint;
}
public void BakeTriangles(){
if(CollisionManager.mesh_triangles.containsKey(this.meshData.meshID) == false){
Logger.error("Failed To Bake Triangles For Mesh: " + this.meshData.meshID);
return;
}
Building parentBuilding = BuildingManager.getBuilding(this.parentUUID);
int degrees = (int)Math.toDegrees(parentBuilding.getBounds().getQuaternion().angleY);
Vector3f parentLoc = new Vector3f(parentBuilding.loc.x,parentBuilding.loc.y,parentBuilding.loc.z);
Vector3f offsetLoc = parentLoc.add(this.meshData.loc);
for(Triangle tri : CollisionManager.mesh_triangles.get(this.meshData.meshID)) {
Triangle newTri = new Triangle();
Vector3f Point1 = offsetLoc.add(new Vector3f(tri.point1.x,offsetLoc.y,tri.point1.y));
Vector3f Point2 = offsetLoc.add(new Vector3f(tri.point2.x,offsetLoc.y,tri.point2.y));
Vector3f Point3 = offsetLoc.add(new Vector3f(tri.point3.x,offsetLoc.y,tri.point3.y));
Vector3f rotatedPoint1 = Vector3f.rotateAroundPoint(Point1,offsetLoc,degrees);
Vector3f rotatedPoint2 = Vector3f.rotateAroundPoint(Point2,offsetLoc,degrees);
Vector3f rotatedPoint3 = Vector3f.rotateAroundPoint(Point3,offsetLoc,degrees);
newTri.point1 = new Point2D.Float(rotatedPoint1.x,rotatedPoint1.z);
newTri.point2 = new Point2D.Float(rotatedPoint2.x,rotatedPoint2.z);
newTri.point3 = new Point2D.Float(rotatedPoint3.x,rotatedPoint3.z);
newTri.sides = new ArrayList<>();
newTri.sides.add(new Line2D.Float(newTri.point1,newTri.point2));
newTri.sides.add(new Line2D.Float(newTri.point2,newTri.point3));
newTri.sides.add(new Line2D.Float(newTri.point3,newTri.point1));
this.triangles.add(newTri);
}
}
public Boolean collides(Line2D line){
for(Triangle tri : this.triangles)
if(tri.collides(line))
return true;
return false;
}
}
+14
View File
@@ -0,0 +1,14 @@
package engine.CollisionEngine;
import engine.math.Vector3f;
public class MeshData {
public int propID;
public int meshID;
public Vector3f loc;
public Vector3f scale;
public Vector3f refPoint;
public Vector3f endPoint;
public float maxY;
public float minY;
}
+21
View File
@@ -0,0 +1,21 @@
package engine.CollisionEngine;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
public class Triangle {
public Point2D.Float point1;
public Point2D.Float point2;
public Point2D.Float point3;
public ArrayList<Line2D> sides;
public boolean collides(Line2D line)
{
for(Line2D side : sides)
if(side.intersectsLine(line))
return true;
return false;
}
}
+171 -57
View File
@@ -9,6 +9,9 @@
package engine.db.handlers;
import engine.CollisionEngine.CollisionManager;
import engine.CollisionEngine.MeshData;
import engine.CollisionEngine.Triangle;
import engine.Enum;
import engine.Enum.DbObjectType;
import engine.Enum.ProtectionState;
@@ -16,11 +19,15 @@ import engine.Enum.TaxType;
import engine.gameManager.BuildingManager;
import engine.gameManager.DbManager;
import engine.math.Vector2f;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.objects.*;
import org.joda.time.DateTime;
import org.pmw.tinylog.Logger;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -28,6 +35,7 @@ import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
@@ -549,63 +557,6 @@ public class dbBuildingHandler extends dbHandlerBase {
return false;
}
public void LOAD_CONVEX_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 meshID = rs.getInt("meshID");
String[] hullString = rs.getString("vertices").split(";");
// Filter things that couldn't be wrapped
if (hullString.length < 3) {
Logger.error("Mesh : " + meshID + " has less than 3 vertices.");
continue;
}
ArrayList<Vector2f> convexHull = new ArrayList<>();
ArrayList<Float> floats = new ArrayList<>();
for (String read : hullString) {
floats.add(Float.parseFloat(read));
if (floats.size() == 2) {
convexHull.add(new Vector2f(floats.get(0), floats.get(1)));
floats.clear();
}
}
ArrayList<ArrayList<Vector2f>> hullList;
if (BuildingManager._hull_data.get(meshID) == null) {
hullList = new ArrayList<>();
hullList.add(convexHull);
BuildingManager._hull_data.put(meshID, hullList);
} else {
hullList = BuildingManager._hull_data.get(meshID);
hullList.add(convexHull);
}
}
} 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<>();
@@ -907,4 +858,167 @@ public class dbBuildingHandler extends dbHandlerBase {
return false;
}
public void LOAD_MESH_DATA(){
CollisionManager.structure_meshes = new HashMap<>();
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `final_structure_meshes`")) {
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
MeshData md = new MeshData();
md.propID = rs.getInt("propID");
md.meshID = rs.getInt("meshID");
md.loc = new Vector3f(rs.getFloat("locX"), rs.getFloat("locY"),rs.getFloat("locz"));
md.scale = new Vector3f(rs.getFloat("scaleX"), rs.getFloat("scaleY"),rs.getFloat("scaleZ"));
md.refPoint = new Vector3f(rs.getFloat("refX"), rs.getFloat("refY"),rs.getFloat("refZ"));
md.endPoint = new Vector3f(rs.getFloat("endX"), rs.getFloat("endY"),rs.getFloat("endZ"));
md.minY = rs.getFloat("minY");
md.maxY = rs.getFloat("maxY");
if(CollisionManager.structure_meshes.containsKey(rs.getInt("propID"))){
CollisionManager.structure_meshes.get(rs.getInt("propID")).add(md);
} else{
ArrayList<MeshData> meshData = new ArrayList<>();
meshData.add(md);
CollisionManager.structure_meshes.put(rs.getInt("propID"),meshData);
}
}
} catch (SQLException e) {
Logger.error(e);
}
}
public void LOAD_MESH_TRIANGLE_DATA(){
CollisionManager.mesh_triangles = new HashMap<>();
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `final_mesh_triangles`")) {
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
Triangle tri = new Triangle();
tri.point1 = new Point2D.Float(rs.getFloat("P1X"),rs.getFloat("P1Z"));
tri.point2 = new Point2D.Float(rs.getFloat("P2X"),rs.getFloat("P2Z"));
tri.point3 = new Point2D.Float(rs.getFloat("P3X"),rs.getFloat("P3Z"));
if(CollisionManager.mesh_triangles.containsKey(rs.getInt("meshID"))){
CollisionManager.mesh_triangles.get(rs.getInt("meshID")).add(tri);
} else{
ArrayList<Triangle> triData = new ArrayList<>();
triData.add(tri);
CollisionManager.mesh_triangles.put(rs.getInt("meshID"),triData);
}
}
} catch (SQLException e) {
Logger.error(e);
}
}
public void LOAD_PROP_MESHES() {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_structure_meshes`")) {
ResultSet rs = preparedStatement.executeQuery();
BuildingManager.prop_meshes = new HashMap<>();
while (rs.next()) {
if(BuildingManager.prop_meshes.containsKey(rs.getInt("propID")) == false){
ArrayList<Integer> meshList = new ArrayList<>();
meshList.add(rs.getInt("meshID"));
BuildingManager.prop_meshes.put(rs.getInt("propID"),meshList);
}
else
{
ArrayList<Integer> meshes = BuildingManager.prop_meshes.get(rs.getInt("propID"));
meshes.add(rs.getInt("meshID"));
//BuildingManager.prop_meshes.get(rs.getInt("propID")).add(rs.getInt("meshID"));
}
}
} catch (SQLException e) {
Logger.error(e);
}
}
public void LOAD_MESH_DATA_OLD() {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_mesh_triangles`")) {
ResultSet rs = preparedStatement.executeQuery();
BuildingManager.mesh_triangle_points = new HashMap<>();
while (rs.next()) {
ArrayList<Float> floatPoints = new ArrayList<>();
for(String f : rs.getString("vertices").split(";"))
{
floatPoints.add(Float.parseFloat(f));
}
ArrayList<Vector3f> triPoints = new ArrayList<>();
for(int i = 0; i < floatPoints.size(); i += 3){
triPoints.add(new Vector3f(floatPoints.get(i),floatPoints.get(i+1),floatPoints.get(i+2)));
}
if(BuildingManager.mesh_triangle_points.containsKey(rs.getInt("meshID")) == false){
ArrayList<ArrayList<Vector3f>> newPoints = new ArrayList<>();
newPoints.add(triPoints);
BuildingManager.mesh_triangle_points.put(rs.getInt("meshID"),newPoints);
}
else
{
BuildingManager.mesh_triangle_points.get(rs.getInt("meshID")).add(triPoints);
}
}
} catch (SQLException e) {
Logger.error(e);
}
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_mesh_heights`")) {
ResultSet rs = preparedStatement.executeQuery();
BuildingManager.mesh_heights = new HashMap<>();
while (rs.next()) {
if(BuildingManager.mesh_heights.containsKey(rs.getInt("meshID")) == false){
Vector2f heights = new Vector2f(rs.getFloat("maxY"),rs.getFloat("minY"));
BuildingManager.mesh_heights.put(rs.getInt("meshID"),heights);
}
}
} catch (SQLException e) {
Logger.error(e);
}
}
public void LOAD_MESH_BOUNDING_BOXES() {
try (Connection connection = DbManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM `static_mesh_bounding_boxes`")) {
ResultSet rs = preparedStatement.executeQuery();
BuildingManager.mesh_bounding_boxes = new HashMap<>();
while (rs.next()) {
int meshID = rs.getInt("meshId");
if(BuildingManager.mesh_bounding_boxes.containsKey(meshID) == false){
float endX = Float.parseFloat(rs.getString("mesh_end_point").split(";")[0]);
float endZ = Float.parseFloat(rs.getString("mesh_end_point").split(";")[1]);
float refX = Float.parseFloat(rs.getString("mesh_ref_point").split(";")[0]);
float refZ = Float.parseFloat(rs.getString("mesh_ref_point").split(";")[1]);
Vector2f topLeft = new Vector2f(refX,refZ);
float width = Math.abs(Math.abs(endX)-Math.abs(refX));
float height = Math.abs(Math.abs(endZ)-Math.abs(refZ));
Rectangle2D boundRect = new Rectangle2D.Float();
boundRect.setRect(topLeft.x,topLeft.y,width,height);
BuildingManager.mesh_bounding_boxes.put(meshID,boundRect);
}
}
} catch (SQLException e) {
Logger.error(e);
}
}
}
@@ -34,16 +34,19 @@ public class dbCityHandler extends dbHandlerBase {
case "zone":
Zone zone = new Zone(rs);
DbManager.addToCache(zone);
zone.runAfterLoad();
list.add(zone);
break;
case "building":
Building building = new Building(rs);
DbManager.addToCache(building);
building.runAfterLoad();
list.add(building);
break;
case "city":
City city = new City(rs);
DbManager.addToCache(city);
city.runAfterLoad();
list.add(city);
break;
}
+60
View File
@@ -0,0 +1,60 @@
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.devcmd.cmds;
import engine.CollisionEngine.Mesh;
import engine.Enum;
import engine.devcmd.AbstractDevCmd;
import engine.objects.*;
public class ColliderCmd extends AbstractDevCmd {
public ColliderCmd() {
super("collider");
}
@Override
protected void _doCmd(PlayerCharacter pc, String[] words,
AbstractGameObject target) {
String newline = "\r\n ";
String output;
if(target.getObjectType().equals(Enum.GameObjectType.Building) == false){
throwbackInfo(pc,"Please Select A Building To Show Collider Data");
}
Building building = (Building)target;
output = "Collision Info:" + newline;
output += "Total Meshes: " + building.buildingMeshes.size() + newline;
for(Mesh mesh : building.buildingMeshes){
output += "-----------------------------" + newline;
output += "Mesh ID: " + mesh.mesh_id + newline;
output += "Mesh Location: " + mesh.mesh_location + newline;
output += "Mesh Scale: " + mesh.mesh_scale + newline;
output += "Mesh Min/Max: " + mesh.mesh_min_y + "/" + mesh.mesh_max_y + newline;
output += "Mesh Triangle Count: " + mesh.triangles.size() + newline;
output += "Mesh Rect: " + mesh.mesh_bounds + newline;
output += "-----------------------------" + newline;
}
throwbackInfo(pc,output);
}
@Override
protected String _getHelpString() {
return "Displays Information About Colliders";
}
@Override
protected String _getUsageString() {
return "' /collider displays collision info when selected on a building";
}
}
+1 -1
View File
@@ -9,6 +9,7 @@
package engine.devcmd.cmds;
import engine.CollisionEngine.Mesh;
import engine.Enum;
import engine.Enum.BuildingGroup;
import engine.Enum.GameObjectType;
@@ -244,7 +245,6 @@ public class InfoCmd extends AbstractDevCmd {
for (Regions regions : targetBuilding.getBounds().getRegions()) {
//TODO ADD REGION INFO
}
break;
case PlayerCharacter:
output += newline;
+8 -38
View File
@@ -9,24 +9,12 @@
package engine.devcmd.cmds;
import engine.Enum;
import engine.CollisionEngine.Mesh;
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;
import java.awt.geom.Point2D;
public class RegionCmd extends AbstractDevCmd {
@@ -47,36 +35,18 @@ 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.");
}
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);
}
//Zone zone = ZoneManager.findSmallestZone(((AbstractCharacter) target).loc);
//if(zone != null) {
// output += "zone: " + zone.zoneName + newline;
// output += "on navmesh: " + zone.navMesh.contains(((AbstractCharacter) target).loc.x,((AbstractCharacter) target).loc.z) + newline;
//}else {
// output += "zone: null" + newline;
//}
output += "pointBlocked: " + NavigationManager.pointIsBlocked(((AbstractCharacter)target).loc);
this.throwbackInfo(pc, output);
}
@Override
+1 -6
View File
@@ -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);
}
+51 -53
View File
@@ -9,18 +9,22 @@
package engine.gameManager;
import engine.CollisionEngine.CollisionManager;
import engine.CollisionEngine.MeshData;
import engine.Enum;
import engine.Enum.BuildingGroup;
import engine.Enum.GameObjectType;
import engine.InterestManagement.InterestManager;
import engine.InterestManagement.WorldGrid;
import engine.CollisionEngine.Mesh;
import engine.CollisionEngine.Triangle;
import engine.job.JobContainer;
import engine.job.JobScheduler;
import engine.jobs.UpgradeBuildingJob;
import engine.math.Bounds;
import engine.math.Vector2f;
import engine.math.Vector3f;
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,7 +33,9 @@ import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.awt.geom.Path2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
@@ -40,7 +46,13 @@ import java.util.concurrent.ThreadLocalRandom;
public enum BuildingManager {
BUILDINGMANAGER;
public static HashMap<Integer, ArrayList<ArrayList<Vector2f>>> _hull_data = new HashMap<>();
public static HashMap<Integer,ArrayList<Integer>> prop_meshes = new HashMap<>();
public static HashMap<Integer, Vector2f> mesh_heights = new HashMap<>();
public static HashMap<Integer,ArrayList<ArrayList<Vector3f>>> mesh_triangle_points = new HashMap<>();
public static HashMap<Integer, Rectangle2D> mesh_bounding_boxes = new HashMap<>();
public static HashMap<Integer, ArrayList<BuildingLocation>> _stuckLocations = new HashMap<>();
public static HashMap<Integer, ArrayList<BuildingLocation>> _slotLocations = new HashMap<>();
@@ -945,6 +957,9 @@ public enum BuildingManager {
cleanupHirelings(building);
//rebake colliders for change in rank
//BuildingManager.BakeBuildingMeshes(building);
BuildingManager.BakeBuildingColliders(building);
building.isDeranking.compareAndSet(true, false);
}
@@ -963,63 +978,46 @@ public enum BuildingManager {
return null;
}
public static void bakeNavMesh(Building building) {
building.meshes = new ArrayList<>();
if (building.parentZone == null) {
Logger.error("Attempt to bake navmesh with no parent: " + building.getObjectUUID());
public static void BakeBuildingColliders(Building building){
if(CollisionManager.structure_meshes.containsKey(building.meshUUID) == false) {
Logger.error("No Meshes Found For Structure: " + building.meshUUID);
return;
}
// Build up navmesh by stencil of the
// convex hull meshes that comprise the prop.
//create the empty array of meshes
building.buildingMeshes = new ArrayList<>();
ArrayList<ArrayList<Vector2f>> convexHullList;
convexHullList = _hull_data.get(building.meshUUID);
//create the actual meshes from the stored mesh data
for(MeshData meshData : CollisionManager.structure_meshes.get(building.meshUUID)){
if(meshData.meshID == 0)
continue;
if (convexHullList == null) {
Logger.error("Attempt to bake navmesh with no meshes: " + building.getObjectUUID());
return;
}
int degrees = (int)Math.toDegrees(building.getBounds().getQuaternion().angleY);
for (ArrayList<Vector2f> meshEntry : convexHullList) {
Path2D.Float meshBound = new Path2D.Float();
Vector3fImmutable offsetVect = new Vector3fImmutable(meshEntry.get(0).x + building.loc.x, building.loc.y,meshEntry.get(0).y + building.loc.z);
Vector3fImmutable rotatedStart = Vector3fImmutable.rotateAroundPoint(building.loc,offsetVect,building.getRot().y);
meshBound.moveTo(rotatedStart.x,rotatedStart.z);
for (Vector2f vect : meshEntry) {
if(meshEntry.indexOf(vect) == 0){
continue;
}
Vector3fImmutable pos = new Vector3fImmutable(vect.x + building.loc.x, building.loc.y,vect.y + building.loc.z);
Vector3fImmutable rotatedPos = Vector3fImmutable.rotateAroundPoint(building.loc,pos,building.getRot().getRotation());
meshBound.lineTo(rotatedPos.x,rotatedPos.z);
}
meshBound.lineTo(rotatedStart.x,rotatedStart.z);
meshBound.closePath();
building.meshes.add(meshBound);
building.parentZone.navObstacles.add(meshBound);
}
//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));
}
}
Mesh generatedMesh = new Mesh();
//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));
generatedMesh.meshData = meshData;
Vector3f buildingLoc = new Vector3f(building.loc.x,building.loc.y,building.loc.z);
Vector3f offset_mesh_loc = buildingLoc.add(meshData.loc);
Vector3f offset_mesh_end = buildingLoc.add(meshData.endPoint);
Vector3f offset_mesh_ref = buildingLoc.add(meshData.refPoint);
generatedMesh.mesh_location = Vector3f.rotateAroundPoint(offset_mesh_loc,buildingLoc,degrees);
generatedMesh.mesh_end_point = Vector3f.rotateAroundPoint(offset_mesh_end,buildingLoc,degrees);
generatedMesh.mesh_ref_point = Vector3f.rotateAroundPoint(offset_mesh_ref,buildingLoc,degrees);
generatedMesh.mesh_max_y = building.loc.y + meshData.maxY;
generatedMesh.mesh_min_y = building.loc.y + meshData.minY;
generatedMesh.mesh_scale = meshData.scale;
generatedMesh.mesh_id = meshData.meshID;
generatedMesh.parent_prop_id = meshData.propID;
generatedMesh.parent_structure_id = building.meshUUID;
generatedMesh.parentUUID = building.getObjectUUID();
generatedMesh.update();
building.buildingMeshes.add(generatedMesh);
}
}
}
@@ -140,6 +140,7 @@ public enum DevCmdManager {
DevCmdManager.registerDevCmd(new BoundsCmd());
DevCmdManager.registerDevCmd(new GotoBoundsCmd());
DevCmdManager.registerDevCmd(new RegionCmd());
DevCmdManager.registerDevCmd(new ColliderCmd());
DevCmdManager.registerDevCmd(new SetMaintCmd());
DevCmdManager.registerDevCmd(new ApplyBonusCmd());
DevCmdManager.registerDevCmd(new AuditFailedItemsCmd());
@@ -1,137 +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) {
Zone zone = ZoneManager.findSmallestZone(point);
if(zone != null){
for(Path2D.Float obstacle : zone.navObstacles)
if (obstacle.contains(point.x,point.z)) {
return true;
}
}
//Building building = BuildingManager.getBuildingAtLocation(point);
//if(building != null) {
//for (Path2D.Float mesh : building.meshes) {
//if (mesh.contains(point.x,point.z)) {
//return true;
//}
//}
//for (Regions region : building.getBounds().getRegions()) {
//if (region.isPointInPolygon(point))
//if (Math.abs(region.lerpY(point) - point.y) > stepHeight) // get the height distance between current height and target location height
//return true;
//}
//}
return false;
}
}
-2
View File
@@ -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;
+1 -1
View File
@@ -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
+20 -119
View File
@@ -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,7 +303,7 @@ 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: 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();
}
}
}
@@ -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;
@@ -9,14 +9,22 @@
package engine.net.client.handlers;
import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.exception.MsgSendException;
import engine.gameManager.BuildingManager;
import engine.gameManager.ChatManager;
import engine.CollisionEngine.CollisionManager;
import engine.gameManager.MovementManager;
import engine.math.Vector3fImmutable;
import engine.net.client.ClientConnection;
import engine.net.client.msg.ClientNetMsg;
import engine.net.client.msg.MoveToPointMsg;
import engine.objects.*;
import engine.server.MBServerStatics;
import java.awt.geom.Line2D;
import java.util.HashSet;
public class MoveToPointHandler extends AbstractClientMsgHandler {
@@ -32,6 +40,32 @@ public class MoveToPointHandler extends AbstractClientMsgHandler {
if(pc == null)
return true;
//check for collisions
Line2D travelLine = new Line2D.Float();
Vector3fImmutable endLoc = new Vector3fImmutable(msg.getEndLat(),msg.getEndAlt(),msg.getEndLon());
travelLine.setLine(pc.loc.x,pc.loc.z,endLoc.x,endLoc.z);
if(BuildingManager.getBuildingAtLocation(pc.loc) != null){
Building current = BuildingManager.getBuildingAtLocation(pc.loc);
if (CollisionManager.CollisionDetected(current, travelLine, pc.getCharacterHeight(), pc.loc.y)) {
ChatManager.chatSystemInfo(pc, "Collision Detected With : " + current.getName() + " Rect: " + current.buildingRect);
//msg.setEndCoord();
MovementManager.movement(msg, pc);
return true;
}
}
HashSet<AbstractWorldObject> awoList = WorldGrid.getObjectsInRangePartial(pc.loc, 1000, MBServerStatics.MASK_BUILDING);
for(AbstractWorldObject awo : awoList){
Building building = (Building)awo;
if(travelLine.intersects(building.buildingRect) || building.buildingRect.contains(travelLine.getP1()) || building.buildingRect.contains(travelLine.getP2())) {
if (CollisionManager.CollisionDetected(building, travelLine, pc.getCharacterHeight(), pc.loc.y)) {
ChatManager.chatSystemInfo(pc, "Collision Detected With : " + building.getName() + " Rect: " + building.buildingRect);
//msg.setEndCoord();
MovementManager.movement(msg, pc);
return true;
}
}
}
//ChatManager.chatSystemInfo(pc, "No Collision Detected");
MovementManager.movement(msg, pc);
return true;
}
@@ -766,8 +766,6 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
cityObjectMap.put(gameObject.getObjectType(), gameObject);
treeObject = (Building) cityObjectMap.get(GameObjectType.Building);
treeObject.runAfterLoad();
cityObject = (City) cityObjectMap.get(GameObjectType.City);
zoneObject = (Zone) cityObjectMap.get(GameObjectType.Zone);
@@ -799,6 +797,10 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
City.lastCityUpdate = System.currentTimeMillis();
treeObject.setLoc(treeObject.getLoc());
// As this is a new static object set it's dirtyFlag
// so players already near it will have the object loaded.
InterestManager.setObjectDirty(treeObject);
serverRealm.addCity(cityObject.getObjectUUID());
+13 -12
View File
@@ -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;
+2 -2
View File
@@ -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());
}
+8 -5
View File
@@ -9,11 +9,13 @@
package engine.objects;
import engine.CollisionEngine.Triangle;
import engine.Enum;
import engine.Enum.*;
import engine.InterestManagement.RealmMap;
import engine.InterestManagement.Terrain;
import engine.InterestManagement.WorldGrid;
import engine.CollisionEngine.Mesh;
import engine.db.archive.CityRecord;
import engine.db.archive.DataWarehouse;
import engine.db.archive.MineRecord;
@@ -34,7 +36,7 @@ import engine.net.client.msg.UpdateObjectMsg;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
@@ -100,7 +102,8 @@ public class Building extends AbstractWorldObject {
private ConcurrentHashMap<Integer, Condemned> condemned;
private ArrayList<Building> children = null;
public ArrayList<Path2D.Float> meshes;
public ArrayList<Mesh> buildingMeshes;
public Rectangle2D.Float buildingRect;
/**
* ResultSet Constructor
@@ -913,7 +916,7 @@ public class Building extends AbstractWorldObject {
// Note: We handle R8 tree edge case for mesh and health
// after city is loaded to avoid recursive result set call
// in City resulting in a stack overflow.
// in City resulting in a stack ovreflow.
if (blueprint != null) {
@@ -1007,7 +1010,8 @@ public class Building extends AbstractWorldObject {
if (this.upgradeDateTime != null)
BuildingManager.submitUpgradeJob(this);
BuildingManager.bakeNavMesh(this); // update the navmesh of the parent zone
//BuildingManager.BakeBuildingMeshes(this);
BuildingManager.BakeBuildingColliders(this);
}
public synchronized boolean setOwner(AbstractCharacter newOwner) {
@@ -1535,5 +1539,4 @@ public class Building extends AbstractWorldObject {
public void RemoveFromBarracksList() {
}
}
+1 -8
View File
@@ -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);
}
}
+1 -2
View File
@@ -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);
}
}
+1 -1
View File
@@ -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();
+27 -25
View File
@@ -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);
}
}
+3 -6
View File
@@ -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;
+6 -3
View File
@@ -309,6 +309,12 @@ public class WorldServer {
Logger.info("Initializing Errant Guild");
Guild.getErrantGuild();
Logger.info("Loading Server Collision Meshes.");
//DbManager.BuildingQueries.LOAD_PROP_MESHES();
DbManager.BuildingQueries.LOAD_MESH_DATA();
DbManager.BuildingQueries.LOAD_MESH_TRIANGLE_DATA();
//DbManager.BuildingQueries.LOAD_MESH_BOUNDING_BOXES();
Logger.info("Loading zone template data");
DbManager.ZoneQueries.LOAD_ALL_ZONE_TEMPLATES();
@@ -403,9 +409,6 @@ public class WorldServer {
Logger.info("Loading building slot/stuck location data.");
BuildingLocation.loadBuildingLocations();
Logger.info("Loading mesh hulls.");
DbManager.BuildingQueries.LOAD_CONVEX_HULLS();
// Starting before loading of structures/guilds/characters
// so the database connections are available to write
// historical data.