Skip to content

Commit 28a9e70

Browse files
Prepare release for the next version (#13)
* Update bom usage * Update version and group definition * Update cyano definition * Add generic layer for file tests * Add new test case * Implement new method and deprecate one * Fix wrong import * Add classes to handle custom data loading for our map part # Conflicts: # src/main/java/net/theevilreaper/aves/map/AbstractMapProvider.java # src/main/java/net/theevilreaper/aves/map/MapProvider.java # src/main/java/net/theevilreaper/aves/util/functional/PathFilter.java * Small improvements * Add test for the new provider * Remove debug * Fix tests * Change annotation usage to NotNull * Update variable visibility * Fix test execution * Move TestMapProvider class * Disable some assert calls * Use junit launcher from the provided bom * Update version usage in the readme file * Update version to 1.8.0 --------- Co-authored-by: theEvilReaper <steffenwx@gmail.com>
1 parent 69c26e7 commit 28a9e70

14 files changed

Lines changed: 467 additions & 43 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Add the following dependency to your `build.gradle.kts` file:
3434

3535
```kotlin
3636
dependencies {
37-
implementation("net.theevilreaper.aves:aves:1.6.1")
37+
implementation("net.theevilreaper.aves:aves:<version>")
3838
}
3939
```
4040

build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ plugins {
66
alias(libs.plugins.publishdata)
77
}
88

9-
group = "net.theevilreaper.aves"
10-
version = "1.7.0"
9+
group = "net.theevilreaper"
10+
version = "1.8.0"
1111
description = "Aves"
1212

1313
java {
@@ -21,11 +21,11 @@ configurations.all {
2121
}
2222

2323
dependencies {
24-
implementation(platform(libs.bom.base))
24+
implementation(platform(libs.mycelium.bom))
2525
compileOnly(libs.adventure)
2626
compileOnly(libs.minestom)
2727

28-
testImplementation(platform(libs.bom.base))
28+
testImplementation(platform(libs.mycelium.bom))
2929
testImplementation(libs.adventure)
3030
testImplementation(libs.minestom)
3131
testImplementation(libs.cyano)

settings.gradle.kts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ dependencyResolutionManagement {
2626
}
2727
versionCatalogs {
2828
create("libs") {
29-
version("bom", "1.2.0")
30-
version("junit.platform", "1.12.2")
29+
version("bom", "1.2.3")
3130
version("publishdata", "1.4.0")
3231

33-
library("bom.base", "net.onelitefeather.mycelium.bom", "mycelium-bom").versionRef("bom")
32+
library("mycelium.bom", "net.onelitefeather", "mycelium-bom").versionRef("bom")
3433
library("minestom","net.minestom", "minestom-snapshots").withoutVersion()
3534
library("adventure", "net.kyori", "adventure-text-minimessage").withoutVersion()
36-
library("cyano", "net.onelitefeather.cyano", "cyano").withoutVersion()
35+
library("cyano", "net.onelitefeather", "cyano").withoutVersion()
3736
library("junit-jupiter", "org.junit.jupiter", "junit-jupiter").withoutVersion()
3837
library("junit-jupiter-engine", "org.junit.jupiter", "junit-jupiter-engine").withoutVersion()
39-
library("junit.platform.launcher", "org.junit.platform", "junit-platform-launcher").versionRef("junit.platform")
38+
library("junit.platform.launcher", "org.junit.platform", "junit-platform-launcher").withoutVersion()
39+
4040
plugin("publishdata", "de.chojo.publishdata").versionRef("publishdata")
4141
}
4242
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package net.theevilreaper.aves.map;
2+
3+
import net.theevilreaper.aves.file.FileHandler;
4+
import net.theevilreaper.aves.util.functional.PathFilter;
5+
import net.minestom.server.MinecraftServer;
6+
import net.minestom.server.coordinate.Pos;
7+
import net.minestom.server.entity.Player;
8+
import net.minestom.server.instance.Instance;
9+
import net.minestom.server.instance.InstanceContainer;
10+
import net.minestom.server.instance.anvil.AnvilLoader;
11+
import org.jetbrains.annotations.NotNull;
12+
import org.jetbrains.annotations.Nullable;
13+
import org.jetbrains.annotations.UnmodifiableView;
14+
import org.slf4j.Logger;
15+
import org.slf4j.LoggerFactory;
16+
17+
import java.io.IOException;
18+
import java.nio.file.Files;
19+
import java.nio.file.Path;
20+
import java.util.ArrayList;
21+
import java.util.Collections;
22+
import java.util.List;
23+
import java.util.function.Supplier;
24+
import java.util.stream.Stream;
25+
26+
/**
27+
* Abstract base implementation of {@link MapProvider} for managing map lifecycles
28+
* within a server session. Handles loading map entries from disk, registering map
29+
* instances, and providing access to the currently active map and instance.
30+
* <p>
31+
* Subclasses should implement logic for switching maps and managing map-specific data.
32+
* </p>
33+
*
34+
* @author theEvilReaper
35+
* @version 1.0.0
36+
* @since 1.6.0
37+
*/
38+
public abstract class AbstractMapProvider implements MapProvider {
39+
40+
private static final Logger MAP_LOGGER = LoggerFactory.getLogger(AbstractMapProvider.class);
41+
42+
private final PathFilter<MapEntry> mapFilter;
43+
44+
protected FileHandler fileHandler;
45+
protected List<MapEntry> mapEntries;
46+
47+
protected BaseMap activeMap;
48+
protected InstanceContainer activeInstance;
49+
50+
/**
51+
* Constructs a BaseMapProvider with the specified FileHandler.
52+
*
53+
* @param fileHandler the {@link FileHandler} used to load and save maps
54+
* @param mapFilter the filtering logic for the map entries
55+
*/
56+
protected AbstractMapProvider(@NotNull FileHandler fileHandler, @NotNull PathFilter<MapEntry> mapFilter) {
57+
this.fileHandler = fileHandler;
58+
this.mapFilter = mapFilter;
59+
}
60+
61+
/**
62+
* Registers the specified map entry as an active instance in the server.
63+
* Sets up chunk loading and time rate, and registers the instance with the server manager.
64+
*
65+
* @param instance the instance to be registered; must not be null
66+
* @param mapEntry the map entry representing the world data; must not be null
67+
*/
68+
protected void registerInstance(@NotNull InstanceContainer instance, @NotNull MapEntry mapEntry) {
69+
instance.setChunkLoader(new AnvilLoader(mapEntry.getDirectoryRoot()));
70+
instance.enableAutoChunkLoad(true);
71+
instance.setTimeRate(0);
72+
MinecraftServer.getInstanceManager().registerInstance(instance);
73+
}
74+
75+
/**
76+
* Loads all available map entries from the specified directory.
77+
* Only directories passing the configured map filter are included.
78+
* Handles IO exceptions gracefully by logging and reporting to the server exception manager.
79+
*
80+
* @param path the root directory containing map folders; must not be null
81+
* @return a list of map entries found in the directory, possibly empty but never null
82+
*/
83+
protected @NotNull List<MapEntry> loadMapEntries(@NotNull Path path) {
84+
List<MapEntry> givenMaps = new ArrayList<>();
85+
try (Stream<Path> stream = Files.list(path)) {
86+
givenMaps.addAll(this.mapFilter.filter(stream.filter(Files::isDirectory)));
87+
} catch (IOException exception) {
88+
MinecraftServer.getExceptionManager().handleException(exception);
89+
MAP_LOGGER.error("Unable to load maps from path {}", path, exception);
90+
}
91+
return givenMaps;
92+
}
93+
94+
@Override
95+
public void teleportToSpawn(@NotNull Player player, boolean instanceSet) {
96+
Pos pos = this.activeMap.getSpawnOrDefault(FALLBACK_POS);
97+
if (!instanceSet) {
98+
player.teleport(pos);
99+
return;
100+
}
101+
player.setInstance(this.activeInstance, pos);
102+
}
103+
104+
@Override
105+
public @UnmodifiableView @NotNull List<MapEntry> getEntries() {
106+
if (this.mapEntries == null) return Collections.emptyList();
107+
return Collections.unmodifiableList(this.mapEntries);
108+
}
109+
110+
@Override
111+
public @NotNull Supplier<@Nullable Instance> getActiveInstance() {
112+
return () -> this.activeInstance;
113+
}
114+
}
115+

src/main/java/net/theevilreaper/aves/map/BaseMap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public boolean hasSpawn() {
175175
* @param defaultSpawn the default spawn location
176176
* @return the spawn location or the default spawn location
177177
*/
178-
public @Nullable Pos getSpawnOrDefault(@NotNull Pos defaultSpawn) {
178+
public @NotNull Pos getSpawnOrDefault(@NotNull Pos defaultSpawn) {
179179
return spawn != null ? spawn : defaultSpawn;
180180
}
181181
}

src/main/java/net/theevilreaper/aves/map/BaseMapEntry.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import org.jetbrains.annotations.NotNull;
44
import org.jetbrains.annotations.Nullable;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
57

8+
import java.io.IOException;
69
import java.nio.file.Files;
710
import java.nio.file.Path;
811

@@ -16,6 +19,8 @@
1619
*/
1720
public final class BaseMapEntry implements MapEntry {
1821

22+
private static final Logger LOGGER = LoggerFactory.getLogger(BaseMapEntry.class);
23+
1924
private final String mapFileNaming;
2025
private final Path directory;
2126
private Path mapFilePath;
@@ -39,6 +44,18 @@ public final class BaseMapEntry implements MapEntry {
3944
}
4045
}
4146

47+
@Override
48+
public void createFile() {
49+
if (this.mapFilePath != null && Files.exists(mapFilePath)) return;
50+
51+
try {
52+
this.mapFilePath = directory.resolve(mapFileNaming);
53+
Files.createFile(this.mapFilePath);
54+
} catch (IOException exception) {
55+
LOGGER.warn("Could not create map file for path {}", mapFilePath, exception);
56+
}
57+
}
58+
4259
/**
4360
* Refreshes the map entry. It will check if the map file exists.
4461
*/

src/main/java/net/theevilreaper/aves/map/MapEntry.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,16 @@ public sealed interface MapEntry permits BaseMapEntry {
4444
return new BaseMapEntry(directoryRoot, mapFileNaming);
4545
}
4646

47+
/**
48+
* Creates a new MapEntry from the given path.
49+
*/
50+
void createFile();
51+
4752
/**
4853
* If the method is called the entry checks if the data file exists.
4954
* This can be used to update the path references in special cases.
5055
*/
56+
@Deprecated(forRemoval = true, since = "Please use createFile instead")
5157
void refresh();
5258

5359
/**
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package net.theevilreaper.aves.map;
2+
3+
import net.minestom.server.coordinate.Pos;
4+
import net.minestom.server.entity.Player;
5+
import net.minestom.server.instance.Instance;
6+
import org.jetbrains.annotations.NotNull;
7+
import org.jetbrains.annotations.Nullable;
8+
import org.jetbrains.annotations.UnmodifiableView;
9+
10+
import java.nio.file.Path;
11+
import java.util.List;
12+
import java.util.function.Supplier;
13+
14+
/**
15+
* The {@link MapProvider} interface is responsible for managing the available maps.
16+
* It will load all maps data from the given path and store them.
17+
* It would not load the map itself over a {@link net.minestom.server.instance.anvil.AnvilLoader} instance.
18+
* This behavior is handled by another class.
19+
*
20+
* @author theEvilReaper
21+
* @version 1.0.0
22+
* @since 1.6.0
23+
*/
24+
public interface MapProvider {
25+
26+
Pos FALLBACK_POS = new Pos(0, 100, 0);
27+
28+
/**
29+
* Saves the given data from a {@link BaseMap} to the given path.
30+
*
31+
* @param path the path where the map data should be saved
32+
* @param baseMap the map data which should be saved
33+
*/
34+
void saveMap(@NotNull Path path, @NotNull BaseMap baseMap);
35+
36+
/**
37+
* Teleports a {@link Player} to the current active spawn position of the {@link Instance}.
38+
*
39+
* @param player the player which should be teleported
40+
* @param instanceSet if the instance should be set to the current active instance
41+
*/
42+
void teleportToSpawn(@NotNull Player player, boolean instanceSet);
43+
44+
/**
45+
* Returns a {@link List} which contains all available maps as {@link MapEntry} objects.
46+
*
47+
* @return the given list of maps
48+
*/
49+
@UnmodifiableView
50+
@NotNull List<MapEntry> getEntries();
51+
52+
/**
53+
* Returns the current active {@link Instance} which is used for the game.
54+
*
55+
* @return the current active instance
56+
*/
57+
@NotNull Supplier<@Nullable Instance> getActiveInstance();
58+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package net.theevilreaper.aves.util.functional;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
5+
import java.nio.file.Path;
6+
import java.util.List;
7+
import java.util.stream.Stream;
8+
9+
/**
10+
* The {@link PathFilter<T>} is a functional interface that can be used to bind a filter logic to a method reference.
11+
* It can be used for filtering a {@link Stream} of {@link Path} objects and returning a list of {@link T} objects.
12+
*
13+
* @param <T> the type of the objects to be filtered
14+
* @author theEvilReaper
15+
* @version 1.0.0
16+
* @since 1.0.0
17+
*/
18+
@FunctionalInterface
19+
public interface PathFilter<T> {
20+
21+
/**
22+
* Filters the given stream of map paths and returns a list of {@link T} objects.
23+
*
24+
* @param stream the stream of map paths to filter
25+
* @return a list of filtered {@link T} objects
26+
*/
27+
@NotNull List<T> filter(@NotNull Stream<Path> stream);
28+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package net.theevilreaper.aves;
2+
3+
import org.junit.jupiter.api.AfterEach;
4+
import org.junit.jupiter.api.io.TempDir;
5+
6+
import java.io.IOException;
7+
import java.nio.file.DirectoryStream;
8+
import java.nio.file.Files;
9+
import java.nio.file.Path;
10+
11+
/**
12+
* The {@link FileTestBase} is a base class for all tests that need a temporary directory.
13+
* It will create a temporary directory for each test and delete it after the test is finished.
14+
*
15+
* @author theEvilReaper
16+
* @version 1.0.0
17+
* @since 1.6.1
18+
*/
19+
public abstract class FileTestBase {
20+
21+
@TempDir
22+
protected Path tempDir;
23+
24+
@AfterEach
25+
void tearDown() {
26+
try (DirectoryStream<Path> stream = Files.newDirectoryStream(tempDir)) {
27+
for (Path file : stream) {
28+
Files.delete(file);
29+
}
30+
} catch (IOException exception) {
31+
exception.printStackTrace();
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)