Skip to content

Commit c16ee1b

Browse files
authored
Merge pull request #2669 from BentoBoxWorld/develop
Release 3.3.5
2 parents 6efff6b + 8e90c15 commit c16ee1b

File tree

18 files changed

+441
-130
lines changed

18 files changed

+441
-130
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ jobs:
3636
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
3737
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
3838
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=BentoBoxWorld_BentoBox
39+
- name: Debug - List target directory
40+
run: ls -la /home/runner/work/BentoBox/BentoBox/target
3941
- run: mvn --batch-mode clean org.jacoco:jacoco-maven-plugin:prepare-agent install
4042
- run: mkdir staging && cp target/*.jar staging
4143
- name: Save artifacts

.github/workflows/modrinth-publish.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ jobs:
2525

2626
- name: Build and package with Maven
2727
run: mvn -B clean package -DskipTests -Pmaster --file pom.xml
28-
28+
- name: Debug - List target directory
29+
run: ls -la /home/runner/work/BentoBox/BentoBox/target
2930
- name: Upload to Modrinth
3031
uses: cloudnode-pro/modrinth-publish@v2
3132
with:

pom.xml

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
<!-- Do not change unless you want different name for local builds. -->
7575
<build.number>-LOCAL</build.number>
7676
<!-- This allows to change between versions. -->
77-
<build.version>3.3.4</build.version>
77+
<build.version>3.3.5</build.version>
7878
<sonar.organization>bentobox-world</sonar.organization>
7979
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
8080
<server.jars>${project.basedir}/lib</server.jars>
@@ -161,6 +161,17 @@
161161
<id>MG-Dev Jenkins CI Maven Repository</id>
162162
<url>https://ci.mg-dev.eu/plugin/repository/everything</url>
163163
</repository>
164+
<!-- Used for Multiverse hook -->
165+
<repository>
166+
<id>multiverse-multiverse-releases</id>
167+
<name>Multiverse Repository</name>
168+
<url>https://repo.onarandombox.com/multiverse-releases</url>
169+
</repository>
170+
<repository>
171+
<id>multiverse-multiverse-snapshots</id>
172+
<name>Multiverse Repository</name>
173+
<url>https://repo.onarandombox.com/multiverse-snapshots</url>
174+
</repository>
164175
<!-- For MythicMobs -->
165176
<repository>
166177
<id>nexus</id>
@@ -304,11 +315,29 @@
304315
<version>5.3.5</version>
305316
<scope>provided</scope>
306317
</dependency>
318+
<dependency>
319+
<groupId>org.mvplugins.multiverse.core</groupId>
320+
<artifactId>multiverse-core</artifactId>
321+
<version>5.0.0-SNAPSHOT</version>
322+
<scope>provided</scope>
323+
</dependency>
324+
<dependency>
325+
<groupId>com.onarandombox.multiversecore</groupId>
326+
<artifactId>multiverse-core</artifactId>
327+
<version>4.3.16</version>
328+
<scope>provided</scope>
329+
</dependency>
307330
<!-- Shaded APIs -->
331+
<!--
308332
<dependency>
309333
<groupId>com.github.TheBusyBiscuit</groupId>
310334
<artifactId>GitHubWebAPI4Java</artifactId>
311335
<version>${githubapi.version}</version>
336+
</dependency>-->
337+
<dependency>
338+
<groupId>javax.xml.bind</groupId>
339+
<artifactId>jaxb-api</artifactId>
340+
<version>2.3.0</version>
312341
</dependency>
313342
<dependency>
314343
<groupId>com.github.Marcono1234</groupId>
@@ -512,10 +541,10 @@
512541
<pattern>org.bstats</pattern>
513542
<shadedPattern>world.bentobox.bentobox.util.metrics</shadedPattern>
514543
</relocation>
515-
<relocation>
544+
<!-- <relocation>
516545
<pattern>io.github.TheBusyBiscuit.GitHubWebAPI4Java</pattern>
517546
<shadedPattern>world.bentobox.bentobox.api.github</shadedPattern>
518-
</relocation>
547+
</relocation>-->
519548
<relocation>
520549
<pattern>io.papermc.lib</pattern>
521550
<shadedPattern>world.bentobox.bentobox.paperlib</shadedPattern>

src/main/java/world/bentobox/bentobox/BentoBox.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
import world.bentobox.bentobox.hooks.FancyNpcsHook;
2828
import world.bentobox.bentobox.hooks.ItemsAdderHook;
2929
import world.bentobox.bentobox.hooks.MultipaperHook;
30-
import world.bentobox.bentobox.hooks.MultiverseCoreHook;
30+
import world.bentobox.bentobox.hooks.MultiverseCore4Hook;
31+
import world.bentobox.bentobox.hooks.MultiverseCore5Hook;
3132
import world.bentobox.bentobox.hooks.MyWorldsHook;
3233
import world.bentobox.bentobox.hooks.MythicMobsHook;
3334
import world.bentobox.bentobox.hooks.SlimefunHook;
@@ -233,7 +234,11 @@ private void completeSetup(long loadTime) {
233234

234235
// Register Multiverse hook - MV loads AFTER BentoBox
235236
// Make sure all worlds are already registered to Multiverse.
236-
hooksManager.registerHook(new MultiverseCoreHook());
237+
if (hasClass("org.mvplugins.multiverse.core.MultiverseCore")) {
238+
hooksManager.registerHook(new MultiverseCore5Hook());
239+
} else if (hasClass("com.onarandombox.MultiverseCore.MultiverseCore")) {
240+
hooksManager.registerHook(new MultiverseCore4Hook());
241+
}
237242
hooksManager.registerHook(new MyWorldsHook());
238243
islandWorldManager.registerWorldsToMultiverse(true);
239244

@@ -281,6 +286,15 @@ private void completeSetup(long loadTime) {
281286
}
282287
}
283288

289+
private boolean hasClass(String className) {
290+
try {
291+
Class.forName(className);
292+
return true;
293+
} catch (ClassNotFoundException e) {
294+
return false;
295+
}
296+
}
297+
284298
private void fireCriticalError(String message, String error) {
285299
logError("*****************CRITICAL ERROR!******************");
286300
logError(message);

src/main/java/world/bentobox/bentobox/api/commands/admin/range/AdminRangeDisplayCommand.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import world.bentobox.bentobox.api.commands.CompositeCommand;
1414
import world.bentobox.bentobox.api.user.User;
1515
import world.bentobox.bentobox.database.objects.Island;
16-
import world.bentobox.bentobox.util.Util;
1716

1817
/**
1918
* @author Poslovitch
@@ -24,9 +23,8 @@ public class AdminRangeDisplayCommand extends CompositeCommand {
2423
private static final String DISPLAY = "display";
2524
private static final String SHOW = "show";
2625
private static final String HIDE = "hide";
27-
public static final Particle PARTICLE = Util.findFirstMatchingEnum(Particle.class, "REDSTONE", "DUST");
28-
private static final Particle PARTICLE2 = Util.findFirstMatchingEnum(Particle.class, "VILLAGER_HAPPY",
29-
"HAPPY_VILLAGER");
26+
public static final Particle PARTICLE = Particle.DUST;
27+
private static final Particle PARTICLE2 = Particle.DUST;
3028

3129
// Map of users to which ranges must be displayed
3230
private final Map<User, Integer> displayRanges = new HashMap<>();
@@ -80,7 +78,8 @@ private void showZones(User user) {
8078

8179
// Draw the default protected area if island protected zone is different
8280
if (island.getProtectionRange() != getPlugin().getIWM().getIslandProtectionRange(getWorld())) {
83-
drawZone(user, PARTICLE2, null, island, getPlugin().getIWM().getIslandProtectionRange(getWorld()));
81+
drawZone(user, PARTICLE2, new Particle.DustOptions(Color.GREEN, 1.0F), island,
82+
getPlugin().getIWM().getIslandProtectionRange(getWorld()));
8483
}
8584

8685
// Draw the island area
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package world.bentobox.bentobox.api.github;
2+
3+
import java.io.IOException;
4+
import java.net.HttpURLConnection;
5+
import java.net.URL;
6+
import java.util.Scanner;
7+
import java.util.concurrent.CompletableFuture;
8+
import java.util.concurrent.ExecutorService;
9+
import java.util.concurrent.Executors;
10+
11+
import com.google.gson.JsonObject;
12+
import com.google.gson.JsonParser;
13+
14+
import world.bentobox.bentobox.api.github.objects.repositories.GitHubRepository;
15+
16+
/**
17+
* Handles interactions with the GitHub API.
18+
* This is a rewrite of {@link https://github.com/Poslovitch/GitHubWebAPI4}, which is now out of date
19+
* and this code only implements parts that are used by BentoBox and not all of it.
20+
*/
21+
public class GitHubWebAPI {
22+
23+
private static final String API_BASE_URL = "https://api.github.com/";
24+
private static final long RATE_LIMIT_INTERVAL_MS = 1000; // 1 second
25+
private static long lastRequestTime = 0;
26+
27+
private final ExecutorService executor = Executors.newCachedThreadPool();
28+
29+
/**
30+
* Fetches the content of a given API endpoint.
31+
*
32+
* @param endpoint The API endpoint to fetch.
33+
* @return The JSON response as a JsonObject.
34+
* @throws IOException If an error occurs during the request.
35+
*/
36+
public synchronized JsonObject fetch(String endpoint) throws IOException {
37+
long currentTime = System.currentTimeMillis();
38+
long timeSinceLastRequest = currentTime - lastRequestTime;
39+
40+
if (timeSinceLastRequest < RATE_LIMIT_INTERVAL_MS) {
41+
try {
42+
Thread.sleep(RATE_LIMIT_INTERVAL_MS - timeSinceLastRequest);
43+
} catch (InterruptedException e) {
44+
Thread.currentThread().interrupt();
45+
throw new IOException("Thread interrupted while waiting for rate limit", e);
46+
}
47+
}
48+
49+
lastRequestTime = System.currentTimeMillis();
50+
51+
URL url = new URL(API_BASE_URL + endpoint);
52+
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
53+
connection.setRequestMethod("GET");
54+
connection.setRequestProperty("Accept", "application/vnd.github.v3+json");
55+
connection.setRequestProperty("User-Agent", "BentoBox"); // Add User-Agent header
56+
57+
int responseCode = connection.getResponseCode();
58+
if (responseCode == 403) {
59+
throw new IOException("GitHub API rate limit exceeded or access forbidden. Response code: " + responseCode);
60+
}
61+
62+
try (Scanner scanner = new Scanner(connection.getInputStream())) {
63+
String response = scanner.useDelimiter("\\A").next();
64+
return JsonParser.parseString(response).getAsJsonObject();
65+
}
66+
}
67+
68+
/**
69+
* Fetches the content of a given API endpoint asynchronously.
70+
*
71+
* @param endpoint The API endpoint to fetch.
72+
* @return A CompletableFuture containing the JSON response as a JsonObject.
73+
*/
74+
public CompletableFuture<JsonObject> fetchAsync(String endpoint) {
75+
return CompletableFuture.supplyAsync(() -> {
76+
try {
77+
return fetch(endpoint);
78+
} catch (IOException e) {
79+
throw new RuntimeException("Failed to fetch data from GitHub API", e);
80+
}
81+
}, executor);
82+
}
83+
84+
public GitHubRepository getRepository(String username, String repo) {
85+
return new GitHubRepository(this, username + "/" + repo);
86+
}
87+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package world.bentobox.bentobox.api.github.objects.repositories;
2+
3+
/**
4+
* Represents a contributor to a GitHub repository.
5+
*/
6+
public class GitHubContributor {
7+
8+
private final String username;
9+
private final int contributionsAmount;
10+
11+
public GitHubContributor(String username, int contributionsAmount) {
12+
this.username = username;
13+
this.contributionsAmount = contributionsAmount;
14+
}
15+
16+
public String getUsername() {
17+
return username;
18+
}
19+
20+
public int getContributionsAmount() {
21+
return contributionsAmount;
22+
}
23+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package world.bentobox.bentobox.api.github.objects.repositories;
2+
3+
import java.io.IOException;
4+
5+
import com.google.gson.JsonObject;
6+
7+
import world.bentobox.bentobox.api.github.GitHubWebAPI;
8+
9+
/**
10+
* Represents a file or a directory.
11+
*/
12+
public class GitHubFile {
13+
14+
private final GitHubWebAPI api;
15+
private final String path;
16+
17+
public GitHubFile(GitHubWebAPI api, GitHubRepository gitHubRepository, String fullpath) {
18+
this.api = api;
19+
this.path = "repos/" + gitHubRepository.getFullName() + fullpath;
20+
}
21+
22+
/**
23+
* Returns the content of this file.
24+
* @return the content of this file in Base64 or nothing if the connection to the GitHub API could not be established.
25+
* @throws IOException - If an error occurs during the request.
26+
*/
27+
public String getContent() throws IllegalAccessException {
28+
JsonObject response;
29+
try {
30+
response = api.fetch(path);
31+
} catch (IOException e) {
32+
// Cannot get a connection for some reason
33+
return "";
34+
}
35+
return response.get("content").getAsString();
36+
}
37+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package world.bentobox.bentobox.api.github.objects.repositories;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import com.google.gson.JsonArray;
7+
import com.google.gson.JsonObject;
8+
9+
import world.bentobox.bentobox.api.github.GitHubWebAPI;
10+
11+
/**
12+
* Represents a GitHub repository and provides methods to fetch its data.
13+
*/
14+
public class GitHubRepository {
15+
16+
private final GitHubWebAPI api;
17+
private final String fullName;
18+
19+
public GitHubRepository(GitHubWebAPI api, String fullName) {
20+
this.api = api;
21+
this.fullName = fullName;
22+
}
23+
24+
public String getFullName() {
25+
return fullName;
26+
}
27+
28+
/**
29+
* Fetches the content of a file in the repository.
30+
*
31+
* @param fpath The path to the file.
32+
* @return A GitHubFile object representing the file content.
33+
* @throws Exception If an error occurs during the request.
34+
*/
35+
public GitHubFile getContent(String path) throws Exception {
36+
return new GitHubFile(api, this, "/contents/" + path);
37+
}
38+
39+
/**
40+
* Fetches the list of contributors to the repository.
41+
*
42+
* @return A list of GitHubContributor objects.
43+
* @throws Exception If an error occurs during the request.
44+
*/
45+
public List<GitHubContributor> getContributors() throws Exception {
46+
JsonArray response = api.fetch("repos/" + fullName + "/contributors").getAsJsonArray();
47+
List<GitHubContributor> contributors = new ArrayList<>();
48+
response.forEach(element -> {
49+
JsonObject contributor = element.getAsJsonObject();
50+
contributors.add(new GitHubContributor(
51+
contributor.get("login").getAsString(),
52+
contributor.get("contributions").getAsInt()
53+
));
54+
});
55+
return contributors;
56+
}
57+
}

src/main/java/world/bentobox/bentobox/api/user/User.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.UUID;
1313
import java.util.regex.Matcher;
1414
import java.util.regex.Pattern;
15+
import java.util.stream.Collectors;
1516

1617
import org.apache.commons.lang.math.NumberUtils;
1718
import org.bukkit.Bukkit;
@@ -823,8 +824,10 @@ public boolean inWorld() {
823824
*/
824825
public void spawnParticle(Particle particle, @Nullable Object dustOptions, double x, double y, double z) {
825826
Class<?> expectedClass = VALIDATION_CHECK.get(particle);
826-
if (expectedClass == null)
827-
throw new IllegalArgumentException("Unexpected value: " + particle);
827+
if (expectedClass == null) {
828+
throw new IllegalArgumentException("Unexpected value: " + particle + "\nExpected one of:"
829+
+ VALIDATION_CHECK.keySet().stream().map(Particle::name).collect(Collectors.joining(", ")));
830+
}
828831

829832
if (!(expectedClass.isInstance(dustOptions))) {
830833
throw new IllegalArgumentException("A non-null " + expectedClass.getSimpleName()

0 commit comments

Comments
 (0)