Skip to content

Commit 5648211

Browse files
authored
Merge pull request #3488 from Multiverse/fix/spawn-category
Fix spawn category mapping changes in 26.2
2 parents ed96764 + 15453e6 commit 5648211

6 files changed

Lines changed: 87 additions & 39 deletions

File tree

.github/workflows/generic.platform_uploads.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ jobs:
107107
files: '["${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar"]'
108108
name: ${{ steps.release-info.outputs.tag_name }}
109109
changelog: ${{ steps.release-artifact.outputs.body }}
110-
game_versions: 26.1.2, 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
110+
game_versions: 26.2, 26.1.2, 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
111111
version_type: ${{ steps.parse-release-type.outputs.release_type }}
112112
loaders: bukkit, spigot, paper, purpur
113113
dependencies: ${{ inputs.modrinth_dependencies }}
@@ -121,7 +121,7 @@ jobs:
121121
changelog: ${{ steps.release-artifact.outputs.body }}
122122
changelog_type: markdown
123123
display_name: ${{ steps.release-info.outputs.tag_name }}
124-
game_versions: 26.1.2, 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
124+
game_versions: 26.2, 26.1.2, 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2
125125
release_type: ${{ steps.parse-release-type.outputs.release_type }}
126126
project_relations: ${{ inputs.dbo_project_relations }}
127127
file_path: ${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar
@@ -136,5 +136,5 @@ jobs:
136136
channel: ${{ steps.parse-release-type.outputs.release_type }}
137137
files: '[{"path": "${{ github.workspace }}/${{ inputs.plugin_name }}-${{ steps.release-info.outputs.tag_name }}.jar", "platforms": ["PAPER"]}]'
138138
description: ${{ steps.release-artifact.outputs.body }}
139-
platform_dependencies: '{"PAPER": ["1.18.2-26.1.2"]}'
139+
platform_dependencies: '{"PAPER": ["1.18.2-26.2"]}'
140140
plugin_dependencies: ${{ inputs.hangar_plugin_dependencies }}

src/main/java/org/mvplugins/multiverse/core/MultiverseCore.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.mvplugins.multiverse.core.module.MultiverseModule;
3131
import org.mvplugins.multiverse.core.utils.StringFormatter;
3232
import org.mvplugins.multiverse.core.world.WorldManager;
33+
import org.mvplugins.multiverse.core.world.entity.SpawnCategoryMapper;
3334
import org.mvplugins.multiverse.core.world.location.NullSpawnLocation;
3435
import org.mvplugins.multiverse.core.world.location.SpawnLocation;
3536
import org.mvplugins.multiverse.core.world.location.UnloadedWorldLocation;
@@ -86,6 +87,9 @@ public void onEnable() {
8687
super.onEnable();
8788
initializeDependencyInjection(new MultiverseCorePluginBinder(this));
8889

90+
// Build it here so our logger can work, and failure messages will be logged
91+
SpawnCategoryMapper.buildSpawnCategoryMap();
92+
8993
// Load our configs first as we need them for everything else.
9094
var config = configProvider.get();
9195
var loadSuccess = config.load().andThenTry(config::save).isSuccess();

src/main/java/org/mvplugins/multiverse/core/world/WorldsConfigManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ Try<Void> save() {
227227
worldsConfig = new YamlConfiguration();
228228
worldConfigMap.forEach((keyOrName, worldConfig) -> {
229229
worldConfig.save().onFailure(e -> {
230-
throw new RuntimeException("Failed to save world %s in config: " + keyOrName, e);
230+
throw new RuntimeException("Failed to save world " + keyOrName + " in config: " + e.getMessage(), e);
231231
});
232232
worldsConfig.set(encodeConfigKey(keyOrName), worldConfig.getConfigurationSection());
233233
});

src/main/java/org/mvplugins/multiverse/core/world/entity/EntitySpawnConfig.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.bukkit.entity.EntityType;
88
import org.bukkit.entity.SpawnCategory;
99
import org.jetbrains.annotations.ApiStatus;
10+
import org.jetbrains.annotations.NotNull;
1011
import org.mvplugins.multiverse.core.config.CoreConfig;
1112
import org.mvplugins.multiverse.core.utils.StringFormatter;
1213
import org.mvplugins.multiverse.core.world.MultiverseWorld;
@@ -20,12 +21,13 @@ public final class EntitySpawnConfig {
2021
private final CoreConfig config;
2122
private final Map<SpawnCategory, SpawnCategoryConfig> spawnCategoriesConfig;
2223

23-
EntitySpawnConfig(CoreConfig config, Map<SpawnCategory, SpawnCategoryConfig> spawnCategoriesConfig) {
24+
EntitySpawnConfig(@NotNull CoreConfig config,
25+
@NotNull Map<SpawnCategory, SpawnCategoryConfig> spawnCategoriesConfig) {
2426
this.config = config;
2527
this.spawnCategoriesConfig = spawnCategoriesConfig;
2628
}
2729

28-
public SpawnCategoryConfig getSpawnCategoryConfig(SpawnCategory spawnCategory) {
30+
public @NotNull SpawnCategoryConfig getSpawnCategoryConfig(@NotNull SpawnCategory spawnCategory) {
2931
return spawnCategoriesConfig.computeIfAbsent(spawnCategory,
3032
computeSpawnCategory -> new SpawnCategoryConfig(
3133
config,
@@ -35,12 +37,16 @@ public SpawnCategoryConfig getSpawnCategoryConfig(SpawnCategory spawnCategory) {
3537
}
3638

3739
@ApiStatus.AvailableSince("5.7")
38-
public boolean shouldAllowSpawn(EntityType entityType) {
39-
return getSpawnCategoryConfig(SpawnCategoryMapper.getSpawnCategory(entityType)).shouldAllowSpawn(entityType);
40+
public boolean shouldAllowSpawn(@NotNull EntityType entityType) {
41+
// Ensure it defaults to true if SpawnCategoryMapper fails to find a spawn category for the entity type,
42+
// to avoid accidentally breaking mob spawns.
43+
return SpawnCategoryMapper.getSpawnCategory(entityType)
44+
.map(spawnCategory -> getSpawnCategoryConfig(spawnCategory).shouldAllowSpawn(entityType))
45+
.getOrElse(true);
4046
}
4147

42-
public boolean shouldAllowSpawn(Entity entity) {
43-
return getSpawnCategoryConfig(entity.getSpawnCategory()).shouldAllowSpawn(entity);
48+
public boolean shouldAllowSpawn(@NotNull Entity entity) {
49+
return shouldAllowSpawn(entity.getType());
4450
}
4551

4652
public void applyConfigToWorld() {
@@ -57,16 +63,19 @@ public String toString() {
5763
}
5864

5965
@ApiStatus.Internal
60-
public ConfigurationSection toSection() {
66+
public @NotNull ConfigurationSection toSection() {
6167
MemoryConfiguration section = new MemoryConfiguration();
6268
spawnCategoriesConfig.forEach((spawnCategory, spawnCategoryConfig) -> {
63-
section.set(spawnCategory.toString().toLowerCase(Locale.ENGLISH), spawnCategoryConfig.saveSection());
69+
section.set(String.valueOf(spawnCategory).toLowerCase(Locale.ENGLISH), spawnCategoryConfig.saveSection());
6470
});
6571
return section;
6672
}
6773

6874
@ApiStatus.Internal
69-
public static EntitySpawnConfig fromSection(CoreConfig config, ConfigurationSection section) {
75+
public static @NotNull EntitySpawnConfig fromSection(
76+
@NotNull CoreConfig config,
77+
@NotNull ConfigurationSection section
78+
) {
7079
Map<SpawnCategory, SpawnCategoryConfig> spawnCategoriesConfig = new LinkedHashMap<>();
7180
Map<String, Object> existingCategories = section.getValues(false);
7281
for (SpawnCategory category : SpawnCategory.values()) {

src/main/java/org/mvplugins/multiverse/core/world/entity/SpawnCategoryConfig.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.bukkit.entity.Entity;
99
import org.bukkit.entity.EntityType;
1010
import org.bukkit.entity.SpawnCategory;
11+
import org.jetbrains.annotations.NotNull;
1112
import org.mvplugins.multiverse.core.config.CoreConfig;
1213
import org.mvplugins.multiverse.core.config.handle.MemoryConfigurationHandle;
1314
import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
@@ -32,7 +33,11 @@ public final class SpawnCategoryConfig {
3233

3334
private MultiverseWorld world;
3435

35-
SpawnCategoryConfig(CoreConfig config, SpawnCategory spawnCategory, ConfigurationSection section) {
36+
SpawnCategoryConfig(
37+
@NotNull CoreConfig config,
38+
@NotNull SpawnCategory spawnCategory,
39+
@NotNull ConfigurationSection section
40+
) {
3641
this.config = config;
3742
this.spawnCategory = spawnCategory;
3843
this.nodes = new Nodes();
@@ -67,7 +72,7 @@ void applyConfigToWorld() {
6772
});
6873
}
6974

70-
private void applyTickPerSpawns(World bukkitWorld) {
75+
private void applyTickPerSpawns(@NotNull World bukkitWorld) {
7176
if (!config.getApplyEntitySpawnLimit()) {
7277
Logging.finer("World %s %s skipping setTicksPerSpawns due to core config", world.getName(), spawnCategory);
7378
return;
@@ -85,7 +90,7 @@ private void applyTickPerSpawns(World bukkitWorld) {
8590
bukkitWorld.setTicksPerSpawns(spawnCategory, getTickRate());
8691
}
8792

88-
private void applySpawnLimit(World bukkitWorld) {
93+
private void applySpawnLimit(@NotNull World bukkitWorld) {
8994
if (!config.getApplyEntitySpawnLimit()) {
9095
Logging.finer("Skipping World %s %s setSpawnLimit due to core config", world.getName(), spawnCategory);
9196
return;
@@ -98,51 +103,51 @@ private void applySpawnLimit(World bukkitWorld) {
98103
bukkitWorld.setSpawnLimit(spawnCategory, getSpawnLimit());
99104
}
100105

101-
public StringPropertyHandle getStringPropertyHandle() {
106+
public @NotNull StringPropertyHandle getStringPropertyHandle() {
102107
return stringPropertyHandle;
103108
}
104109

105-
public SpawnCategory getSpawnCategory() {
110+
public @NotNull SpawnCategory getSpawnCategory() {
106111
return spawnCategory;
107112
}
108113

109114
public boolean isSpawn() {
110115
return handle.get(nodes.spawn);
111116
}
112117

113-
public Try<Void> setSpawn(boolean spawn) {
118+
public @NotNull Try<Void> setSpawn(boolean spawn) {
114119
return handle.set(nodes.spawn, spawn);
115120
}
116121

117122
public int getTickRate() {
118123
return handle.get(nodes.tickRate);
119124
}
120125

121-
public Try<Void> setTickRate(int tickRate) {
126+
public @NotNull Try<Void> setTickRate(int tickRate) {
122127
return handle.set(nodes.tickRate, tickRate);
123128
}
124129

125130
public int getSpawnLimit() {
126131
return handle.get(nodes.spawnLimit);
127132
}
128133

129-
public Try<Void> setSpawnLimit(int spawnLimit) {
134+
public @NotNull Try<Void> setSpawnLimit(int spawnLimit) {
130135
return handle.set(nodes.spawnLimit, spawnLimit);
131136
}
132137

133-
public List<EntityType> getExceptions() {
138+
public @NotNull List<EntityType> getExceptions() {
134139
return handle.get(nodes.exceptions);
135140
}
136141

137-
public Try<Void> setExceptions(List<EntityType> exceptions) {
142+
public @NotNull Try<Void> setExceptions(@NotNull List<EntityType> exceptions) {
138143
return handle.set(nodes.exceptions, exceptions);
139144
}
140145

141-
public boolean shouldAllowSpawn(Entity entity) {
146+
public boolean shouldAllowSpawn(@NotNull Entity entity) {
142147
return shouldAllowSpawn(entity.getType());
143148
}
144149

145-
public boolean shouldAllowSpawn(EntityType entityType) {
150+
public boolean shouldAllowSpawn(@NotNull EntityType entityType) {
146151
return isSpawn() != getExceptions().contains(entityType);
147152
}
148153

src/main/java/org/mvplugins/multiverse/core/world/entity/SpawnCategoryMapper.java

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package org.mvplugins.multiverse.core.world.entity;
22

33
import com.dumptruckman.minecraft.util.Logging;
4+
import io.vavr.control.Option;
45
import io.vavr.control.Try;
56
import org.bukkit.entity.EntityType;
67
import org.bukkit.entity.SpawnCategory;
8+
import org.jetbrains.annotations.ApiStatus;
9+
import org.jetbrains.annotations.NotNull;
710
import org.mvplugins.multiverse.core.utils.ReflectHelper;
811

12+
import javax.annotation.Nullable;
913
import java.lang.reflect.Method;
1014
import java.util.ArrayList;
1115
import java.util.Arrays;
@@ -17,23 +21,30 @@
1721
/**
1822
* Uses reflection into nms to map entity types to spawn categories.
1923
*/
20-
final class SpawnCategoryMapper {
24+
@ApiStatus.Internal
25+
public final class SpawnCategoryMapper {
2126

22-
private static final Map<EntityType, SpawnCategory> entityTypeToSpawnCategoryMap;
23-
private static final Map<SpawnCategory, List<EntityType>> spawnCategoryMap;
27+
private static final @NotNull Map<EntityType, SpawnCategory> entityTypeToSpawnCategoryMap;
28+
private static final @NotNull Map<SpawnCategory, List<EntityType>> spawnCategoryMap;
2429

2530
static {
2631
entityTypeToSpawnCategoryMap = new HashMap<>();
2732
spawnCategoryMap = new HashMap<>();
28-
buildSpawnCategoryMap();
2933
}
3034

31-
private static void buildSpawnCategoryMap() {
35+
public static void buildSpawnCategoryMap() {
3236
Class<?> entityTypeClass = ReflectHelper.tryGetClass("net.minecraft.world.entity.EntityType").getOrNull();
3337
if (entityTypeClass == null) {
3438
Logging.warning("Failed to find EntityType class. SpawnCategoryMapper will not work.");
3539
return;
3640
}
41+
// In 26.2, the list of static fields has been moved from EntityType to EntityTypes class.
42+
Class<?> entityTypesListClass = ReflectHelper.tryGetClass("net.minecraft.world.entity.EntityTypes").getOrNull();
43+
if (entityTypesListClass == null) {
44+
// Assume it's the older mc versions that has list of static fields in EntityType class instead.
45+
Logging.finer("Failed to find EntityTypes class. falling back to EntityType.");
46+
entityTypesListClass = entityTypeClass;
47+
}
3748
Method getCategoryMethod = ReflectHelper.tryGetMethod(entityTypeClass, "getCategory").getOrNull();
3849
if (getCategoryMethod == null) {
3950
Logging.warning("Failed to find getCategory method. SpawnCategoryMapper will not work.");
@@ -52,7 +63,10 @@ private static void buildSpawnCategoryMap() {
5263
Logging.warning("Failed to find toBukkit method. SpawnCategoryMapper will not work.");
5364
return;
5465
}
55-
Arrays.stream(entityTypeClass.getFields()).forEach(entityTypeField -> Try.of(() -> EntityType.valueOf(entityTypeField.getName()))
66+
67+
Logging.finer("Mapping entities to its spawn category...");
68+
69+
Arrays.stream(entityTypesListClass.getFields()).forEach(entityTypeField -> Try.of(() -> EntityType.valueOf(entityTypeField.getName()))
5670
.peek(entityType -> ReflectHelper.tryGetStaticFieldValue(entityTypeField, entityTypeClass)
5771
.flatMap(nmsEntityType -> ReflectHelper.tryInvokeMethod(nmsEntityType, getCategoryMethod))
5872
.flatMap(nsmMobCategory -> ReflectHelper.tryInvokeStaticMethod(toBukkitMethod, nsmMobCategory))
@@ -61,7 +75,22 @@ private static void buildSpawnCategoryMap() {
6175
.peek(bukkitSpawnCategory -> entityTypeToSpawnCategoryMap.put(entityType, bukkitSpawnCategory))
6276
.peek(bukkitSpawnCategory -> spawnCategoryMap
6377
.computeIfAbsent(bukkitSpawnCategory, ignore -> new ArrayList<>())
64-
.add(entityType))));
78+
.add(entityType))
79+
.onFailure(throwable -> Logging.warning("Failed to map entity type "
80+
+ entityTypeField.getName() + " to its spawn category. " + throwable.getLocalizedMessage())))
81+
.onFailure(throwable -> Logging.warning("Failed to map entity type "
82+
+ entityTypeField.getName() + " to its spawn category. " + throwable.getLocalizedMessage())));
83+
84+
if (entityTypeToSpawnCategoryMap.isEmpty()) {
85+
Logging.warning("entityTypeToSpawnCategoryMap map is empty after building... " +
86+
"SpawnCategoryMapper will not work.");
87+
}
88+
if (spawnCategoryMap.isEmpty()) {
89+
Logging.warning("spawnCategoryMap map is empty after building... " +
90+
"SpawnCategoryMapper will not work.");
91+
}
92+
93+
Logging.finer("Mapped " + entityTypeToSpawnCategoryMap.size() + " entities to its spawn category.");
6594
}
6695

6796
/**
@@ -70,8 +99,8 @@ private static void buildSpawnCategoryMap() {
7099
* @param entityType The entity type
71100
* @return The spawn category that the given entity type is in, or null if it cannot be determined
72101
*/
73-
static SpawnCategory getSpawnCategory(EntityType entityType) {
74-
return entityTypeToSpawnCategoryMap.get(entityType);
102+
static @NotNull Option<SpawnCategory> getSpawnCategory(@Nullable EntityType entityType) {
103+
return Option.of(entityTypeToSpawnCategoryMap.get(entityType));
75104
}
76105

77106
/**
@@ -80,10 +109,11 @@ static SpawnCategory getSpawnCategory(EntityType entityType) {
80109
* @param spawnCategory The spawn category
81110
* @return The entity types associated with the spawn category
82111
*/
83-
static List<EntityType> getEntityTypes(SpawnCategory spawnCategory) {
84-
if (spawnCategoryMap == null) {
85-
return Collections.emptyList();
86-
}
87-
return spawnCategoryMap.get(spawnCategory);
112+
static @NotNull List<EntityType> getEntityTypes(@Nullable SpawnCategory spawnCategory) {
113+
return spawnCategoryMap.getOrDefault(spawnCategory, Collections.emptyList());
114+
}
115+
116+
private SpawnCategoryMapper() {
117+
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
88118
}
89119
}

0 commit comments

Comments
 (0)