package com.hypixel.hytale.builtin.adventure.objectives.markers.objectivelocation;
import com.hypixel.hytale.builtin.adventure.objectives.Objective;
import com.hypixel.hytale.builtin.adventure.objectives.ObjectiveDataStore;
import com.hypixel.hytale.builtin.adventure.objectives.ObjectivePlugin;
import com.hypixel.hytale.builtin.adventure.objectives.config.ObjectiveLocationMarkerAsset;
import com.hypixel.hytale.builtin.adventure.objectives.config.triggercondition.ObjectiveLocationTriggerCondition;
import com.hypixel.hytale.builtin.adventure.objectives.task.ObjectiveTask;
import com.hypixel.hytale.builtin.adventure.objectives.task.UseEntityObjectiveTask;
import com.hypixel.hytale.builtin.weather.components.WeatherTracker;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.dependency.Dependency;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.component.dependency.OrderPriority;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.spatial.SpatialResource;
import com.hypixel.hytale.component.system.HolderSystem;
import com.hypixel.hytale.component.system.RefSystem;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector3f;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.packets.assets.TrackOrUpdateObjective;
import com.hypixel.hytale.protocol.packets.assets.UntrackObjective;
import com.hypixel.hytale.server.core.asset.type.model.config.Model;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import com.hypixel.hytale.server.core.modules.entity.system.PlayerSpatialSystem;
import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
import com.hypixel.hytale.server.core.prefab.PrefabCopyableComponent;
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 it.unimi.dsi.fastutil.objects.ObjectList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class ObjectiveLocationMarkerSystems {
public ObjectiveLocationMarkerSystems() {
}
public static class InitSystem extends RefSystem<EntityStore> {
@Nonnull
private final ComponentType<EntityStore, ObjectiveLocationMarker> objectiveLocationMarkerComponent;
@Nonnull
private final ComponentType<EntityStore, ModelComponent> modelComponentType;
@Nonnull
private final ComponentType<EntityStore, TransformComponent> transformComponentType;
@Nonnull
private final Query<EntityStore> query;
public InitSystem(@Nonnull ComponentType<EntityStore, ObjectiveLocationMarker> objectiveLocationMarkerComponent) {
this.objectiveLocationMarkerComponent = objectiveLocationMarkerComponent;
this.modelComponentType = ModelComponent.getComponentType();
this.transformComponentType = TransformComponent.getComponentType();
this.query = Query.<EntityStore>and(objectiveLocationMarkerComponent, this.modelComponentType, this.transformComponentType);
}
@Nonnull
public Query<EntityStore> getQuery() {
return this.query;
}
public void onEntityAdded(@Nonnull Ref<EntityStore> ref, @Nonnull AddReason reason, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer) {
ObjectiveLocationMarker objectiveLocationMarkerComponent = (ObjectiveLocationMarker)store.getComponent(ref, this.objectiveLocationMarkerComponent);
assert objectiveLocationMarkerComponent != null;
ObjectiveLocationMarkerAsset markerAsset = (ObjectiveLocationMarkerAsset)ObjectiveLocationMarkerAsset.getAssetMap().getAsset(objectiveLocationMarkerComponent.objectiveLocationMarkerId);
if (markerAsset == null) {
ObjectivePlugin.get().getLogger().at(Level.WARNING).log("Failed to find ObjectiveLocationMarker '%s'. Entity removed!", objectiveLocationMarkerComponent.objectiveLocationMarkerId);
commandBuffer.removeEntity(ref, RemoveReason.REMOVE);
} else {
if (objectiveLocationMarkerComponent.activeObjectiveUUID != null) {
Objective activeObjective = ObjectivePlugin.get().getObjectiveDataStore().loadObjective(objectiveLocationMarkerComponent.activeObjectiveUUID, store);
if (activeObjective == null) {
ObjectivePlugin.get().getLogger().at(Level.WARNING).log("Failed to load Objective with UUID '%s'. Entity removed!", objectiveLocationMarkerComponent.activeObjectiveUUID);
commandBuffer.removeEntity(ref, RemoveReason.REMOVE);
return;
}
objectiveLocationMarkerComponent.setActiveObjective(activeObjective);
objectiveLocationMarkerComponent.setUntrackPacket(new UntrackObjective(objectiveLocationMarkerComponent.activeObjectiveUUID));
}
TransformComponent transformComponent = (TransformComponent)store.getComponent(ref, this.transformComponentType);
assert transformComponent != null;
Vector3f rotation = transformComponent.getRotation();
objectiveLocationMarkerComponent.updateLocationMarkerValues(markerAsset, rotation.getYaw(), store);
ModelComponent modelComponent = (ModelComponent)store.getComponent(ref, this.modelComponentType);
assert modelComponent != null;
Model model = modelComponent.getModel();
commandBuffer.putComponent(ref, this.modelComponentType, new ModelComponent(new Model(model.getModelAssetId(), model.getScale(), model.getRandomAttachmentIds(), model.getAttachments(), objectiveLocationMarkerComponent.getArea().getBoxForEntryArea(), model.getModel(), model.getTexture(), model.getGradientSet(), model.getGradientId(), model.getEyeHeight(), model.getCrouchOffset(), model.getAnimationSetMap(), model.getCamera(), model.getLight(), model.getParticles(), model.getTrails(), model.getPhysicsValues(), model.getDetailBoxes(), model.getPhobia(), model.getPhobiaModelAssetId())));
commandBuffer.ensureComponent(ref, PrefabCopyableComponent.getComponentType());
}
}
public void onEntityRemove(@Nonnull Ref<EntityStore> ref, @Nonnull RemoveReason reason, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer) {
ObjectiveLocationMarker objectLocationMarkerComponent = (ObjectiveLocationMarker)store.getComponent(ref, this.objectiveLocationMarkerComponent);
assert objectLocationMarkerComponent != null;
Objective activeObjective = objectLocationMarkerComponent.getActiveObjective();
if (activeObjective != null) {
ObjectiveDataStore objectiveDataStore = ObjectivePlugin.get().getObjectiveDataStore();
objectiveDataStore.saveToDisk(objectLocationMarkerComponent.activeObjectiveUUID.toString(), activeObjective);
objectiveDataStore.unloadObjective(objectLocationMarkerComponent.activeObjectiveUUID);
if (reason == RemoveReason.REMOVE) {
commandBuffer.run((theStore) -> ObjectivePlugin.get().cancelObjective(objectLocationMarkerComponent.activeObjectiveUUID, theStore));
}
}
}
}
public static class EnsureNetworkSendableSystem extends HolderSystem<EntityStore> {
@Nonnull
private final Query<EntityStore> query = Query.<EntityStore>and(ObjectiveLocationMarker.getComponentType(), Query.not(NetworkId.getComponentType()));
public EnsureNetworkSendableSystem() {
}
public void onEntityAdd(@Nonnull Holder<EntityStore> holder, @Nonnull AddReason reason, @Nonnull Store<EntityStore> store) {
holder.addComponent(NetworkId.getComponentType(), new NetworkId(((EntityStore)store.getExternalData()).takeNextNetworkId()));
}
public void onEntityRemoved(@Nonnull Holder<EntityStore> holder, @Nonnull RemoveReason reason, @Nonnull Store<EntityStore> store) {
}
@Nonnull
public Query<EntityStore> getQuery() {
return this.query;
}
}
public static class TickingSystem extends EntityTickingSystem<EntityStore> {
@Nonnull
private final ComponentType<EntityStore, ObjectiveLocationMarker> objectiveLocationMarkerComponentType;
@Nonnull
private final ComponentType<EntityStore, PlayerRef> playerRefComponentType;
@Nonnull
private final ComponentType<EntityStore, TransformComponent> transformComponentType = TransformComponent.getComponentType();
@Nonnull
private final ComponentType<EntityStore, WeatherTracker> weatherTrackerComponentType = WeatherTracker.getComponentType();
@Nonnull
private final ComponentType<EntityStore, UUIDComponent> uuidComponentType = UUIDComponent.getComponentType();
@Nonnull
private final ResourceType<EntityStore, SpatialResource<Ref<EntityStore>, EntityStore>> playerSpatialComponent;
@Nonnull
private final Query<EntityStore> query;
@Nonnull
private final Set<Dependency<EntityStore>> dependencies;
public TickingSystem(@Nonnull ComponentType<EntityStore, ObjectiveLocationMarker> objectiveLocationMarkerComponentType, @Nonnull ComponentType<EntityStore, PlayerRef> playerRefComponentType, @Nonnull ResourceType<EntityStore, SpatialResource<Ref<EntityStore>, EntityStore>> playerSpatialComponent) {
this.objectiveLocationMarkerComponentType = objectiveLocationMarkerComponentType;
this.playerRefComponentType = playerRefComponentType;
this.playerSpatialComponent = playerSpatialComponent;
this.query = Archetype.of(objectiveLocationMarkerComponentType, this.transformComponentType, this.uuidComponentType);
this.dependencies = Set.of(new SystemDependency(Order.AFTER, PlayerSpatialSystem.class, OrderPriority.CLOSEST));
}
@Nonnull
public Set<Dependency<EntityStore>> getDependencies() {
return this.dependencies;
}
@Nonnull
public Query<EntityStore> getQuery() {
return this.query;
}
public boolean isParallel(int archetypeChunkSize, int taskCount) {
return false;
}
public void tick(float dt, int systemIndex, @Nonnull Store<EntityStore> store) {
World world = ((EntityStore)store.getExternalData()).getWorld();
if (world.getWorldConfig().isObjectiveMarkersEnabled()) {
store.tick(this, dt, systemIndex);
}
}
public void tick(float dt, int index, @Nonnull ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull Store<EntityStore> store, @Nonnull CommandBuffer<EntityStore> commandBuffer) {
ObjectiveLocationMarker objectiveLocationMarkerComponent = (ObjectiveLocationMarker)archetypeChunk.getComponent(index, this.objectiveLocationMarkerComponentType);
assert objectiveLocationMarkerComponent != null;
TransformComponent transformComponent = (TransformComponent)archetypeChunk.getComponent(index, this.transformComponentType);
assert transformComponent != null;
Ref<EntityStore> entityReference = archetypeChunk.getReferenceTo(index);
Vector3d position = transformComponent.getPosition();
Objective activeObjective = objectiveLocationMarkerComponent.getActiveObjective();
if (activeObjective == null) {
UUIDComponent uuidComponent = (UUIDComponent)archetypeChunk.getComponent(index, this.uuidComponentType);
assert uuidComponent != null;
UUID uuid = uuidComponent.getUuid();
this.setupMarker(store, objectiveLocationMarkerComponent, entityReference, position, uuid, commandBuffer);
} else if (!activeObjective.isCompleted()) {
SpatialResource<Ref<EntityStore>, EntityStore> spatialResource = (SpatialResource)store.getResource(this.playerSpatialComponent);
ObjectList<Ref<EntityStore>> playerReferences = SpatialResource.getThreadLocalReferenceList();
objectiveLocationMarkerComponent.area.getPlayersInExitArea(spatialResource, playerReferences, position);
HashSet<UUID> playersInExitArea = new HashSet(playerReferences.size());
PlayerRef[] playersInEntryArea = new PlayerRef[playerReferences.size()];
int playersInEntryAreaSize = 0;
for(Ref<EntityStore> playerReference : playerReferences) {
PlayerRef playerRefComponent = (PlayerRef)commandBuffer.getComponent(playerReference, this.playerRefComponentType);
assert playerRefComponent != null;
UUIDComponent playerUuidComponent = (UUIDComponent)commandBuffer.getComponent(playerReference, this.uuidComponentType);
assert playerUuidComponent != null;
TransformComponent playerTransformComponent = (TransformComponent)commandBuffer.getComponent(playerReference, this.transformComponentType);
assert playerTransformComponent != null;
WeatherTracker playerWeatherTrackerComponent = (WeatherTracker)commandBuffer.getComponent(playerReference, this.weatherTrackerComponentType);
assert playerWeatherTrackerComponent != null;
if (isPlayerInSpecificEnvironment(objectiveLocationMarkerComponent, playerWeatherTrackerComponent, playerTransformComponent, commandBuffer)) {
playersInExitArea.add(playerUuidComponent.getUuid());
if (objectiveLocationMarkerComponent.area.isPlayerInEntryArea(playerTransformComponent.getPosition(), position)) {
playersInEntryArea[playersInEntryAreaSize++] = playerRefComponent;
}
}
}
Set<UUID> playerUUIDs = activeObjective.getPlayerUUIDs();
Set<UUID> activePlayerUUIDs = activeObjective.getActivePlayerUUIDs();
String objectiveId = activeObjective.getObjectiveId();
updateIncomingPlayers(playersInEntryArea, playersInEntryAreaSize, objectiveLocationMarkerComponent, playerUUIDs, activePlayerUUIDs, objectiveId);
updateOutgoingPlayers(playersInExitArea, objectiveLocationMarkerComponent, activePlayerUUIDs, objectiveId);
} else {
commandBuffer.removeEntity(entityReference, RemoveReason.REMOVE);
}
}
private void setupMarker(@Nonnull Store<EntityStore> store, @Nonnull ObjectiveLocationMarker entity, @Nonnull Ref<EntityStore> entityReference, @Nonnull Vector3d position, @Nonnull UUID uuid, @Nonnull CommandBuffer<EntityStore> commandBuffer) {
if (entity.triggerConditions != null && entity.triggerConditions.length > 0) {
SpatialResource<Ref<EntityStore>, EntityStore> spatialResource = (SpatialResource)store.getResource(this.playerSpatialComponent);
if (!entity.area.hasPlayerInExitArea(spatialResource, this.playerRefComponentType, position, commandBuffer)) {
return;
}
for(ObjectiveLocationTriggerCondition triggerCondition : entity.triggerConditions) {
if (!triggerCondition.isConditionMet(commandBuffer, entityReference, entity)) {
return;
}
}
}
ObjectiveLocationMarkerAsset objectiveLocationMarkerAsset = (ObjectiveLocationMarkerAsset)ObjectiveLocationMarkerAsset.getAssetMap().getAsset(entity.objectiveLocationMarkerId);
if (objectiveLocationMarkerAsset == null) {
ObjectivePlugin.get().getLogger().at(Level.WARNING).log("Could not find ObjectiveLocationMarker '%s'. Entity removed!", entity.objectiveLocationMarkerId);
commandBuffer.removeEntity(entityReference, RemoveReason.REMOVE);
} else {
World world = ((EntityStore)store.getExternalData()).getWorld();
Objective objective = objectiveLocationMarkerAsset.getObjectiveTypeSetup().setup(new HashSet(), world.getWorldConfig().getUuid(), uuid, store);
if (objective == null) {
ObjectivePlugin.get().getLogger().at(Level.WARNING).log("Objective failed to setup for ObjectiveLocationMarker '%s'. Entity removed!", entity.objectiveLocationMarkerId);
commandBuffer.removeEntity(entityReference, RemoveReason.REMOVE);
} else {
entity.setActiveObjective(objective);
entity.activeObjectiveUUID = objective.getObjectiveUUID();
entity.setUntrackPacket(new UntrackObjective(entity.activeObjectiveUUID));
}
}
}
private static void updateIncomingPlayers(@Nonnull PlayerRef[] playersInArea, int playersInAreaSize, @Nonnull ObjectiveLocationMarker entity, @Nonnull Set<UUID> playerUUIDs, @Nonnull Set<UUID> activePlayerUUIDs, @Nonnull String objectiveId) {
if (playersInArea.length != 0) {
TrackOrUpdateObjective trackPacket = null;
ObjectivePlugin objectiveModule = ObjectivePlugin.get();
HytaleLogger logger = objectiveModule.getLogger();
ObjectiveDataStore objectiveDataStore = objectiveModule.getObjectiveDataStore();
for(int i = 0; i < playersInAreaSize; ++i) {
PlayerRef playerRef = playersInArea[i];
UUID playerUUID = playerRef.getUuid();
if (activePlayerUUIDs.add(playerUUID)) {
playerUUIDs.add(playerUUID);
logger.at(Level.FINE).log("Player '%s' joined the objective area for marker '%s', current objective '%s' with UUID '%s'", playerRef.getUsername(), entity.objectiveLocationMarkerId, objectiveId, entity.activeObjectiveUUID);
if (trackPacket == null) {
trackPacket = new TrackOrUpdateObjective(entity.getActiveObjective().toPacket());
}
playerRef.getPacketHandler().writeNoCache(trackPacket);
for(ObjectiveTask task : entity.getActiveObjective().getCurrentTasks()) {
if (task instanceof UseEntityObjectiveTask) {
objectiveDataStore.addEntityTaskForPlayer(playerUUID, ((UseEntityObjectiveTask)task).getAsset().getTaskId(), entity.activeObjectiveUUID);
}
}
}
}
}
}
private static void updateOutgoingPlayers(@Nonnull Set<UUID> playersInArea, @Nonnull ObjectiveLocationMarker entity, @Nullable Set<UUID> activePlayerUUIDs, @Nonnull String objectiveId) {
if (activePlayerUUIDs != null && !activePlayerUUIDs.isEmpty()) {
HytaleLogger logger = ObjectivePlugin.get().getLogger();
Iterator<UUID> iterator = activePlayerUUIDs.iterator();
Universe universe = Universe.get();
while(iterator.hasNext()) {
UUID uuid = (UUID)iterator.next();
if (!playersInArea.contains(uuid)) {
iterator.remove();
untrackEntityObjectiveForPlayer(entity, uuid);
PlayerRef playerRef = universe.getPlayer(uuid);
logger.at(Level.FINE).log("Player '%s' left the objective area for marker '%s', current objective '%s' with UUID '%s'", playerRef == null ? uuid : playerRef.getUsername(), entity.objectiveLocationMarkerId, objectiveId, entity.activeObjectiveUUID);
if (playerRef != null) {
playerRef.getPacketHandler().write((Packet)entity.getUntrackPacket());
}
}
}
}
}
private static boolean isPlayerInSpecificEnvironment(@Nonnull ObjectiveLocationMarker entity, @Nonnull WeatherTracker weatherTracker, @Nonnull TransformComponent transform, @Nonnull ComponentAccessor<EntityStore> componentAccessor) {
if (entity.environmentIndexes == null) {
return true;
} else {
weatherTracker.updateEnvironment(transform, componentAccessor);
int environmentIndex = weatherTracker.getEnvironmentId();
return Arrays.binarySearch(entity.environmentIndexes, environmentIndex) >= 0;
}
}
private static void untrackEntityObjectiveForPlayer(@Nonnull ObjectiveLocationMarker entity, @Nonnull UUID playerUUID) {
ObjectiveDataStore objectiveDataStore = ObjectivePlugin.get().getObjectiveDataStore();
for(ObjectiveTask task : entity.getActiveObjective().getCurrentTasks()) {
if (task instanceof UseEntityObjectiveTask) {
String taskId = ((UseEntityObjectiveTask)task).getAsset().getTaskId();
objectiveDataStore.removeEntityTaskForPlayer(entity.activeObjectiveUUID, taskId, playerUUID);
}
}
}
}
}