Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ jar {
archiveVersion.set("${version}")

from { project(':api').sourceSets.main.output }
from { project(':nms:v1_21').sourceSets.main.output }
from { project(':nms:v1_21_4').sourceSets.main.output }
from { project(':nms:v1_21_6').sourceSets.main.output }
from sourceSets.main.output
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
Expand Down
13 changes: 13 additions & 0 deletions core/src/main/java/github/nighter/smartspawner/SmartSpawner.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import github.nighter.smartspawner.commands.list.gui.management.SpawnerManagementGUI;
import github.nighter.smartspawner.commands.list.gui.adminstacker.AdminStackerHandler;
import github.nighter.smartspawner.commands.prices.PricesGUI;
import github.nighter.smartspawner.config.MobHeadConfig;
import github.nighter.smartspawner.logging.LoggingConfig;
import github.nighter.smartspawner.logging.SpawnerActionLogger;
import github.nighter.smartspawner.logging.SpawnerAuditListener;
Expand Down Expand Up @@ -79,6 +80,7 @@ public class SmartSpawner extends JavaPlugin implements SmartSpawnerPlugin {
private LanguageManager languageManager;
private LanguageUpdater languageUpdater;
private MessageService messageService;
private MobHeadConfig mobHeadConfig;

// Factories
private SpawnerItemFactory spawnerItemFactory;
Expand Down Expand Up @@ -227,6 +229,10 @@ private void initializeServices() {
this.languageUpdater = new LanguageUpdater(this);
this.messageService = new MessageService(this, languageManager);

// Initialize mob head config
this.mobHeadConfig = new MobHeadConfig(this);
this.mobHeadConfig.load();

// Initialize logging system
this.loggingConfig = new LoggingConfig(this);
this.spawnerActionLogger = new SpawnerActionLogger(this, loggingConfig);
Expand Down Expand Up @@ -378,6 +384,13 @@ public void reload() {
spawnerMenuAction.reload();
timeFormatter.clearCache();

// Reload mob head config
if (mobHeadConfig != null) {
mobHeadConfig.reload();
// Clear head cache to force regeneration with new textures
SpawnerMobHeadTexture.clearCache();
}

// Reload logging system
loggingConfig.loadConfig();
spawnerActionLogger.shutdown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.mojang.brigadier.suggestion.SuggestionProvider;
import github.nighter.smartspawner.SmartSpawner;
import github.nighter.smartspawner.commands.BaseSubCommand;
import github.nighter.smartspawner.nms.SpawnerWrapper;
import github.nighter.smartspawner.utils.DynamicEntityValidator;
import github.nighter.smartspawner.spawner.item.SpawnerItemFactory;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
Expand All @@ -21,6 +21,7 @@

import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@NullMarked
public class GiveSubCommand extends BaseSubCommand {
Expand All @@ -31,7 +32,11 @@ public class GiveSubCommand extends BaseSubCommand {
public GiveSubCommand(SmartSpawner plugin) {
super(plugin);
this.spawnerItemFactory = plugin.getSpawnerItemFactory();
this.supportedMobs = SpawnerWrapper.SUPPORTED_MOBS;
// Generate supported mobs list from DynamicEntityValidator
this.supportedMobs = DynamicEntityValidator.getValidEntities().stream()
.map(EntityType::name)
.sorted()
.collect(Collectors.toList());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package github.nighter.smartspawner.config;

import github.nighter.smartspawner.SmartSpawner;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.EntityType;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.EnumMap;
import java.util.Map;
import java.util.logging.Level;

/**
* Manages player-configurable mob head textures for spawner GUI
*/
public class MobHeadConfig {
private final SmartSpawner plugin;
private FileConfiguration config;
private final File configFile;

private Material defaultMaterial;
private final Map<EntityType, MobHeadData> mobHeadMap = new EnumMap<>(EntityType.class);

public MobHeadConfig(SmartSpawner plugin) {
this.plugin = plugin;
this.configFile = new File(plugin.getDataFolder(), "mob_heads.yml");
}

/**
* Load or create the mob heads configuration
*/
public void load() {
// Create config file if it doesn't exist
if (!configFile.exists()) {
saveDefaultConfig();
}

// Load the configuration
config = YamlConfiguration.loadConfiguration(configFile);

// Parse configuration
parseConfig();
}

/**
* Save the default configuration from resources
*/
private void saveDefaultConfig() {
try {
if (!plugin.getDataFolder().exists()) {
plugin.getDataFolder().mkdirs();
}

try (InputStream in = plugin.getResource("mob_heads.yml")) {
if (in != null) {
Files.copy(in, configFile.toPath());
plugin.getLogger().info("Created default mob_heads.yml configuration");
} else {
plugin.getLogger().warning("Could not find default mob_heads.yml in resources");
}
}
} catch (IOException e) {
plugin.getLogger().log(Level.SEVERE, "Could not create mob_heads.yml", e);
}
}

/**
* Parse the configuration and populate the mob head map
*/
private void parseConfig() {
mobHeadMap.clear();

// Get default material
String defaultMaterialName = config.getString("default_material", "SPAWNER");
try {
defaultMaterial = Material.valueOf(defaultMaterialName.toUpperCase());
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Invalid default_material in mob_heads.yml: " + defaultMaterialName + ", using SPAWNER");
defaultMaterial = Material.SPAWNER;
}

// Parse mob heads
ConfigurationSection mobHeadsSection = config.getConfigurationSection("mob_heads");
if (mobHeadsSection == null) {
plugin.getLogger().warning("No mob_heads section found in mob_heads.yml");
return;
}

for (String entityTypeName : mobHeadsSection.getKeys(false)) {
try {
EntityType entityType = EntityType.valueOf(entityTypeName.toUpperCase());
ConfigurationSection entitySection = mobHeadsSection.getConfigurationSection(entityTypeName);

if (entitySection != null) {
String materialName = entitySection.getString("material", "SPAWNER");
String customTexture = entitySection.getString("custom_texture");

// Validate material
Material material;
try {
material = Material.valueOf(materialName.toUpperCase());
if (!material.isItem()) {
plugin.getLogger().warning("Material " + materialName + " for " + entityTypeName + " is not an item, using default");
material = defaultMaterial;
}
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Invalid material " + materialName + " for " + entityTypeName + ", using default");
material = defaultMaterial;
}

// Store mob head data
mobHeadMap.put(entityType, new MobHeadData(material, customTexture));
}
} catch (IllegalArgumentException e) {
plugin.getLogger().warning("Invalid entity type in mob_heads.yml: " + entityTypeName);
}
}

plugin.getLogger().info("Loaded " + mobHeadMap.size() + " mob head configurations");
}

/**
* Get the material for a specific entity type
*
* @param entityType Entity type
* @return Material to use for the mob head
*/
public Material getMaterial(EntityType entityType) {
MobHeadData data = mobHeadMap.get(entityType);
return data != null ? data.material : defaultMaterial;
}

/**
* Get the custom texture for a specific entity type
*
* @param entityType Entity type
* @return Custom texture Base64 string, or null if not configured
*/
public String getCustomTexture(EntityType entityType) {
MobHeadData data = mobHeadMap.get(entityType);
return data != null ? data.customTexture : null;
}

/**
* Check if an entity type has a custom texture configured
*
* @param entityType Entity type
* @return true if custom texture is configured
*/
public boolean hasCustomTexture(EntityType entityType) {
MobHeadData data = mobHeadMap.get(entityType);
return data != null && data.customTexture != null && !data.customTexture.isEmpty();
}

/**
* Get the default material for mobs without custom configuration
*
* @return Default material
*/
public Material getDefaultMaterial() {
return defaultMaterial;
}

/**
* Reload the configuration
*/
public void reload() {
load();
}

/**
* Internal class to store mob head data
*/
private static class MobHeadData {
final Material material;
final String customTexture;

MobHeadData(Material material, String customTexture) {
this.material = material;
this.customTexture = customTexture;
}
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Loading