diff --git a/ocraft-s2client-api/pom.xml b/ocraft-s2client-api/pom.xml index 70ec52b0..e33a1bac 100644 --- a/ocraft-s2client-api/pom.xml +++ b/ocraft-s2client-api/pom.xml @@ -3,7 +3,7 @@ ocraft-s2client com.github.ocraft - 0.4.21-SNAPSHOT + 0.4.22-SNAPSHOT 4.0.0 diff --git a/ocraft-s2client-benchmark/pom.xml b/ocraft-s2client-benchmark/pom.xml index 9ef9b2dc..23f90da3 100644 --- a/ocraft-s2client-benchmark/pom.xml +++ b/ocraft-s2client-benchmark/pom.xml @@ -3,7 +3,7 @@ ocraft-s2client com.github.ocraft - 0.4.21-SNAPSHOT + 0.4.22-SNAPSHOT 4.0.0 diff --git a/ocraft-s2client-bot/pom.xml b/ocraft-s2client-bot/pom.xml index 4b04184f..5f48781a 100644 --- a/ocraft-s2client-bot/pom.xml +++ b/ocraft-s2client-bot/pom.xml @@ -3,7 +3,7 @@ ocraft-s2client com.github.ocraft - 0.4.21-SNAPSHOT + 0.4.22-SNAPSHOT 4.0.0 diff --git a/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/ExpansionParameters.java b/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/ExpansionParameters.java index ffc74fdd..506b810d 100644 --- a/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/ExpansionParameters.java +++ b/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/ExpansionParameters.java @@ -31,7 +31,9 @@ /** * Some nice parameters that generally work but may require tuning for certain maps. + * @deprecated this class is no longer used in the calculateExpansionLocations() algorithm */ +@Deprecated public final class ExpansionParameters { private final List radiuses = new ArrayList<>(); diff --git a/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/QueryInterface.java b/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/QueryInterface.java index 9a9e8d57..83a2945b 100644 --- a/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/QueryInterface.java +++ b/ocraft-s2client-bot/src/main/java/com/github/ocraft/s2client/bot/gateway/QueryInterface.java @@ -39,6 +39,7 @@ import com.github.ocraft.s2client.protocol.unit.Unit; import java.util.*; +import java.util.stream.Collectors; import static java.util.Arrays.asList; @@ -117,20 +118,19 @@ public interface QueryInterface { * optional unit tags and returns a matching array of booleans indicating if placement is possible. * * @param queries Placement queries. - * @return Array of booleans indicating if placement is possible. + * @return List of booleans indicating if placement is possible. */ List placement(List queries); /** - * Calculates expansion locations, this call can take on the order of 100ms since it makes blocking queries to SC2 - * so call it once and cache the results. + * Calculates expansion locations + * Note: bases that are blocked by destructible rocks or small minerals are included in this list * - * @param debug If filled out CalculateExpansionLocations will render spheres to show what it calculated. + * @param debug If provided CalculateExpansionLocations will render boxes to show what it calculated. */ - default List calculateExpansionLocations( - ObservationInterface observation, DebugInterface debug, ExpansionParameters parameters) { + default List calculateExpansionLocations(ObservationInterface observation, DebugInterface debug) { List resources = observation.getUnits(unitInPool -> { - Set fields = new HashSet<>(asList( + Set nodes = new HashSet<>(asList( Units.NEUTRAL_MINERAL_FIELD, Units.NEUTRAL_MINERAL_FIELD750, Units.NEUTRAL_RICH_MINERAL_FIELD, Units.NEUTRAL_RICH_MINERAL_FIELD750, Units.NEUTRAL_PURIFIER_MINERAL_FIELD, Units.NEUTRAL_PURIFIER_MINERAL_FIELD750, @@ -141,124 +141,97 @@ default List calculateExpansionLocations( Units.NEUTRAL_SPACE_PLATFORM_GEYSER, Units.NEUTRAL_PURIFIER_VESPENE_GEYSER, Units.NEUTRAL_SHAKURAS_VESPENE_GEYSER, Units.NEUTRAL_RICH_VESPENE_GEYSER )); - return fields.contains(unitInPool.unit().getType()); + return nodes.contains(unitInPool.unit().getType()); }); List expansionLocations = new ArrayList<>(); - Map> clusters = cluster(resources, parameters.getClusterDistance()); - - Map querySize = new LinkedHashMap<>(); - List queries = new ArrayList<>(); - for (Map.Entry> cluster : clusters.entrySet()) { - if (debug != null) { - for (double r : parameters.getRadiuses()) { - debug.debugSphereOut(cluster.getKey(), (float) r, Color.GREEN); - } - } - - // Get the required queries for this cluster. - int queryCount = 0; - for (double r : parameters.getRadiuses()) { - List calculatedQueries = calculateQueries( - r, parameters.getCircleStepSize(), cluster.getKey().toPoint2d()); - queries.addAll(calculatedQueries); - queryCount += calculatedQueries.size(); - } - - querySize.put(cluster.getKey(), queryCount); - } - - List results = this.placement(queries); - int startIndex = 0; - for (Map.Entry> cluster : clusters.entrySet()) { - double distance = Double.MAX_VALUE; - Point2d closest = null; - - // For each query for the cluster minimum distance location that is valid. - for (int j = startIndex, e = startIndex + querySize.get(cluster.getKey()); j < e; ++j) { - if (!results.get(j)) { + Map> clusters = cluster(resources, 15); + for (Map.Entry> cluster : clusters.entrySet()) { + + Point2d basePos = cluster.getKey(); + List nodes = cluster.getValue(); + + //estimate base position + basePos = estimateBasePos(basePos, nodes); + + //adjust basePos by grid restraints on each resource node in the cluster + while (true) { + Point2d finalBasePos = basePos; + nodes = nodes.stream() + .sorted(Comparator.comparing(u -> u.unit().getPosition().toPoint2d().distance(finalBasePos))) + .collect(Collectors.toList()); + Point2d adjustedPoint = pushAwayFromNodes(basePos, nodes); + if (adjustedPoint != null) { + basePos = adjustedPoint; continue; } - - Point2d p = queries.get(j).getTarget(); - - double d = p.distance(cluster.getKey().toPoint2d()); - if (d < distance) { - distance = d; - closest = p; + adjustedPoint = pullTowardsNodes(basePos, nodes); + if (adjustedPoint != null) { + basePos = adjustedPoint; + continue; } + break; } - - if (closest != null) { - Point expansion = Point.of( - closest.getX(), - closest.getY(), - cluster.getValue().get(0).unit().getPosition().getZ()); - if (debug != null) { - debug.debugSphereOut(expansion, 0.35f, Color.RED); - } - - expansionLocations.add(expansion); + Point basePoint = basePos.toPoint((float)Math.ceil(observation.terrainHeight(basePos))); + if (debug != null) { + debug.debugBoxOut(basePoint.add(2.5f, 2.5f, 0), basePoint.sub(2.5f, 2.5f, 0), Color.RED); } - - startIndex += querySize.get(cluster.getKey()); + expansionLocations.add(basePoint); } - return expansionLocations; } - default List calculateExpansionLocations(ObservationInterface observation) { - return calculateExpansionLocations(observation, null, ExpansionParameters.preset()); - } - default List calculateExpansionLocations(ObservationInterface observation, DebugInterface debug) { - return calculateExpansionLocations(observation, debug, ExpansionParameters.preset()); + /** + * Calculates expansion locations + * Note: bases that are blocked by destructible rocks or small minerals are included in this list + * + * @param debug If provided CalculateExpansionLocations will render boxes to show what it calculated. + * @deprecated use {@link #calculateExpansionLocations(ObservationInterface observation, DebugInterface debug)} instead. + */ + @Deprecated + default List calculateExpansionLocations( + ObservationInterface observation, DebugInterface debug, ExpansionParameters parameters) { + return calculateExpansionLocations(observation, debug); } - private List calculateQueries(double radius, double stepSize, Point2d center) { - List queries = new ArrayList<>(); - - Point2d previousGrid = Point2d.of(Float.MAX_VALUE, Float.MAX_VALUE); - // Find a buildable location on the circumference of the sphere - for (double degree = 0.0; degree < 360.0; degree += stepSize) { - Point2d point = pointOnCircle(radius, center, degree); - - QueryBuildingPlacement query = QueryBuildingPlacement - .placeBuilding() - .useAbility(Abilities.BUILD_COMMAND_CENTER) - .on(point) - .build(); - - Point2d currentGrid = Point2d.of((float) Math.floor(point.getX()), (float) Math.floor(point.getY())); - - if (!previousGrid.equals(currentGrid)) { - queries.add(query); - } - - previousGrid = currentGrid; - } - - return queries; + /** + * Calculates expansion locations + * Note: bases that are blocked by destructible rocks or small minerals are included in this list + */ + default List calculateExpansionLocations(ObservationInterface observation) { + return calculateExpansionLocations(observation, null); } - private static Point2d pointOnCircle(double radius, Point2d center, double degree) { - return Point2d.of( - (float) (radius * Math.cos(Math.toRadians(degree)) + center.getX()), - (float) (radius * Math.sin(Math.toRadians(degree)) + center.getY())); + /** + * Clusters units within some distance of each other and returns a list of them and their center of mass. + * @param units List of minerals and vespian geyser units + * @param distanceApart Range to consider as apart of the same base + * @return Map of minerals/gas clusters (one entry for each base) + */ + static Map> cluster(List units, double distanceApart) { + return cluster(units, distanceApart,true); } + /** * Clusters units within some distance of each other and returns a list of them and their center of mass. + * @param units List of minerals and vespian geyser units + * @param distanceApart Range to consider as apart of the same base + * @param isElevationResticted if true, minerals/gas will only be apart of the same cluster if they are at the same elevation + * @return Map of minerals/gas clusters (one entry for each base) */ - static Map> cluster(List units, double distanceApart) { - Map> clusters = new LinkedHashMap<>(); + static Map> cluster(List units, double distanceApart, boolean isElevationResticted) { + Map> clusters = new LinkedHashMap<>(); for (UnitInPool u : units) { double distance = Double.MAX_VALUE; - Map.Entry> targetCluster = null; + Point2d unitPos = u.unit().getPosition().toPoint2d(); + Map.Entry> targetCluster = null; + // Find the cluster this mineral patch is closest to. - for (Map.Entry> cluster : clusters.entrySet()) { - double d = u.unit().getPosition().distance(cluster.getKey()); - if (d < distance) { + for (Map.Entry> cluster : clusters.entrySet()) { + double d = unitPos.distance(cluster.getKey()); + if (d < distance && (!isElevationResticted || isSameElevation(u.unit().getPosition(), cluster))) { distance = d; targetCluster = cluster; } @@ -268,23 +241,125 @@ static Map> cluster(List units, double dista if (targetCluster == null || distance > distanceApart) { ArrayList unitsInCluster = new ArrayList<>(); unitsInCluster.add(u); - clusters.put(u.unit().getPosition(), unitsInCluster); + clusters.put(unitPos, unitsInCluster); continue; } // Otherwise append to that cluster and update it's center of mass. - if (targetCluster.getValue() == null) { targetCluster.setValue(new ArrayList<>()); } targetCluster.getValue().add(u); + Point2d centerOfCluster = getCenterPos(targetCluster.getValue()); + clusters.put(centerOfCluster, clusters.remove(targetCluster.getKey())); + } + return clusters; + } - int size = targetCluster.getValue().size(); - Point centerOfMass = targetCluster.getKey().mul(size - 1.0f).add(u.unit().getPosition()).div(size); - clusters.put(centerOfMass, clusters.remove(targetCluster.getKey())); + private static Point2d getCenterPos(List unitList) { + float minX, maxX, minY, maxY; + minX = minY = Float.MAX_VALUE; + maxX = maxY = 0; + for (UnitInPool u : unitList) { + Point2d p = u.unit().getPosition().toPoint2d(); + minX = Math.min(p.getX(), minX); + maxX = Math.max(p.getX(), maxX); + minY = Math.min(p.getY(), minY); + maxY = Math.max(p.getY(), maxY); } + return Point2d.of((minX+maxX)/2f, (minY+maxY)/2f); + } - return clusters; + private static Point2d estimateBasePos(Point2d basePos, List nodes) { + for (int i=0; i<6; i++) { + Point2d finalBestGuess = basePos; + Point2d closestNodePos = nodes.stream() + .min(Comparator.comparing(node -> node.unit().getPosition().toPoint2d().distance(finalBestGuess))).get() + .unit().getPosition().toPoint2d(); + basePos = closestNodePos.towards(basePos, 6.2f); + } + basePos = Point2d.of(basePos.getX(), basePos.getY()).toNearestHalfPoint(); + return basePos; + } + + private static Point2d pullTowardsNodes(Point2d basePos, List nodes) { + for (int i = nodes.size() - 1; i >= 0; i--) { + UnitInPool node = nodes.get(i); + Point2d nodePos = node.unit().getPosition().toPoint2d().roundToHalfPointAccuracy(); + boolean isMineralNode = node.unit().getType().toString().contains("MINERAL"); + float xMinDistCenter = isMineralNode ? 6.5f : 7; + float yMinDistCenter = isMineralNode ? 6f : 7; + float xMaxDist = isMineralNode ? 7.5f : 7; + float yMaxDist = 7; + float xDist = Math.abs(nodePos.getX() - basePos.getX()); + float yDist = Math.abs(nodePos.getY() - basePos.getY()); + if (xDist < yDist) { + if (xDist < xMinDistCenter && yDist > yMaxDist) { + return moveYFromNodeBy(basePos, nodePos, yMaxDist); + } + } + else { + if (yDist < yMinDistCenter && xDist > xMaxDist) { + return moveXFromNodeBy(basePos, nodePos, xMaxDist); + } + } + } + return null; + } + + private static Point2d pushAwayFromNodes(Point2d basePos, List nodes) { + for (UnitInPool node : nodes) { + Point2d nodePos = node.unit().getPosition().toPoint2d().roundToHalfPointAccuracy(); + boolean isMineralNode = node.unit().getType().toString().contains("MINERAL"); + float xMinDistCenter = isMineralNode ? 6.5f : 7; + float xMinDistCorner = isMineralNode ? 5.5f : 6; + float yMinDistCenter = isMineralNode ? 6f : 7; + float yMinDistCorner = isMineralNode ? 5f : 6; + float xDist = Math.abs(nodePos.getX() - basePos.getX()); + float yDist = Math.abs(nodePos.getY() - basePos.getY()); + if (xDist < yDist) { + if (xDist < xMinDistCorner && yDist < yMinDistCenter) { + return moveYFromNodeBy(basePos, nodePos, yMinDistCenter); + } + else if (xDist < xMinDistCenter && yDist < yMinDistCorner) { + return moveYFromNodeBy(basePos, nodePos, yMinDistCorner); + } + } + else { + if (yDist < yMinDistCorner && xDist < xMinDistCenter) { + return moveXFromNodeBy(basePos, nodePos, xMinDistCenter); + } + else if (yDist < yMinDistCenter && xDist < xMinDistCorner) { + return moveXFromNodeBy(basePos, nodePos, xMinDistCorner); + } + } + } + return null; + } + + private static Point2d moveXFromNodeBy(Point2d origin, Point2d nodePos, float distance) { + float newX; + if (origin.getX() < nodePos.getX()) { + newX = nodePos.getX() - distance; + } + else { + newX = nodePos.getX() + distance; + } + return Point2d.of(newX, origin.getY()); } + private static Point2d moveYFromNodeBy(Point2d origin, Point2d nodePos, float distance) { + float newY; + if (origin.getY() < nodePos.getY()) { + newY = nodePos.getY() - distance; + } + else { + newY = nodePos.getY() + distance; + } + return Point2d.of(origin.getX(), newY); + } + + private static boolean isSameElevation(Point newNode, Map.Entry> cluster) { + return cluster.getValue().stream().allMatch(node -> Math.abs(node.unit().getPosition().getZ() - newNode.getZ()) < 1.2); + } } diff --git a/ocraft-s2client-bot/src/test/java/com/github/ocraft/s2client/bot/gateway/QueryInterfaceTest.java b/ocraft-s2client-bot/src/test/java/com/github/ocraft/s2client/bot/gateway/QueryInterfaceTest.java index c3109181..4940987e 100644 --- a/ocraft-s2client-bot/src/test/java/com/github/ocraft/s2client/bot/gateway/QueryInterfaceTest.java +++ b/ocraft-s2client-bot/src/test/java/com/github/ocraft/s2client/bot/gateway/QueryInterfaceTest.java @@ -27,6 +27,7 @@ */ import com.github.ocraft.s2client.protocol.spatial.Point; +import com.github.ocraft.s2client.protocol.spatial.Point2d; import com.github.ocraft.s2client.protocol.unit.Tag; import org.junit.jupiter.api.Test; @@ -46,13 +47,13 @@ void clustersUnits() { UnitInPool unit03 = new UnitInPool(Tag.of(3L)).update(mockUnit(Point.of(0.5f, 0.1f, 0.0f)), 0, true); UnitInPool unit04 = new UnitInPool(Tag.of(4L)).update(mockUnit(Point.of(9.5f, 5.2f, 3.1f)), 0, true); - Map> clusters = QueryInterface.cluster(List.of(unit01, unit02, unit03, unit04), 1.0f); + Map> clusters = QueryInterface.cluster(List.of(unit01, unit02, unit03, unit04), 1.0f); - Map> expectedClusters = Map.of( - Point.of(0.4f, 0.05f, 0.1f), List.of(unit02, unit03), - Point.of(9.75f, 5.1f, 3.05f), List.of(unit01, unit04)); + Map> expectedClusters = Map.of( + Point2d.of(0.4f, 0.05f), List.of(unit02, unit03), + Point2d.of(9.75f, 5.1f), List.of(unit01, unit04) + ); assertThat(clusters).containsAllEntriesOf(expectedClusters); - } } diff --git a/ocraft-s2client-protocol/pom.xml b/ocraft-s2client-protocol/pom.xml index 61779d84..c2fb04a5 100644 --- a/ocraft-s2client-protocol/pom.xml +++ b/ocraft-s2client-protocol/pom.xml @@ -3,7 +3,7 @@ ocraft-s2client com.github.ocraft - 0.4.21-SNAPSHOT + 0.4.22-SNAPSHOT 4.0.0 diff --git a/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point.java b/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point.java index 750ab721..34425064 100644 --- a/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point.java +++ b/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point.java @@ -105,6 +105,10 @@ public Point add(Point pointToAdd) { return new Point(x + pointToAdd.getX(), y + pointToAdd.getY(), z + pointToAdd.getZ()); } + public Point add(float addX, float addY, float addZ) { + return new Point(x + addX, y + addY, z + addZ); + } + public Point sub(Point pointToSubtract) { return new Point(x - pointToSubtract.getX(), y - pointToSubtract.getY(), z - pointToSubtract.getZ()); } @@ -151,9 +155,9 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = (x != +0.0f ? Float.floatToIntBits(x) : 0); - result = 31 * result + (y != +0.0f ? Float.floatToIntBits(y) : 0); - result = 31 * result + (z != +0.0f ? Float.floatToIntBits(z) : 0); + int result = (x != 0.0f ? Float.floatToIntBits(x) : 0); + result = 31 * result + (y != 0.0f ? Float.floatToIntBits(y) : 0); + result = 31 * result + (z != 0.0f ? Float.floatToIntBits(z) : 0); return result; } diff --git a/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point2d.java b/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point2d.java index 1c5ed0c9..d6de4b3c 100644 --- a/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point2d.java +++ b/ocraft-s2client-protocol/src/main/java/com/github/ocraft/s2client/protocol/spatial/Point2d.java @@ -29,6 +29,7 @@ import SC2APIProtocol.Common; import com.github.ocraft.s2client.protocol.Sc2ApiSerializable; import com.github.ocraft.s2client.protocol.Strings; +import com.github.ocraft.s2client.protocol.unit.Unit; import static com.github.ocraft.s2client.protocol.DataExtractor.tryGet; import static com.github.ocraft.s2client.protocol.Errors.required; @@ -110,10 +111,7 @@ public Point2d mul(float mulBy) { } public double distance(Point2d b) { - float x1 = x - b.getX(); - float y1 = y - b.getY(); - - return Math.sqrt(x1 * x1 + y1 * y1); + return Math.hypot(x - b.getX(), y - b.getY()); } public float dot(Point2d b) { @@ -124,6 +122,78 @@ public Point toPoint(float z) { return Point.of(x, y, z); } + public float getAngle(Unit b) { + return getAngle(b.getPosition().toPoint2d()); + } + // 0 = right, pi/2 = up, pi = left, 3pi/2 = down + public float getAngle(Point2d b) { + return (float)((Math.atan2(b.getY() - y, b.getX() - x) + Math.PI*2) % (Math.PI*2)); + } + + public Point2d addDistanceByAngle(double angleInRads, float distance) { + return Point2d.of( + distance * (float)Math.cos(angleInRads) + x, + distance * (float)Math.sin(angleInRads) + y + ); + } + + public Point2d midPoint(Point2d b) { + return this.add(b).div(2); + } + + public Point2d rotate(Point2d pivotPoint, double angleInRads) { + double sin = Math.sin(angleInRads); + double cos = Math.cos(angleInRads); + + //subtract pivot point + Point2d origin = this.sub(pivotPoint); + + //rotate point + float xNew = (float)(origin.getX() * cos - origin.getY() * sin); + float yNew = (float)(origin.getX() * sin + origin.getY() * cos); + + //add back the pivot point + float x = xNew + pivotPoint.getX(); + float y = yNew + pivotPoint.getY(); + + return Point2d.of(x, y); + } + + public Point2d roundToHalfPointAccuracy() { + return Point2d.of(Math.round(x * 2) / 2f, Math.round(y * 2) / 2f); + } + + //useful for 1x1, 3x3, and 5x5 structure placements + public Point2d toNearestHalfPoint() { + return Point2d.of((int)x + 0.5f, (int)y + 0.5f); + } + + //useful for 2x2 structure placements + public Point2d toNearestWholePoint() { + return Point2d.of(Math.round(x), Math.round(y)); + } + + public Point2d towards(Unit b, float distance) { + return towards(b.getPosition().toPoint2d(), distance); + } + + public Point2d towards(Point2d b, float distance) { + if (this.equals(b)) { + return b; + } + Point2d vector = unitVector(b); + return this.add(vector.mul(distance)); + } + + public Point2d unitVector(Point2d b) { + return b.sub(this).normalize(); + } + + public Point2d normalize() { + float length = (float)Math.hypot(x, y); + return this.div(length); + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -137,8 +207,8 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = (x != +0.0f ? Float.floatToIntBits(x) : 0); - result = 31 * result + (y != +0.0f ? Float.floatToIntBits(y) : 0); + int result = (x != 0.0f ? Float.floatToIntBits(x) : 0); + result = 31 * result + (y != 0.0f ? Float.floatToIntBits(y) : 0); return result; } diff --git a/ocraft-s2client-sample/pom.xml b/ocraft-s2client-sample/pom.xml index 54e5b6d4..86798d3a 100644 --- a/ocraft-s2client-sample/pom.xml +++ b/ocraft-s2client-sample/pom.xml @@ -3,7 +3,7 @@ ocraft-s2client com.github.ocraft - 0.4.21-SNAPSHOT + 0.4.22-SNAPSHOT 4.0.0 diff --git a/ocraft-s2client-test/pom.xml b/ocraft-s2client-test/pom.xml index e3c184fd..0c386a9b 100644 --- a/ocraft-s2client-test/pom.xml +++ b/ocraft-s2client-test/pom.xml @@ -3,7 +3,7 @@ ocraft-s2client com.github.ocraft - 0.4.21-SNAPSHOT + 0.4.22-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 34669466..cc323309 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.ocraft ocraft-s2client pom - 0.4.21-SNAPSHOT + 0.4.22-SNAPSHOT ocraft-s2client-test