55import com .google .gson .JsonObject ;
66import com .palmergames .bukkit .towny .TownyAPI ;
77import com .palmergames .bukkit .towny .TownySettings ;
8+ import com .palmergames .bukkit .towny .object .Nation ;
89import com .palmergames .bukkit .towny .object .Town ;
910import com .palmergames .bukkit .towny .object .TownBlock ;
1011import com .palmergames .bukkit .towny .object .WorldCoord ;
2324
2425import java .util .ArrayList ;
2526import java .util .List ;
27+ import java .util .Objects ;
2628
2729public class NearbyEndpoint extends PostEndpoint <NearbyContext > {
2830
@@ -43,89 +45,139 @@ public NearbyContext getObjectOrNull(JsonElement element, @Nullable String key)
4345 NearbyType searchType ;
4446 try {
4547 targetType = NearbyType .valueOf (targetTypeString );
48+ } catch (IllegalArgumentException ignored ) {
49+ throw new BadRequestResponse ("Invalid target type" );
50+ }
51+ try {
4652 searchType = NearbyType .valueOf (searchTypeString );
47- } catch (IllegalArgumentException e ) {
48- throw new BadRequestResponse ("Your target or search type is invalid" );
53+ if (searchType == NearbyType .COORDINATE ) {
54+ throw new BadRequestResponse ("Search type cannot be coordinate. Select town or nation." );
55+ }
56+ } catch (IllegalArgumentException ignored ) {
57+ throw new BadRequestResponse ("Invalid search type" );
4958 }
5059
5160 Integer radius = JSONUtil .getJsonElementAsIntegerOrNull (jsonObject .get ("radius" ));
52- if (radius == null ) throw new BadRequestResponse ("You did not specify a radius" );
61+ if (radius == null || radius < 0 ) throw new BadRequestResponse ("Invalid radius provided " );
5362
63+ boolean strict = Objects .requireNonNullElse (JSONUtil .getJsonElementAsBooleanOrNull (jsonObject .get ("strict" )), false );
5464 JsonElement targetElement = jsonObject .get ("target" );
55- if (targetType .equals (NearbyType .COORDINATE )) {
56- JsonArray jsonArray = JSONUtil .getJsonElementAsJsonArrayOrNull (targetElement );
57- if (jsonArray == null ) throw new BadRequestResponse ("Your target is not a valid JSON array" );
58-
59- Pair <Integer , Integer > pair = new Pair <>(jsonArray .get (0 ).getAsInt (), jsonArray .get (1 ).getAsInt ());
65+ return switch (targetType ) {
66+ case COORDINATE -> {
67+ JsonArray jsonArray = JSONUtil .getJsonElementAsJsonArrayOrNull (targetElement );
68+ if (jsonArray == null ) throw new BadRequestResponse ("Your target is not a valid JSON array" );
6069
61- return new NearbyContext (targetType , pair , searchType , radius );
62- } else if (targetType .equals (NearbyType .TOWN )) {
63- String target = JSONUtil .getJsonElementAsStringOrNull (targetElement );
64- if (target == null ) throw new BadRequestResponse ("Your target is not a valid string" );
70+ Pair <Integer , Integer > pair = new Pair <>(jsonArray .get (0 ).getAsInt (), jsonArray .get (1 ).getAsInt ());
6571
66- return new NearbyContext (targetType , target , searchType , radius );
67- }
72+ yield new NearbyContext (targetType , pair , searchType , radius , strict );
73+ }
74+ case TOWN , NATION -> {
75+ String target = JSONUtil .getJsonElementAsStringOrNull (targetElement );
76+ if (target == null ) throw new BadRequestResponse ("Your target is not a valid string" );
6877
69- return null ;
78+ yield new NearbyContext (targetType , target , searchType , radius , strict );
79+ }
80+ };
7081 }
7182
7283 @ Override
7384 public JsonElement getJsonElement (NearbyContext context , @ Nullable String key ) {
7485 NearbyType targetType = context .getTargetType ();
7586 int radius = context .getRadius ();
76- switch (targetType ) {
87+ NearbyType searchType = context .getSearchType ();
88+ boolean strict = context .isStrict ();
89+
90+ return switch (targetType ) {
7791 case COORDINATE -> {
7892 Pair <Integer , Integer > pair = context .getTargetCoordinate ();
7993
80- return lookupNearbyCoordinate (pair .getFirst (), pair .getSecond (), radius );
81- }
82- case TOWN -> {
83- String townName = context .getTargetString ();
84-
85- return lookupNearbyTown (townName , radius );
94+ yield lookupNearCoordinates (pair .getFirst (), pair .getSecond (), radius , strict , searchType );
8695 }
96+ case TOWN -> lookupNearTown (context .getTargetString (), radius , strict , searchType );
97+ case NATION -> lookupNearNation (context .getTargetString (), radius , strict , searchType );
8798 };
88-
89- return null ;
9099 }
91100
92- public JsonArray lookupNearbyCoordinate (Integer x , Integer z , Integer radius ) {
93- if (x == null || z == null ) throw new BadRequestResponse ("Invalid coordinates provided" );
94- if (radius == null || radius < 0 ) throw new BadRequestResponse ("Invalid radius provided" );
95-
96- Location location = new Location (Bukkit .getWorlds ().get (0 ), x , 0 , z );
101+ private JsonArray lookupNearCoordinates (int x , int z , int radius , boolean strict , NearbyType searchType ) {
102+ Location location = new Location (Bukkit .getWorlds ().getFirst (), x , 0 , z );
97103
98- return getJsonArrayOfNearbyTowns (WorldCoord .parseWorldCoord (location ), radius , null );
104+ WorldCoord worldCoord = WorldCoord .parseWorldCoord (location );
105+ return searchType == NearbyType .TOWN ? getJsonArrayOfNearbyTowns (worldCoord , radius , strict , null ) : getNearbyNations (worldCoord , radius , strict , null );
99106 }
100107
101- public JsonElement lookupNearbyTown (String townString , Integer radius ) {
108+ private JsonElement lookupNearTown (String townString , int radius , boolean strict , NearbyType searchType ) {
102109 if (townString == null ) throw new BadRequestResponse ("Invalid town provided" );
103110
104111 Town town = TownyAPI .getInstance ().getTown (townString );
105112 if (town == null ) throw new BadRequestResponse (townString + " is not a real town" );
106113
107- if (radius == null || radius < 0 ) throw new BadRequestResponse ("Invalid radius provided" );
108-
109114 TownBlock homeBlock = town .getHomeBlockOrNull ();
110115 if (homeBlock == null ) throw new BadRequestResponse ("The specified town has no homeblock" );
111116
112- return getJsonArrayOfNearbyTowns (homeBlock .getWorldCoord (), radius , town );
117+ return searchType == NearbyType . TOWN ? getJsonArrayOfNearbyTowns (homeBlock .getWorldCoord (), radius , strict , town ) : getNearbyNations ( homeBlock . getWorldCoord (), radius , strict , town . isCapital () ? town . getNationOrNull () : null );
113118 }
114119
115- private JsonArray getJsonArrayOfNearbyTowns ( WorldCoord worldCoord , int radius , Town town ) {
116- List < Town > towns = new ArrayList <>( );
120+ private JsonElement lookupNearNation ( String nationName , int radius , boolean strict , NearbyType searchType ) {
121+ if ( nationName == null ) throw new BadRequestResponse ( "Invalid nation provided" );
117122
118- for ( Town otherTown : TownyAPI .getInstance ().getTowns ()) {
119- if (town != null && town == otherTown ) continue ; // Don't add the town we are looking nearby
123+ Nation nation = TownyAPI .getInstance ().getNation ( nationName );
124+ if (nation == null ) throw new BadRequestResponse ( nationName + " is not a real nation" );
120125
121- TownBlock homeBlock = otherTown . getHomeBlockOrNull ();
122- if (homeBlock == null ) continue ;
126+ Town capital = nation . getCapital ();
127+ if (capital == null ) throw new BadRequestResponse ( "The specified nation has no capital" ) ;
123128
124- WorldCoord homeBlockWorldCoord = homeBlock .getWorldCoord ();
129+ TownBlock homeBlock = capital .getHomeBlockOrNull ();
130+ if (homeBlock == null ) throw new BadRequestResponse ("The specified nation's capital has no homeblock" );
125131
126- if (MathUtil .distance (worldCoord , homeBlockWorldCoord ) * TownySettings .getTownBlockSize () <= radius ) towns .add (otherTown );
132+ return searchType == NearbyType .TOWN ? getJsonArrayOfNearbyTowns (homeBlock .getWorldCoord (), radius , strict , capital ) : getNearbyNations (homeBlock .getWorldCoord (), radius , strict , nation );
133+ }
134+
135+ private JsonArray getJsonArrayOfNearbyTowns (WorldCoord center , int radius , boolean strict , Town excludeTown ) {
136+ List <Town > towns = new ArrayList <>();
137+
138+ for (Town town : TownyAPI .getInstance ().getTowns ()) {
139+ if (excludeTown != null && excludeTown .equals (town )) continue ;
140+
141+ if (isTownInRange (town , center , radius , strict )) {
142+ towns .add (town );
143+ }
127144 }
128145
129146 return EndpointUtils .getTownArray (towns );
130147 }
148+
149+ private JsonArray getNearbyNations (WorldCoord center , int radius , boolean strict , Nation excludeNation ) {
150+ List <Nation > nations = new ArrayList <>();
151+
152+ for (Nation nation : TownyAPI .getInstance ().getNations ()) {
153+ if (excludeNation != null && excludeNation .equals (nation )) continue ;
154+
155+ Town capital = nation .getCapital ();
156+ if (capital == null ) continue ;
157+
158+ if (isTownInRange (capital , center , radius , strict )) {
159+ nations .add (nation );
160+ }
161+ }
162+
163+ return EndpointUtils .getNationArray (nations );
164+ }
165+
166+ private boolean isTownInRange (Town town , WorldCoord center , int radius , boolean strict ) {
167+ TownBlock homeBlock = town .getHomeBlockOrNull ();
168+ if (homeBlock == null ) return false ;
169+ WorldCoord homeBlockWorldCoord = homeBlock .getWorldCoord ();
170+ double distance = MathUtil .distance (center , homeBlockWorldCoord ) * TownySettings .getTownBlockSize ();
171+ if (distance <= radius ) {
172+ return true ;
173+ }
174+ if (!strict && distance <= radius + 300 ) { // Homeblock is less than 300 blocks out of reach, check all the town's chunks
175+ for (TownBlock townBlock : town .getTownBlocks ()) {
176+ if (MathUtil .distance (center , townBlock .getWorldCoord ()) * TownySettings .getTownBlockSize () <= radius ) {
177+ return true ;
178+ }
179+ }
180+ }
181+ return false ;
182+ }
131183}
0 commit comments