- Interaction-Interfaces (Interactable, UiTarget, etc.)
- InteractionRegistry + InteractionHandler
- Plot-Interface-Hierarchie (Plot, BasePlot, Traits)
- TradeguildPlot mit allen Traits
- GuildTraderNpcEntity (UiTarget für NPCs)
Problem:
- PlotRegistry speichert nur Plot-IDs (Strings), nicht Plot-Objekte
- TradeguildPlot-Instanzen müssen irgendwo verwaltet werden
Lösungsansatz:
// In PlotModule:
private Map<String, TradeguildPlot> tradeguildPlots = new ConcurrentHashMap<>();
private void registerTradeguildPlotInInteractionRegistry(Plot basePlot) {
// Prüfe ob MERCHANT_GUILD
if (plotRegistry.isRegistered(basePlot, PlotType.MERCHANT_GUILD)) {
// Erstelle TradeguildPlot
TradeguildPlot tradePlot = new TradeguildPlot(
basePlot.getUuid(),
basePlot.getIdentifier(),
basePlot.getLocation(),
basePlot.getNativePlot()
);
// In InteractionRegistry registrieren
corePlugin.getInteractionRegistry().registerPlot(basePlot.getLocation(), tradePlot);
// Cache für spätere Verwendung
tradeguildPlots.put(basePlot.getIdentifier(), tradePlot);
}
}Benötigt:
- Laden von Custom-Namen aus Towny MetaData / DataStore
- Laden von Storage-Daten (Items, Preise)
- Laden von NPC-IDs
- Laden von Slot-Daten
Lösungsansatz:
// TradeguildPlot.java
public void loadFromDataStore(DataStore dataStore) {
String key = "tradeguild." + getUuid();
// Lade Custom-Name
dataStore.load(key + ".name", String.class)
.thenAccept(opt -> opt.ifPresent(name -> this.customName = name));
// Lade Storage
dataStore.load(key + ".storage", Map.class)
.thenAccept(opt -> opt.ifPresent(data -> this.storage.putAll(data)));
// ...
}
public void saveToDataStore(DataStore dataStore) {
String key = "tradeguild." + getUuid();
dataStore.save(key + ".name", customName);
dataStore.save(key + ".storage", storage);
// ...
}Benötigt:
- GuildTraderNpcEntity-Instanzen in InteractionRegistry registrieren
- Beim NPC-Spawn:
interactionRegistry.registerEntity(npcId, entity) - Beim NPC-Despawn:
interactionRegistry.unregisterEntity(npcId)
Lösungsansatz:
// In NPCModule oder NPCManager
public UUID spawnGuildTrader(Plot plot) {
UUID npcId = npcManager.spawnNPC(...);
// Erstelle Entity
GuildTraderNpcEntity entity = new GuildTraderNpcEntity(
npcId, plot, guildTraderType
);
// In InteractionRegistry registrieren
corePlugin.getInteractionRegistry().registerEntity(npcId, entity);
return npcId;
}Ausstehende UIs:
- PlotMainMenuUi (mit getAvailableActions)
- StoragePriceUi (Preise verwalten)
- NpcManagementUi (NPCs spawnen/entfernen)
- PlotStorageUi (Lager-Übersicht)
- PlotNameInputUi (AnvilUi für Namen-Eingabe)
Beispiel PlotMainMenuUi:
public class PlotMainMenuUi extends LargeChestUi {
private final TradeguildPlot plot;
public PlotMainMenuUi(TradeguildPlot plot, Player player) {
super("§6" + plot.getDisplayName());
this.plot = plot;
// Auto-generate buttons from available actions
List<UiActionInfo> actions = plot.getAvailableActions(player, UiContext.MAIN_MENU);
for (UiActionInfo action : actions) {
action.slot().ifPresent(slot -> {
setItem(slot, createButton(action), p -> {
plot.executeAction(p, action.id());
});
});
}
}
}Benötigt:
isOwner(Plot, Player)für Owner-ChecksgetPlotAs(Location, Class<T>)für Type-Safe Casting
Beispiel:
public interface PlotProvider {
// ...
/**
* Prüft ob Spieler Owner eines Plots ist.
*/
boolean isOwner(Plot plot, Player player);
/**
* Gibt Plot als spezifischen Typ zurück.
*
* @return Optional mit gecastetem Plot, oder empty wenn falscher Typ
*/
default <T extends Plot> Optional<T> getPlotAs(Location location, Class<T> type) {
Plot plot = getPlot(location);
if (type.isInstance(plot)) {
return Optional.of(type.cast(plot));
}
return Optional.empty();
}
}- TradeguildPlot-Factory erstellen
- PlotModule: TradeguildPlot-Cache implementieren
- PlotRegistryListener: TradeguildPlot bei MERCHANT_GUILD-Registration erstellen
- InteractionRegistry-Integration für alle TradeguildPlots
- TradeguildPlot: loadFromDataStore/saveToDataStore implementieren
- PlotModule: Laden aller TradeguildPlots beim Start
- PlotModule: Speichern bei onDisable
- Auto-Save nach jeder Änderung
- NPCModule: InteractionRegistry-Zugriff
- GuildTraderNPC: registerEntity bei Spawn
- GuildTraderNPC: unregisterEntity bei Despawn
- Migration alter NPCs zu neuen Entities
- PlotMainMenuUi implementieren
- StoragePriceUi überarbeiten (UiActionTarget-basiert)
- NpcManagementUi implementieren
- PlotStorageUi implementieren
- Build-Test
- Server-Deploy
- Click-to-UI-Test (Plots)
- Click-to-UI-Test (NPCs)
- Owner/Guest-Unterscheidung testen
- Persistenz testen
- Plot-Interface ist jetzt Interface, nicht Klasse
- BasePlot ist minimal (nur Basis-Daten)
- TradeguildPlot erweitert BasePlot mit allen Traits
- Traits ermöglichen Composition statt Vererbung
- Zentrale Verwaltung aller klickbaren Objekte
- Type-Safe (Interactable-Interface)
- Automatisches Click-Routing via InteractionHandler
- Saubere Trennung: Core = Infrastructure, Module = Business Logic
- Self-Constructing UIs (Objekte definieren eigene Buttons)
- Context-Aware (verschiedene Aktionen je nach UI-Kontext)
- Permission-Integration
- DRY (keine Code-Duplizierung in UIs)
- Commit: TradeguildPlot-Factory + Instanz-Verwaltung
- Commit: PlotModule InteractionRegistry-Integration
- Commit: NPCModule InteractionRegistry-Integration
- Commit: PlotMainMenuUi Implementierung
- Commit: Testing + Bugfixes
Stand: 2025-11-18 Branch: claude/fix-storage-price-loop-012sXDfqzLyyPSPX8QC8egq7