package com.hypixel.hytale.builtin.adventure.memories.page;
import com.hypixel.hytale.builtin.adventure.memories.MemoriesGameplayConfig;
import com.hypixel.hytale.builtin.adventure.memories.MemoriesPlugin;
import com.hypixel.hytale.builtin.adventure.memories.component.PlayerMemories;
import com.hypixel.hytale.builtin.adventure.memories.memories.Memory;
import com.hypixel.hytale.builtin.adventure.memories.memories.npc.NPCMemory;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.codec.codecs.EnumCodec;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.spatial.SpatialResource;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.protocol.BlockPosition;
import com.hypixel.hytale.protocol.packets.interface_.CustomPageLifetime;
import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCustomUIPage;
import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.ui.Anchor;
import com.hypixel.hytale.server.core.ui.Value;
import com.hypixel.hytale.server.core.ui.builder.EventData;
import com.hypixel.hytale.server.core.ui.builder.UICommandBuilder;
import com.hypixel.hytale.server.core.ui.builder.UIEventBuilder;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.world.ParticleUtil;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class MemoriesPage extends InteractiveCustomUIPage<PageEventData> {
@Nullable
private String currentCategory;
@Nullable
private Memory selectedMemory;
private Vector3d recordMemoriesParticlesPosition;
public MemoriesPage(@Nonnull PlayerRef playerRef, BlockPosition blockPosition) {
super(playerRef, CustomPageLifetime.CanDismissOrCloseThroughInteraction, MemoriesPage.PageEventData.CODEC);
this.recordMemoriesParticlesPosition = new Vector3d((double)blockPosition.x, (double)blockPosition.y, (double)blockPosition.z);
}
public void build(@Nonnull Ref<EntityStore> ref, @Nonnull UICommandBuilder commandBuilder, @Nonnull UIEventBuilder eventBuilder, @Nonnull Store<EntityStore> store) {
MemoriesPlugin memoriesPlugin = MemoriesPlugin.get();
if (this.currentCategory == null) {
commandBuilder.append("Pages/Memories/MemoriesCategoryPanel.ui");
Map<String, Set<Memory>> allMemories = memoriesPlugin.getAllMemories();
Set<Memory> recordedMemories = memoriesPlugin.getRecordedMemories();
int totalMemories = 0;
for(Set<Memory> value : allMemories.values()) {
totalMemories += value.size();
}
commandBuilder.set("#MemoriesProgressBar.Value", (float)recordedMemories.size() / (float)totalMemories);
commandBuilder.set("#MemoriesProgressBarTexture.Value", (float)recordedMemories.size() / (float)totalMemories);
commandBuilder.set("#TotalCollected.Text", String.valueOf(recordedMemories.size()));
commandBuilder.set("#MemoriesTotal.Text", String.valueOf(totalMemories));
eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#MemoriesInfoButton", (new EventData()).append("Action", (Enum)MemoriesPage.PageAction.MemoriesInfo));
GameplayConfig gameplayConfig = ((EntityStore)store.getExternalData()).getWorld().getGameplayConfig();
PlayerMemories playerMemories = (PlayerMemories)store.getComponent(ref, PlayerMemories.getComponentType());
int i = 0;
for(Map.Entry<String, Set<Memory>> entry : allMemories.entrySet()) {
String category = (String)entry.getKey();
Set<Memory> memoriesInCategory = (Set)entry.getValue();
int var10000 = i++;
String selector = "#IconList[" + var10000 + "] ";
int recordedMemoriesCount = 0;
for(Memory memory : memoriesInCategory) {
if (recordedMemories.contains(memory)) {
++recordedMemoriesCount;
}
}
commandBuilder.append("#IconList", "Pages/Memories/MemoriesCategory.ui");
commandBuilder.set(selector + "#Button.Text", Message.translation("server.memories.categories." + category + ".title"));
commandBuilder.set(selector + "#CurrentMemoryCountNotComplete.Text", String.valueOf(recordedMemoriesCount));
commandBuilder.set(selector + "#CurrentMemoryCountComplete.Text", String.valueOf(recordedMemoriesCount));
commandBuilder.set(selector + "#TotalMemoryCountNotComplete.Text", String.valueOf(memoriesInCategory.size()));
commandBuilder.set(selector + "#TotalMemoryCountComplete.Text", String.valueOf(memoriesInCategory.size()));
boolean isCategoryComplete = recordedMemoriesCount == memoriesInCategory.size();
if (isCategoryComplete) {
commandBuilder.set(selector + "#CategoryIcon.Background", "Pages/Memories/categories/" + category + "Complete.png");
commandBuilder.set(selector + "#CompleteCategoryBackground.Visible", true);
commandBuilder.set(selector + "#CompleteCategoryCounter.Visible", true);
} else {
commandBuilder.set(selector + "#CategoryIcon.Background", "Pages/Memories/categories/" + category + ".png");
commandBuilder.set(selector + "#NotCompleteCategoryCounter.Visible", true);
}
if (playerMemories != null) {
Set<Memory> newMemories = playerMemories.getRecordedMemories();
for(Memory memory : memoriesInCategory) {
if (newMemories.contains(memory)) {
commandBuilder.set(selector + "#NewMemoryIndicator.Visible", true);
break;
}
}
}
eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, selector + "#Button", (new EventData()).append("Action", (Enum)MemoriesPage.PageAction.ViewCategory).append("Category", category));
}
commandBuilder.set("#RecordButton.Visible", true);
commandBuilder.set("#RecordButton.Disabled", playerMemories == null || !playerMemories.hasMemories());
buildChestMarkers(commandBuilder, gameplayConfig, totalMemories);
if (playerMemories != null && playerMemories.hasMemories()) {
commandBuilder.set("#RecordButton.Text", Message.translation("server.memories.general.recordNum").param("count", playerMemories.getRecordedMemories().size()));
}
eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#RecordButton", (new EventData()).append("Action", (Enum)MemoriesPage.PageAction.Record));
} else {
commandBuilder.append("Pages/Memories/MemoriesPanel.ui");
Set<Memory> memoriesSet = (Set)memoriesPlugin.getAllMemories().get(this.currentCategory);
ObjectArrayList<Memory> memories = new ObjectArrayList<Memory>(memoriesSet);
memories.sort(Comparator.comparing(Memory::getTitle));
Set<Memory> recordedMemories = memoriesPlugin.getRecordedMemories();
int recordedMemoriesCount = 0;
for(Memory memory : memories) {
if (recordedMemories.contains(memory)) {
++recordedMemoriesCount;
}
}
commandBuilder.set("#CategoryTitle.Text", Message.translation("server.memories.categories." + this.currentCategory + ".title"));
commandBuilder.set("#CategoryCount.Text", recordedMemoriesCount + "/" + memories.size());
for(int i = 0; i < memories.size(); ++i) {
Memory memory = memories.get(i);
String selector = "#IconList[" + i + "] ";
commandBuilder.append("#IconList", "Pages/Memories/Memory.ui");
boolean isDiscovered = recordedMemories.contains(memory);
boolean isSelected = this.selectedMemory != null && this.selectedMemory.equals(memory);
String buttonSelector = isSelected ? selector + "#ButtonSelected" : selector + "#ButtonNotSelected";
if (isDiscovered) {
commandBuilder.set(buttonSelector + ".Visible", true);
commandBuilder.set(buttonSelector + ".TooltipText", memory.getTooltipText());
commandBuilder.setNull(buttonSelector + ".Background");
String iconPath = memory.getIconPath();
if (iconPath != null && !iconPath.isEmpty()) {
commandBuilder.set(selector + "#Icon.AssetPath", iconPath);
}
eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, buttonSelector, (new EventData()).append("Action", (Enum)MemoriesPage.PageAction.SelectMemory).append("MemoryId", memory.getId()));
} else {
commandBuilder.set(selector + "#EmptyBackground.Visible", true);
}
}
if (this.selectedMemory != null && recordedMemories.contains(this.selectedMemory)) {
updateMemoryDetailsPanel(commandBuilder, this.selectedMemory);
}
eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#BackButton", (new EventData()).append("Action", (Enum)MemoriesPage.PageAction.Back));
}
}
private static void buildChestMarkers(@Nonnull UICommandBuilder commandBuilder, @Nonnull GameplayConfig gameplayConfig, int totalMemories) {
MemoriesGameplayConfig memoriesConfig = MemoriesGameplayConfig.get(gameplayConfig);
if (memoriesConfig != null) {
int[] memoriesAmountPerLevel = memoriesConfig.getMemoriesAmountPerLevel();
if (memoriesAmountPerLevel != null && memoriesAmountPerLevel.length > 1) {
MemoriesPlugin memoriesPlugin = MemoriesPlugin.get();
int recordedMemoriesCount = memoriesPlugin.getRecordedMemories().size();
int PROGRESS_BAR_PADDING = 18;
int PROGRESS_BAR_WIDTH = 1018;
int CHEST_POSITION_AREA = 1000;
for(int i = 0; i < memoriesAmountPerLevel.length; ++i) {
int memoryAmount = memoriesAmountPerLevel[i];
boolean hasReachedLevel = recordedMemoriesCount >= memoryAmount;
String selector = "#ChestMarkers[" + i + "]";
Anchor anchor = new Anchor();
int left = memoryAmount * 1000 / totalMemories;
commandBuilder.append("#ChestMarkers", "Pages/Memories/ChestMarker.ui");
anchor.setLeft(Value.of(left));
commandBuilder.setObject(selector + ".Anchor", anchor);
Message rewardsMessage = Message.translation("server.memories.general.chestActive.level" + (i + 1) + ".rewards");
if (hasReachedLevel) {
Message memoriesUnlockedMessage = Message.translation("server.memories.general.chestActive.tooltipText").param("count", memoryAmount);
Message activeTooltipMessage = memoriesUnlockedMessage.insert("\n").insert(rewardsMessage);
commandBuilder.set(selector + " #Arrow.Visible", true);
commandBuilder.set(selector + " #ChestActive.Visible", true);
commandBuilder.set(selector + " #ChestActive.TooltipTextSpans", activeTooltipMessage);
} else {
commandBuilder.set(selector + " #ChestDisabled.Visible", true);
Message memoriesToUnlockMessage = Message.translation("server.memories.general.chestLocked.tooltipText").param("count", memoryAmount);
Message disabledTooltipMessage = memoriesToUnlockMessage.insert("\n").insert(rewardsMessage);
commandBuilder.set(selector + " #ChestDisabled.TooltipTextSpans", disabledTooltipMessage);
}
}
}
}
}
public void handleDataEvent(@Nonnull Ref<EntityStore> ref, @Nonnull Store<EntityStore> store, @Nonnull PageEventData data) {
Player player = (Player)store.getComponent(ref, Player.getComponentType());
assert player != null;
TransformComponent transformComponent = (TransformComponent)store.getComponent(ref, TransformComponent.getComponentType());
assert transformComponent != null;
switch (data.action.ordinal()) {
case 0:
PlayerMemories playerMemories = (PlayerMemories)store.getComponent(ref, PlayerMemories.getComponentType());
if (playerMemories == null) {
this.sendUpdate();
return;
}
if (!MemoriesPlugin.get().recordPlayerMemories(playerMemories)) {
this.rebuild();
return;
}
MemoriesGameplayConfig memoriesGameplayConfig = MemoriesGameplayConfig.get(((EntityStore)store.getExternalData()).getWorld().getGameplayConfig());
if (memoriesGameplayConfig != null) {
SpatialResource<Ref<EntityStore>, EntityStore> playerSpatialResource = (SpatialResource)store.getResource(EntityModule.get().getPlayerSpatialResourceType());
ObjectList<Ref<EntityStore>> results = SpatialResource.getThreadLocalReferenceList();
playerSpatialResource.getSpatialStructure().collect(this.recordMemoriesParticlesPosition, 75.0, results);
ParticleUtil.spawnParticleEffect((String)memoriesGameplayConfig.getMemoriesRecordParticles(), this.recordMemoriesParticlesPosition, results, store);
}
this.close();
break;
case 1:
this.currentCategory = data.category;
this.selectedMemory = null;
this.rebuild();
break;
case 2:
this.currentCategory = null;
this.selectedMemory = null;
this.rebuild();
break;
case 3:
BlockPosition blockPostion = new BlockPosition((int)this.recordMemoriesParticlesPosition.x, (int)this.recordMemoriesParticlesPosition.y, (int)this.recordMemoriesParticlesPosition.z);
player.getPageManager().openCustomPage(ref, store, new MemoriesUnlockedPage(this.playerRef, blockPostion));
break;
case 4:
if (data.memoryId == null || this.currentCategory == null) {
return;
}
Set<Memory> memoriesSet = (Set)MemoriesPlugin.get().getAllMemories().get(this.currentCategory);
if (memoriesSet == null) {
return;
}
ObjectArrayList<Memory> memories = new ObjectArrayList<Memory>(memoriesSet);
memories.sort(Comparator.comparing(Memory::getTitle));
Set<Memory> recordedMemories = MemoriesPlugin.get().getRecordedMemories();
if (recordedMemories == null) {
return;
}
Memory newSelection = null;
Iterator var10 = recordedMemories.iterator();
while(true) {
if (var10.hasNext()) {
Memory memory = (Memory)var10.next();
if (!memory.getId().equals(data.memoryId)) {
continue;
}
newSelection = memory;
}
if (newSelection == null) {
return;
}
if (!memories.contains(newSelection) || newSelection.equals(this.selectedMemory)) {
return;
}
UICommandBuilder commandBuilder = new UICommandBuilder();
if (this.selectedMemory != null && recordedMemories.contains(this.selectedMemory)) {
int previousIndex = memories.indexOf(this.selectedMemory);
if (previousIndex >= 0) {
updateMemoryButtonSelection(commandBuilder, previousIndex, this.selectedMemory, false);
}
}
int newIndex = memories.indexOf(newSelection);
if (newIndex >= 0) {
updateMemoryButtonSelection(commandBuilder, newIndex, newSelection, true);
}
updateMemoryDetailsPanel(commandBuilder, newSelection);
this.selectedMemory = newSelection;
this.sendUpdate(commandBuilder);
break;
}
}
}
private static void updateMemoryButtonSelection(@Nonnull UICommandBuilder commandBuilder, int index, @Nonnull Memory memory, boolean isSelected) {
String selector = "#IconList[" + index + "] ";
if (isSelected) {
commandBuilder.set(selector + "#ButtonNotSelected.Visible", false);
commandBuilder.set(selector + "#ButtonSelected.Visible", true);
commandBuilder.setNull(selector + "#ButtonSelected.Background");
commandBuilder.set(selector + "#ButtonSelected.TooltipText", memory.getTooltipText());
} else {
commandBuilder.set(selector + "#ButtonSelected.Visible", false);
commandBuilder.set(selector + "#ButtonNotSelected.Visible", true);
commandBuilder.setNull(selector + "#ButtonNotSelected.Background");
commandBuilder.set(selector + "#ButtonNotSelected.TooltipText", memory.getTooltipText());
}
}
private static void updateMemoryDetailsPanel(@Nonnull UICommandBuilder commandBuilder, @Nonnull Memory memory) {
commandBuilder.set("#MemoryName.Text", Message.translation(memory.getTitle()));
commandBuilder.set("#MemoryTimeLocation.Text", "");
if (memory instanceof NPCMemory npcMemory) {
Message locationNameKey = npcMemory.getLocationMessage();
long capturedTimestamp = npcMemory.getCapturedTimestamp();
String timeString = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(Locale.getDefault()).format(Instant.ofEpochMilli(capturedTimestamp).atZone(ZoneOffset.UTC));
Message memoryLocationTimeText = Message.translation("server.memories.general.foundIn").param("location", locationNameKey).param("time", timeString);
commandBuilder.set("#MemoryTimeLocation.TextSpans", memoryLocationTimeText);
}
String iconPath = memory.getIconPath();
if (iconPath != null && !iconPath.isEmpty()) {
commandBuilder.set("#MemoryIcon.AssetPath", iconPath);
} else {
commandBuilder.setNull("#MemoryIcon.AssetPath");
}
}
public static class PageEventData {
public static final String KEY_ACTION = "Action";
public static final String KEY_CATEGORY = "Category";
public static final String KEY_MEMORY_ID = "MemoryId";
public static final BuilderCodec<PageEventData> CODEC;
public PageAction action;
public String category;
public String memoryId;
public PageEventData() {
}
static {
CODEC = ((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)BuilderCodec.builder(PageEventData.class, PageEventData::new).append(new KeyedCodec("Action", MemoriesPage.PageAction.CODEC), (pageEventData, pageAction) -> pageEventData.action = pageAction, (pageEventData) -> pageEventData.action).add()).append(new KeyedCodec("Category", Codec.STRING), (pageEventData, s) -> pageEventData.category = s, (pageEventData) -> pageEventData.category).add()).append(new KeyedCodec("MemoryId", Codec.STRING), (pageEventData, id) -> pageEventData.memoryId = id, (pageEventData) -> pageEventData.memoryId).add()).build();
}
}
public static enum PageAction {
Record,
ViewCategory,
Back,
MemoriesInfo,
SelectMemory;
public static final Codec<PageAction> CODEC = new EnumCodec<PageAction>(PageAction.class);
private PageAction() {
}
}
}