package com.hypixel.hytale.builtin.adventure.objectives;
import com.hypixel.hytale.builtin.adventure.objectives.config.ObjectiveAsset;
import com.hypixel.hytale.builtin.adventure.objectives.config.ObjectiveLineAsset;
import com.hypixel.hytale.builtin.adventure.objectives.config.completion.ObjectiveCompletionAsset;
import com.hypixel.hytale.builtin.adventure.objectives.config.task.ObjectiveTaskAsset;
import com.hypixel.hytale.builtin.adventure.objectives.config.task.TaskSet;
import com.hypixel.hytale.builtin.adventure.objectives.historydata.ObjectiveHistoryData;
import com.hypixel.hytale.builtin.adventure.objectives.historydata.ObjectiveLineHistoryData;
import com.hypixel.hytale.builtin.adventure.objectives.task.ObjectiveTask;
import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionRecord;
import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionUtil;
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.array.ArrayCodec;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.function.consumer.TriConsumer;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.protocol.packets.assets.TrackOrUpdateObjective;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.io.NetworkSerializable;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.Universe;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class Objective implements NetworkSerializable<com.hypixel.hytale.protocol.Objective> {
public static final BuilderCodec<Objective> CODEC;
protected UUID objectiveUUID;
protected String objectiveId;
@Nullable
protected ObjectiveLineHistoryData objectiveLineHistoryData;
protected ObjectiveHistoryData objectiveHistoryData;
protected Set<UUID> playerUUIDs;
@Nonnull
protected Set<UUID> activePlayerUUIDs = ConcurrentHashMap.newKeySet();
@Nullable
protected ObjectiveTask[] currentTasks;
protected int currentTaskSetIndex;
protected boolean completed;
protected UUID worldUUID;
@Nullable
protected UUID markerUUID;
protected boolean dirty;
protected ItemStack objectiveItemStarter;
public Objective(@Nonnull ObjectiveAsset asset, @Nullable UUID objectiveUUID, @Nonnull Set<UUID> playerUUIDs, @Nonnull UUID worldUUID, @Nullable UUID markerUUID) {
this.objectiveId = asset.getId();
this.currentTaskSetIndex = 0;
this.playerUUIDs = playerUUIDs;
this.worldUUID = worldUUID;
this.objectiveUUID = objectiveUUID == null ? UUID.randomUUID() : objectiveUUID;
this.markerUUID = markerUUID;
this.objectiveHistoryData = new ObjectiveHistoryData(asset.getId(), asset.getCategory());
}
protected Objective() {
}
@Nonnull
public UUID getObjectiveUUID() {
return this.objectiveUUID;
}
@Nonnull
public String getObjectiveId() {
return this.objectiveId;
}
@Nullable
public ObjectiveAsset getObjectiveAsset() {
return (ObjectiveAsset)ObjectiveAsset.getAssetMap().getAsset(this.objectiveId);
}
@Nullable
public ObjectiveLineHistoryData getObjectiveLineHistoryData() {
return this.objectiveLineHistoryData;
}
public void setObjectiveLineHistoryData(@Nullable ObjectiveLineHistoryData objectiveLineHistoryData) {
this.objectiveLineHistoryData = objectiveLineHistoryData;
}
@Nonnull
public ObjectiveHistoryData getObjectiveHistoryData() {
return this.objectiveHistoryData;
}
@Nullable
public ObjectiveLineAsset getObjectiveLineAsset() {
return this.objectiveLineHistoryData == null ? null : (ObjectiveLineAsset)ObjectiveLineAsset.getAssetMap().getAsset(this.objectiveLineHistoryData.getId());
}
public Set<UUID> getPlayerUUIDs() {
return this.playerUUIDs;
}
@Nonnull
public Set<UUID> getActivePlayerUUIDs() {
return this.activePlayerUUIDs;
}
@Nullable
public ObjectiveTask[] getCurrentTasks() {
return this.currentTasks;
}
public int getCurrentTaskSetIndex() {
return this.currentTaskSetIndex;
}
public String getCurrentDescription() {
ObjectiveAsset objectiveAsset = (ObjectiveAsset)Objects.requireNonNull(this.getObjectiveAsset());
TaskSet currentTaskSet = objectiveAsset.getTaskSets()[this.currentTaskSetIndex];
return currentTaskSet.getDescriptionId() != null ? currentTaskSet.getDescriptionKey(this.objectiveId, this.currentTaskSetIndex) : objectiveAsset.getDescriptionKey();
}
public boolean isCompleted() {
return this.completed;
}
public UUID getWorldUUID() {
return this.worldUUID;
}
@Nullable
public UUID getMarkerUUID() {
return this.markerUUID;
}
public boolean isDirty() {
return this.dirty;
}
public ItemStack getObjectiveItemStarter() {
return this.objectiveItemStarter;
}
public void setObjectiveItemStarter(@Nonnull ItemStack objectiveItemStarter) {
this.objectiveItemStarter = objectiveItemStarter;
}
public boolean setup(@Nonnull Store<EntityStore> componentAccessor) {
ObjectiveAsset objectiveAsset = (ObjectiveAsset)Objects.requireNonNull(this.getObjectiveAsset());
ObjectivePlugin objectiveModule = ObjectivePlugin.get();
TaskSet[] taskSets = objectiveAsset.getTaskSets();
if (this.currentTaskSetIndex >= taskSets.length) {
objectiveModule.getLogger().at(Level.WARNING).log("Current taskSet index is higher than total number of taskSets for objective %s", this.objectiveId);
return false;
} else {
ObjectiveTaskAsset[] tasks = taskSets[this.currentTaskSetIndex].getTasks();
ObjectiveTask[] newTasks = new ObjectiveTask[tasks.length];
for(int i = 0; i < tasks.length; ++i) {
newTasks[i] = objectiveModule.createTask(tasks[i], this.currentTaskSetIndex, i);
}
this.currentTasks = newTasks;
return this.setupCurrentTasks(componentAccessor);
}
}
public boolean setupCurrentTasks(@Nonnull Store<EntityStore> store) {
for(ObjectiveTask task : this.currentTasks) {
if (!task.isComplete()) {
TransactionRecord[] taskTransactions = task.setup(this, store);
if (taskTransactions != null && TransactionUtil.anyFailed(taskTransactions)) {
ObjectivePlugin.get().getLogger().at(Level.WARNING).log("Failed to setup objective tasks, transaction records:%s", Arrays.toString(taskTransactions));
for(ObjectiveTask taskSetup : this.currentTasks) {
taskSetup.revertTransactionRecords();
if (taskSetup == task) {
break;
}
}
return false;
}
}
}
return true;
}
public boolean checkTaskSetCompletion(@Nonnull Store<EntityStore> store) {
for(ObjectiveTask task : this.currentTasks) {
if (!task.isComplete()) {
return false;
}
}
this.taskSetComplete(store);
return true;
}
protected void taskSetComplete(@Nonnull Store<EntityStore> store) {
ObjectiveAsset objectiveAsset = (ObjectiveAsset)Objects.requireNonNull(this.getObjectiveAsset());
++this.currentTaskSetIndex;
TaskSet[] taskSets = objectiveAsset.getTaskSets();
if (this.currentTaskSetIndex < taskSets.length) {
if (!this.setup(store)) {
this.taskSetComplete(store);
} else {
TrackOrUpdateObjective trackObjectivePacket = new TrackOrUpdateObjective(this.toPacket());
this.forEachParticipant((participantReference, message, trackOrUpdateObjective) -> {
PlayerRef playerRefComponent = (PlayerRef)store.getComponent(participantReference, PlayerRef.getComponentType());
if (playerRefComponent != null) {
playerRefComponent.sendMessage(message);
playerRefComponent.getPacketHandler().writeNoCache(trackOrUpdateObjective);
}
}, this.getTaskInfoMessage(), trackObjectivePacket);
this.checkTaskSetCompletion(store);
}
} else {
this.complete(store);
}
}
public void complete(@Nonnull Store<EntityStore> store) {
ObjectiveAsset objectiveAsset = (ObjectiveAsset)Objects.requireNonNull(this.getObjectiveAsset());
this.forEachParticipant((participantReference, message) -> {
PlayerRef playerRefComponent = (PlayerRef)store.getComponent(participantReference, PlayerRef.getComponentType());
if (playerRefComponent != null) {
playerRefComponent.sendMessage(message);
}
}, Message.translation("server.modules.objective.completed").param("title", Message.translation(objectiveAsset.getTitleKey())));
ObjectivePlugin objectiveModule = ObjectivePlugin.get();
ObjectiveCompletionAsset[] completionHandlerAssets = objectiveAsset.getCompletionHandlers();
if (completionHandlerAssets != null) {
for(ObjectiveCompletionAsset objectiveCompletionAsset : completionHandlerAssets) {
objectiveModule.createCompletion(objectiveCompletionAsset).handle(this, store);
}
}
this.completed = true;
objectiveModule.objectiveCompleted(this, store);
}
public void cancel() {
for(ObjectiveTask currentTask : this.currentTasks) {
currentTask.revertTransactionRecords();
}
}
public void unload() {
for(ObjectiveTask currentTask : this.currentTasks) {
currentTask.unloadTransactionRecords();
}
}
@Nonnull
public Message getTaskInfoMessage() {
Message info = Message.translation(this.getCurrentDescription());
for(ObjectiveTask task : this.currentTasks) {
info.insert("\n").insert(task.getInfoMessage(this));
}
return info;
}
public void reloadObjectiveAsset(@Nonnull Map<String, ObjectiveAsset> reloadedAssets) {
ObjectiveTaskAsset[] taskAssets = this.checkPossibleAssetReload(reloadedAssets);
if (taskAssets != null) {
World world = Universe.get().getWorld(this.worldUUID);
if (world != null) {
world.execute(() -> {
Store<EntityStore> store = world.getEntityStore().getStore();
ObjectiveTask[] newTasks = this.setupAndUpdateTasks(taskAssets, store);
if (newTasks != null) {
this.revertRemovedTasks(newTasks);
this.currentTasks = newTasks;
for(ObjectiveTask currentTask : this.currentTasks) {
currentTask.assetChanged(this);
}
if (!this.checkTaskSetCompletion(store)) {
TrackOrUpdateObjective updatePacket = new TrackOrUpdateObjective(this.toPacket());
this.forEachParticipant((participantReference, packet) -> {
PlayerRef playerRefComponent = (PlayerRef)store.getComponent(participantReference, PlayerRef.getComponentType());
if (playerRefComponent != null) {
playerRefComponent.getPacketHandler().writeNoCache(packet);
}
}, updatePacket);
}
}
});
}
}
}
@Nullable
private ObjectiveTaskAsset[] checkPossibleAssetReload(@Nonnull Map<String, ObjectiveAsset> reloadedAssets) {
ObjectiveLineAsset objectiveLineAsset = this.getObjectiveLineAsset();
if (this.objectiveLineHistoryData != null && objectiveLineAsset == null) {
this.cancel();
return null;
} else {
ObjectiveAsset objectiveAsset = (ObjectiveAsset)reloadedAssets.get(this.objectiveId);
if (objectiveAsset == null) {
return null;
} else {
TaskSet[] taskSets = objectiveAsset.getTaskSets();
if (this.currentTaskSetIndex > taskSets.length) {
this.cancel();
return null;
} else {
return taskSets[this.currentTaskSetIndex].getTasks();
}
}
}
}
@Nullable
private ObjectiveTask[] setupAndUpdateTasks(@Nonnull ObjectiveTaskAsset[] taskAssets, @Nonnull Store<EntityStore> store) {
ObjectiveTask[] newTasks = new ObjectiveTask[taskAssets.length];
for(int i = 0; i < taskAssets.length; ++i) {
ObjectiveTaskAsset taskAsset = taskAssets[i];
ObjectiveTask objectiveTask = this.findMatchingObjectiveTask(taskAsset);
if (objectiveTask != null) {
objectiveTask.setAsset(taskAsset);
newTasks[i] = objectiveTask;
} else {
ObjectiveTask newTask = newTasks[i] = ObjectivePlugin.get().createTask(taskAsset, this.currentTaskSetIndex, i);
TransactionRecord[] transactionRecords = newTask.setup(this, store);
if (TransactionUtil.anyFailed(transactionRecords)) {
this.cancelReload(newTasks);
return null;
}
}
}
return newTasks;
}
@Nullable
private ObjectiveTask findMatchingObjectiveTask(@Nonnull ObjectiveTaskAsset taskAsset) {
for(ObjectiveTask objectiveTask : this.currentTasks) {
if (objectiveTask.getAsset().matchesAsset(taskAsset)) {
return objectiveTask;
}
}
return null;
}
private void cancelReload(@Nonnull ObjectiveTask[] newTasks) {
for(ObjectiveTask taskToRevert : newTasks) {
if (taskToRevert != null) {
taskToRevert.revertTransactionRecords();
}
}
this.cancel();
this.currentTasks = null;
}
private void revertRemovedTasks(@Nonnull ObjectiveTask[] newTasks) {
for(ObjectiveTask objectiveTask : this.currentTasks) {
boolean foundMatchingTask = false;
for(ObjectiveTask newTask : newTasks) {
if (newTask.equals(objectiveTask)) {
foundMatchingTask = true;
break;
}
}
if (!foundMatchingTask) {
objectiveTask.revertTransactionRecords();
}
}
}
public void forEachParticipant(@Nonnull Consumer<Ref<EntityStore>> consumer) {
for(UUID playerUUID : this.playerUUIDs) {
PlayerRef playerRef = Universe.get().getPlayer(playerUUID);
if (playerRef != null) {
consumer.accept(playerRef.getReference());
}
}
}
public <T> void forEachParticipant(@Nonnull BiConsumer<Ref<EntityStore>, T> consumer, T meta) {
for(UUID playerUUID : this.playerUUIDs) {
PlayerRef playerRef = Universe.get().getPlayer(playerUUID);
if (playerRef != null) {
consumer.accept(playerRef.getReference(), meta);
}
}
}
public <T, U> void forEachParticipant(@Nonnull TriConsumer<Ref<EntityStore>, T, U> consumer, @Nonnull T t, @Nonnull U u) {
for(UUID playerUUID : this.playerUUIDs) {
PlayerRef playerRef = Universe.get().getPlayer(playerUUID);
if (playerRef != null) {
consumer.accept(playerRef.getReference(), t, u);
}
}
}
@Nullable
public Vector3d getPosition(@Nonnull ComponentAccessor<EntityStore> componentAccessor) {
UUID entityUUIDToFind = null;
if (this.markerUUID != null) {
entityUUIDToFind = this.markerUUID;
} else if (!this.playerUUIDs.isEmpty()) {
entityUUIDToFind = (UUID)this.playerUUIDs.iterator().next();
}
if (entityUUIDToFind == null) {
return null;
} else {
World world = ((EntityStore)componentAccessor.getExternalData()).getWorld();
Ref<EntityStore> markerEntityReference = world.getEntityRef(entityUUIDToFind);
if (markerEntityReference != null && markerEntityReference.isValid()) {
TransformComponent transformComponent = (TransformComponent)componentAccessor.getComponent(markerEntityReference, TransformComponent.getComponentType());
return transformComponent != null ? transformComponent.getPosition() : null;
} else {
return null;
}
}
}
public void addActivePlayerUUID(UUID playerUUID) {
this.activePlayerUUIDs.add(playerUUID);
}
public void removeActivePlayerUUID(UUID playerUUID) {
this.activePlayerUUIDs.remove(playerUUID);
}
public void markDirty() {
this.dirty = true;
}
public boolean consumeDirty() {
boolean previous = this.dirty;
this.dirty = false;
return previous;
}
@Nonnull
public com.hypixel.hytale.protocol.Objective toPacket() {
ObjectiveAsset objectiveAsset = (ObjectiveAsset)Objects.requireNonNull(this.getObjectiveAsset());
com.hypixel.hytale.protocol.Objective packet = new com.hypixel.hytale.protocol.Objective();
packet.objectiveUuid = this.objectiveUUID;
packet.objectiveTitleKey = objectiveAsset.getTitleKey();
packet.objectiveDescriptionKey = this.getCurrentDescription();
if (this.objectiveLineHistoryData != null) {
packet.objectiveLineId = this.objectiveLineHistoryData.getId();
}
packet.tasks = new com.hypixel.hytale.protocol.ObjectiveTask[this.currentTasks.length];
for(int i = 0; i < this.currentTasks.length; ++i) {
packet.tasks[i] = (com.hypixel.hytale.protocol.ObjectiveTask)this.currentTasks[i].toPacket(this);
}
return packet;
}
@Nonnull
public String toString() {
String var10000 = String.valueOf(this.objectiveUUID);
return "Objective{objectiveUUID=" + var10000 + ", objectiveId='" + this.objectiveId + "', objectiveLineHistoryData=" + String.valueOf(this.objectiveLineHistoryData) + ", objectiveHistoryData=" + String.valueOf(this.objectiveHistoryData) + ", playerUUIDs=" + String.valueOf(this.playerUUIDs) + ", activePlayerUUIDs=" + String.valueOf(this.activePlayerUUIDs) + ", currentTasks=" + Arrays.toString(this.currentTasks) + ", currentTaskSetIndex=" + this.currentTaskSetIndex + ", completed=" + this.completed + ", worldUUID=" + String.valueOf(this.worldUUID) + ", markerUUID=" + String.valueOf(this.markerUUID) + ", dirty=" + this.dirty + "}";
}
static {
CODEC = ((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)BuilderCodec.builder(Objective.class, Objective::new).append(new KeyedCodec("ObjectiveUUID", Codec.UUID_BINARY), (objective, uuid) -> objective.objectiveUUID = uuid, (objective) -> objective.objectiveUUID).add()).append(new KeyedCodec("ObjectiveId", Codec.STRING), (objective, s) -> objective.objectiveId = s, (objective) -> objective.objectiveId).add()).append(new KeyedCodec("ObjectiveLineData", ObjectiveLineHistoryData.CODEC), (objective, objectiveLineData) -> objective.objectiveLineHistoryData = objectiveLineData, (objective) -> objective.objectiveLineHistoryData).add()).append(new KeyedCodec("ObjectiveData", ObjectiveHistoryData.CODEC), (objective, objectiveHistoryData) -> objective.objectiveHistoryData = objectiveHistoryData, (objective) -> objective.objectiveHistoryData).add()).append(new KeyedCodec("Players", new ArrayCodec(Codec.UUID_STRING, (x$0) -> new UUID[x$0])), (objective, o) -> {
objective.playerUUIDs = new HashSet();
Collections.addAll(objective.playerUUIDs, o);
}, (objective) -> (UUID[])objective.playerUUIDs.toArray((x$0) -> new UUID[x$0])).add()).append(new KeyedCodec("CurrentTasks", new ArrayCodec(ObjectiveTask.CODEC, (x$0) -> new ObjectiveTask[x$0])), (objective, aObjectiveTasks) -> objective.currentTasks = aObjectiveTasks, (objective) -> objective.currentTasks).add()).append(new KeyedCodec("CurrentTaskSetIndex", Codec.INTEGER), (objective, integer) -> objective.currentTaskSetIndex = integer, (objective) -> objective.currentTaskSetIndex).add()).append(new KeyedCodec("WorldUUID", Codec.UUID_BINARY), (objective, s) -> objective.worldUUID = s, (objective) -> objective.worldUUID).add()).append(new KeyedCodec("ObjectiveItemStarter", ItemStack.CODEC), (objective, itemStack) -> objective.objectiveItemStarter = itemStack, (objective) -> objective.objectiveItemStarter).add()).build();
}
}