343 lines
13 KiB
Java
343 lines
13 KiB
Java
package com.hypixel.hytale.builtin.adventure.objectives.task;
|
|
|
|
import com.hypixel.hytale.builtin.adventure.objectives.Objective;
|
|
import com.hypixel.hytale.builtin.adventure.objectives.ObjectivePlugin;
|
|
import com.hypixel.hytale.builtin.adventure.objectives.config.task.ObjectiveTaskAsset;
|
|
import com.hypixel.hytale.builtin.adventure.objectives.config.taskcondition.TaskConditionAsset;
|
|
import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionRecord;
|
|
import com.hypixel.hytale.builtin.adventure.objectives.transaction.TransactionUtil;
|
|
import com.hypixel.hytale.builtin.adventure.objectives.transaction.WorldTransactionRecord;
|
|
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.codec.lookup.CodecMapCodec;
|
|
import com.hypixel.hytale.component.ComponentAccessor;
|
|
import com.hypixel.hytale.component.Ref;
|
|
import com.hypixel.hytale.component.Store;
|
|
import com.hypixel.hytale.event.EventRegistry;
|
|
import com.hypixel.hytale.math.vector.Transform;
|
|
import com.hypixel.hytale.math.vector.Vector3i;
|
|
import com.hypixel.hytale.protocol.packets.assets.UpdateObjectiveTask;
|
|
import com.hypixel.hytale.protocol.packets.worldmap.MapMarker;
|
|
import com.hypixel.hytale.server.core.Message;
|
|
import com.hypixel.hytale.server.core.codec.ProtocolCodecs;
|
|
import com.hypixel.hytale.server.core.entity.entities.Player;
|
|
import com.hypixel.hytale.server.core.io.NetworkSerializer;
|
|
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 com.hypixel.hytale.server.core.util.PositionUtil;
|
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
import javax.annotation.Nonnull;
|
|
import javax.annotation.Nullable;
|
|
|
|
public abstract class ObjectiveTask implements NetworkSerializer<Objective, com.hypixel.hytale.protocol.ObjectiveTask> {
|
|
public static final CodecMapCodec<ObjectiveTask> CODEC = new CodecMapCodec<>("Type");
|
|
public static final BuilderCodec<ObjectiveTask> BASE_CODEC = BuilderCodec.abstractBuilder(ObjectiveTask.class)
|
|
.append(
|
|
new KeyedCodec<>("Task", ObjectiveTaskAsset.CODEC),
|
|
(aObjectiveTask, objectiveTaskAsset) -> aObjectiveTask.asset = objectiveTaskAsset,
|
|
aObjectiveTask -> aObjectiveTask.asset
|
|
)
|
|
.add()
|
|
.append(
|
|
new KeyedCodec<>("Complete", Codec.BOOLEAN),
|
|
(aObjectiveTask, aBoolean) -> aObjectiveTask.complete = aBoolean,
|
|
aObjectiveTask -> aObjectiveTask.complete
|
|
)
|
|
.add()
|
|
.append(
|
|
new KeyedCodec<>("TransactionRecords", new ArrayCodec<>(TransactionRecord.CODEC, TransactionRecord[]::new)),
|
|
(objectiveTask, transactionRecords) -> objectiveTask.serializedTransactionRecords = transactionRecords,
|
|
objectiveTask -> objectiveTask.serializedTransactionRecords
|
|
)
|
|
.add()
|
|
.append(
|
|
new KeyedCodec<>("TaskIndex", Codec.INTEGER), (objectiveTask, integer) -> objectiveTask.taskIndex = integer, objectiveTask -> objectiveTask.taskIndex
|
|
)
|
|
.add()
|
|
.append(new KeyedCodec<>("Markers", ProtocolCodecs.MARKER_ARRAY), (objectiveTask, markers) -> {
|
|
objectiveTask.markers.clear();
|
|
Collections.addAll(objectiveTask.markers, markers);
|
|
}, objectiveTask -> objectiveTask.markers.toArray(MapMarker[]::new))
|
|
.add()
|
|
.append(
|
|
new KeyedCodec<>("TaskSetIndex", Codec.INTEGER),
|
|
(objectiveTask, integer) -> objectiveTask.taskSetIndex = integer,
|
|
objectiveTask -> objectiveTask.taskSetIndex
|
|
)
|
|
.add()
|
|
.build();
|
|
protected ObjectiveTaskAsset asset;
|
|
protected boolean complete = false;
|
|
@Nullable
|
|
protected EventRegistry eventRegistry;
|
|
@Nullable
|
|
protected TransactionRecord[] serializedTransactionRecords;
|
|
@Nullable
|
|
protected TransactionRecord[] nonSerializedTransactionRecords;
|
|
protected int taskIndex;
|
|
@Nonnull
|
|
protected List<MapMarker> markers = new ObjectArrayList();
|
|
protected int taskSetIndex;
|
|
protected ObjectiveTaskRef<? extends ObjectiveTask> taskRef;
|
|
|
|
public ObjectiveTask(@Nonnull ObjectiveTaskAsset asset, int taskSetIndex, int taskIndex) {
|
|
this.asset = asset;
|
|
this.taskIndex = taskIndex;
|
|
this.taskSetIndex = taskSetIndex;
|
|
}
|
|
|
|
protected ObjectiveTask() {
|
|
}
|
|
|
|
@Nonnull
|
|
public ObjectiveTaskAsset getAsset() {
|
|
return this.asset;
|
|
}
|
|
|
|
public void setAsset(@Nonnull ObjectiveTaskAsset asset) {
|
|
this.asset = asset;
|
|
}
|
|
|
|
public boolean isComplete() {
|
|
return this.complete;
|
|
}
|
|
|
|
@Nullable
|
|
public TransactionRecord[] getSerializedTransactionRecords() {
|
|
return this.serializedTransactionRecords;
|
|
}
|
|
|
|
@Nullable
|
|
public TransactionRecord[] getNonSerializedTransactionRecords() {
|
|
return this.nonSerializedTransactionRecords;
|
|
}
|
|
|
|
@Nonnull
|
|
public Message getInfoMessage(@Nonnull Objective objective) {
|
|
return Message.translation(this.asset.getDescriptionKey(objective.getObjectiveId(), this.taskSetIndex, this.taskIndex));
|
|
}
|
|
|
|
@Nonnull
|
|
public List<MapMarker> getMarkers() {
|
|
return this.markers;
|
|
}
|
|
|
|
public void addMarker(@Nonnull MapMarker marker) {
|
|
this.markers.add(marker);
|
|
}
|
|
|
|
public void removeMarker(String id) {
|
|
for (MapMarker marker : this.markers) {
|
|
if (marker.id.equals(id)) {
|
|
this.markers.remove(marker);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public abstract boolean checkCompletion();
|
|
|
|
@Nullable
|
|
protected abstract TransactionRecord[] setup0(@Nonnull Objective var1, @Nonnull World var2, @Nonnull Store<EntityStore> var3);
|
|
|
|
@Nullable
|
|
public final TransactionRecord[] setup(@Nonnull Objective objective, @Nonnull Store<EntityStore> store) {
|
|
World world = Universe.get().getWorld(objective.getWorldUUID());
|
|
if (world == null) {
|
|
String transactionMessage = "This World doesn't exist in this Universe: " + objective.getWorldUUID();
|
|
return TransactionRecord.appendFailedTransaction(this.nonSerializedTransactionRecords, new WorldTransactionRecord(), transactionMessage);
|
|
} else if (this.eventRegistry != null) {
|
|
throw new IllegalStateException("ObjectiveTask.eventRegistry is not null, setup() shouldn't be run more than once!");
|
|
} else {
|
|
this.eventRegistry = new EventRegistry(new CopyOnWriteArrayList<>(), () -> true, null, world.getEventRegistry());
|
|
Vector3i[] mapMarkerPositions = this.asset.getMapMarkers();
|
|
if (mapMarkerPositions != null) {
|
|
String objectiveUUIDString = objective.getObjectiveUUID().toString();
|
|
|
|
for (int i = 0; i < mapMarkerPositions.length; i++) {
|
|
Vector3i mapMarkerPosition = mapMarkerPositions[i];
|
|
this.addMarker(
|
|
new MapMarker(
|
|
"ObjectiveMarker_" + objectiveUUIDString + "_" + i,
|
|
"Objective",
|
|
"Home.png",
|
|
PositionUtil.toTransformPacket(new Transform(mapMarkerPosition)),
|
|
null
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
this.taskRef = new ObjectiveTaskRef<>(objective.getObjectiveUUID(), this);
|
|
this.registerTaskRef();
|
|
TransactionRecord[] transactionRecords = this.setup0(objective, world, store);
|
|
if (transactionRecords == null) {
|
|
return null;
|
|
} else {
|
|
int serializedCount = 0;
|
|
|
|
for (TransactionRecord transactionRecord : transactionRecords) {
|
|
if (transactionRecord.shouldBeSerialized()) {
|
|
serializedCount++;
|
|
}
|
|
}
|
|
|
|
this.serializedTransactionRecords = new TransactionRecord[serializedCount];
|
|
this.nonSerializedTransactionRecords = new TransactionRecord[transactionRecords.length - serializedCount];
|
|
int serializedIndex = 0;
|
|
int nonSerializedIndex = 0;
|
|
|
|
for (TransactionRecord transactionRecordx : transactionRecords) {
|
|
if (transactionRecordx.shouldBeSerialized()) {
|
|
this.serializedTransactionRecords[serializedIndex++] = transactionRecordx;
|
|
} else {
|
|
this.nonSerializedTransactionRecords[nonSerializedIndex++] = transactionRecordx;
|
|
}
|
|
}
|
|
|
|
return transactionRecords;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void complete(@Nonnull Objective objective, @Nullable ComponentAccessor<EntityStore> componentAccessor) {
|
|
if (!this.complete) {
|
|
if (componentAccessor != null) {
|
|
objective.forEachParticipant((participantReference, message) -> {
|
|
Player playerComponent = componentAccessor.getComponent(participantReference, Player.getComponentType());
|
|
if (playerComponent != null) {
|
|
playerComponent.sendMessage(message);
|
|
}
|
|
}, Message.translation("server.modules.objective.task.completed").insert(this.getInfoMessage(objective)));
|
|
}
|
|
|
|
this.markers.clear();
|
|
this.complete = true;
|
|
this.completeTransactionRecords();
|
|
}
|
|
}
|
|
|
|
private void registerTaskRef() {
|
|
ObjectivePlugin.get().getObjectiveDataStore().addTaskRef(this.taskRef);
|
|
}
|
|
|
|
private void unregisterTaskRef() {
|
|
ObjectivePlugin.get().getObjectiveDataStore().removeTaskRef(this.taskRef);
|
|
}
|
|
|
|
public void completeTransactionRecords() {
|
|
TransactionUtil.completeAll(this.serializedTransactionRecords);
|
|
this.serializedTransactionRecords = null;
|
|
TransactionUtil.completeAll(this.nonSerializedTransactionRecords);
|
|
this.nonSerializedTransactionRecords = null;
|
|
this.shutdownEventRegistry();
|
|
this.unregisterTaskRef();
|
|
}
|
|
|
|
public void revertTransactionRecords() {
|
|
TransactionUtil.revertAll(this.serializedTransactionRecords);
|
|
this.serializedTransactionRecords = null;
|
|
TransactionUtil.revertAll(this.nonSerializedTransactionRecords);
|
|
this.nonSerializedTransactionRecords = null;
|
|
this.shutdownEventRegistry();
|
|
this.unregisterTaskRef();
|
|
}
|
|
|
|
public void unloadTransactionRecords() {
|
|
TransactionUtil.unloadAll(this.serializedTransactionRecords);
|
|
this.serializedTransactionRecords = null;
|
|
TransactionUtil.unloadAll(this.nonSerializedTransactionRecords);
|
|
this.nonSerializedTransactionRecords = null;
|
|
this.shutdownEventRegistry();
|
|
this.unregisterTaskRef();
|
|
}
|
|
|
|
private void shutdownEventRegistry() {
|
|
if (this.eventRegistry != null) {
|
|
this.eventRegistry.shutdown();
|
|
this.eventRegistry = null;
|
|
}
|
|
}
|
|
|
|
public void assetChanged(@Nonnull Objective objective) {
|
|
if (!this.complete) {
|
|
if (this.checkCompletion()) {
|
|
this.consumeTaskConditions(null, null, objective.getActivePlayerUUIDs());
|
|
this.complete(objective, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void sendUpdateObjectiveTaskPacket(@Nonnull Objective objective) {
|
|
UpdateObjectiveTask updateObjectiveTaskPacket = new UpdateObjectiveTask(objective.getObjectiveUUID(), this.taskIndex, this.toPacket(objective));
|
|
Universe universe = Universe.get();
|
|
|
|
for (UUID playerUUID : objective.getActivePlayerUUIDs()) {
|
|
PlayerRef player = universe.getPlayer(playerUUID);
|
|
if (player != null) {
|
|
player.getPacketHandler().writeNoCache(updateObjectiveTaskPacket);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean areTaskConditionsFulfilled(
|
|
@Nullable ComponentAccessor<EntityStore> componentAccessor, @Nullable Ref<EntityStore> ref, @Nullable Set<UUID> objectivePlayers
|
|
) {
|
|
TaskConditionAsset[] taskConditions = this.asset.getTaskConditions();
|
|
if (taskConditions == null) {
|
|
return true;
|
|
} else {
|
|
for (TaskConditionAsset taskCondition : taskConditions) {
|
|
if (!taskCondition.isConditionFulfilled(componentAccessor, ref, objectivePlayers)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public void consumeTaskConditions(
|
|
@Nullable ComponentAccessor<EntityStore> componentAccessor, @Nullable Ref<EntityStore> ref, @Nonnull Set<UUID> objectivePlayers
|
|
) {
|
|
TaskConditionAsset[] taskConditions = this.asset.getTaskConditions();
|
|
if (taskConditions != null) {
|
|
for (TaskConditionAsset taskCondition : taskConditions) {
|
|
taskCondition.consumeCondition(componentAccessor, ref, objectivePlayers);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public String toString() {
|
|
return "ObjectiveTask{asset="
|
|
+ this.asset
|
|
+ ", complete="
|
|
+ this.complete
|
|
+ ", eventRegistry="
|
|
+ this.eventRegistry
|
|
+ ", serializedTransactionRecords="
|
|
+ Arrays.toString((Object[])this.serializedTransactionRecords)
|
|
+ ", nonSerializedTransactionRecords="
|
|
+ Arrays.toString((Object[])this.nonSerializedTransactionRecords)
|
|
+ ", taskIndex="
|
|
+ this.taskIndex
|
|
+ ", markers="
|
|
+ this.markers
|
|
+ ", taskSetIndex="
|
|
+ this.taskSetIndex
|
|
+ "}";
|
|
}
|
|
}
|