package com.hypixel.hytale.builtin.buildertools.prefabeditor;
import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin;
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.Resource;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.math.codec.Vector3iArrayCodec;
import com.hypixel.hytale.math.vector.Transform;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.protocol.packets.buildertools.BuilderToolHideAnchors;
import com.hypixel.hytale.protocol.packets.worldmap.ContextMenuItem;
import com.hypixel.hytale.protocol.packets.worldmap.MapMarker;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.io.PacketHandler;
import com.hypixel.hytale.server.core.prefab.selection.standard.BlockSelection;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.universe.Universe;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.server.core.util.PositionUtil;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.nio.file.Path;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class PrefabEditSession implements Resource<EntityStore> {
@Nonnull
public static final BuilderCodec<PrefabEditSession> CODEC;
private String worldName;
private UUID worldArrivedFrom;
@Nullable
private Transform transformArrivedFrom;
private UUID worldCreator;
@Nonnull
private final Map<UUID, PrefabEditingMetadata> loadedPrefabMetadata = new Object2ObjectOpenHashMap<UUID, PrefabEditingMetadata>();
@Nonnull
private final Map<UUID, UUID> selectedPrefab = new Object2ObjectOpenHashMap<UUID, UUID>();
@Nonnull
private Vector3i spawnPoint = new Vector3i(0, 0, 0);
@Nonnull
public static ResourceType<EntityStore, PrefabEditSession> getResourceType() {
return BuilderToolsPlugin.get().getPrefabEditSessionResourceType();
}
private PrefabEditSession() {
}
public PrefabEditSession(@Nonnull String worldName, @Nonnull UUID worldCreator, @Nonnull UUID worldArrivedFrom, @Nonnull Transform transformArrivedFrom) {
this.worldName = worldName;
this.worldCreator = worldCreator;
this.worldArrivedFrom = worldArrivedFrom;
this.transformArrivedFrom = transformArrivedFrom;
}
public PrefabEditSession(@Nonnull PrefabEditSession other) {
this.worldName = other.worldName;
this.worldArrivedFrom = other.worldArrivedFrom;
this.transformArrivedFrom = other.transformArrivedFrom;
this.worldCreator = other.worldCreator;
this.spawnPoint = other.spawnPoint;
}
public void addPrefab(@Nonnull Path prefabPath, @Nonnull Vector3i minPoint, @Nonnull Vector3i maxPoint, @Nonnull Vector3i anchorPoint, @Nonnull Vector3i pastePosition) {
if (this.loadedPrefabMetadata.isEmpty()) {
this.spawnPoint.assign(maxPoint);
}
PrefabEditingMetadata prefabEditingMetadata = new PrefabEditingMetadata(prefabPath, minPoint, maxPoint, anchorPoint, pastePosition, Universe.get().getWorld(this.worldName));
this.loadedPrefabMetadata.put(prefabEditingMetadata.getUuid(), prefabEditingMetadata);
}
@Nullable
public PrefabEditingMetadata updatePrefabBounds(@Nonnull UUID prefab, @Nonnull Vector3i newMin, @Nonnull Vector3i newMax) {
PrefabEditingMetadata prefabEditingMetadata = (PrefabEditingMetadata)this.loadedPrefabMetadata.get(prefab);
if (prefabEditingMetadata == null) {
return null;
} else {
prefabEditingMetadata.setMaxPoint(newMax);
prefabEditingMetadata.setMinPoint(newMin);
prefabEditingMetadata.setDirty(true);
return prefabEditingMetadata;
}
}
public void setSelectedPrefab(@Nonnull Ref<EntityStore> ref, @Nonnull PrefabEditingMetadata prefabEditingMetadata, @Nonnull ComponentAccessor<EntityStore> componentAccessor) {
UUIDComponent uuidComponent = (UUIDComponent)componentAccessor.getComponent(ref, UUIDComponent.getComponentType());
assert uuidComponent != null;
Player playerComponent = (Player)componentAccessor.getComponent(ref, Player.getComponentType());
assert playerComponent != null;
PlayerRef playerRefComponent = (PlayerRef)componentAccessor.getComponent(ref, PlayerRef.getComponentType());
assert playerRefComponent != null;
UUID playerUUID = uuidComponent.getUuid();
if (this.selectedPrefab.get(playerUUID) != null && ((UUID)this.selectedPrefab.get(playerUUID)).equals(prefabEditingMetadata.getUuid())) {
BlockSelection selection = BuilderToolsPlugin.getState(playerComponent, playerRefComponent).getSelection();
if (selection != null && prefabEditingMetadata.getMinPoint().equals(selection.getSelectionMin()) && prefabEditingMetadata.getMaxPoint().equals(selection.getSelectionMax())) {
return;
}
}
this.selectedPrefab.put(playerUUID, prefabEditingMetadata.getUuid());
prefabEditingMetadata.sendAnchorHighlightingPacket(playerRefComponent.getPacketHandler());
BuilderToolsPlugin.addToQueue(playerComponent, playerRefComponent, (r, s, compAccess) -> s.select(prefabEditingMetadata.getMinPoint(), prefabEditingMetadata.getMaxPoint(), (String)null, compAccess));
}
public void hidePrefabAnchors(@Nonnull PacketHandler packetHandler) {
packetHandler.writeNoCache(new BuilderToolHideAnchors());
}
@Nullable
public PrefabEditingMetadata getSelectedPrefab(@Nonnull UUID playerUuid) {
UUID prefabUuid = (UUID)this.selectedPrefab.get(playerUuid);
return prefabUuid == null ? null : (PrefabEditingMetadata)this.loadedPrefabMetadata.get(prefabUuid);
}
public boolean clearSelectedPrefab(@Nonnull Ref<EntityStore> ref, @Nonnull ComponentAccessor<EntityStore> componentAccessor) {
UUIDComponent uuidComponent = (UUIDComponent)componentAccessor.getComponent(ref, UUIDComponent.getComponentType());
assert uuidComponent != null;
UUID playerUUID = uuidComponent.getUuid();
if (this.selectedPrefab.remove(playerUUID) == null) {
return false;
} else {
PlayerRef playerRefComponent = (PlayerRef)componentAccessor.getComponent(ref, PlayerRef.getComponentType());
assert playerRefComponent != null;
Player playerComponent = (Player)componentAccessor.getComponent(ref, Player.getComponentType());
assert playerComponent != null;
this.hidePrefabAnchors(playerRefComponent.getPacketHandler());
BuilderToolsPlugin.addToQueue(playerComponent, playerRefComponent, (r, s, compAccess) -> s.deselect(compAccess));
return true;
}
}
@Nonnull
public String getWorldName() {
return this.worldName;
}
public UUID getWorldArrivedFrom() {
return this.worldArrivedFrom;
}
@Nullable
public Transform getTransformArrivedFrom() {
return this.transformArrivedFrom;
}
public UUID getWorldCreator() {
return this.worldCreator;
}
@Nonnull
public Vector3i getSpawnPoint() {
return this.spawnPoint;
}
@Nonnull
public Map<UUID, PrefabEditingMetadata> getLoadedPrefabMetadata() {
return this.loadedPrefabMetadata;
}
public void markPrefabsDirtyAtPosition(@Nonnull Vector3i position) {
for(PrefabEditingMetadata metadata : this.loadedPrefabMetadata.values()) {
if (metadata.isLocationWithinPrefabBoundingBox(position)) {
metadata.setDirty(true);
}
}
}
public void markPrefabsDirtyInBounds(@Nonnull Vector3i min, @Nonnull Vector3i max) {
for(PrefabEditingMetadata metadata : this.loadedPrefabMetadata.values()) {
if (boundsIntersect(metadata.getMinPoint(), metadata.getMaxPoint(), min, max)) {
metadata.setDirty(true);
}
}
}
private static boolean boundsIntersect(@Nonnull Vector3i aMin, @Nonnull Vector3i aMax, @Nonnull Vector3i bMin, @Nonnull Vector3i bMax) {
return aMin.x <= bMax.x && aMax.x >= bMin.x && aMin.y <= bMax.y && aMax.y >= bMin.y && aMin.z <= bMax.z && aMax.z >= bMin.z;
}
@Nonnull
public MapMarker[] createPrefabMarkers() {
return (MapMarker[])this.loadedPrefabMetadata.values().stream().map(PrefabEditSession::createPrefabMarker).toArray((x$0) -> new MapMarker[x$0]);
}
@Nonnull
public static MapMarker createPrefabMarker(@Nonnull PrefabEditingMetadata metadata) {
String fileName = metadata.getPrefabPath().getFileName().toString();
String prefabName = fileName.replace(".prefab.json", "");
return new MapMarker("prefab-" + String.valueOf(metadata.getUuid()), prefabName, "Prefab.png", PositionUtil.toTransformPacket(new Transform(metadata.getAnchorEntityPosition().toVector3d())), (ContextMenuItem[])null);
}
@Nonnull
public PrefabEditSession clone() {
return new PrefabEditSession(this);
}
static {
CODEC = ((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)((BuilderCodec.Builder)BuilderCodec.builder(PrefabEditSession.class, PrefabEditSession::new).append(new KeyedCodec("WorldName", Codec.STRING, true), (o, worldName) -> o.worldName = worldName, (o) -> o.worldName).add()).append(new KeyedCodec("WorldArrivedFrom", Codec.UUID_STRING, true), (o, worldName) -> o.worldArrivedFrom = worldName, (o) -> o.worldArrivedFrom).add()).append(new KeyedCodec("TransformArrivedFrom", Transform.CODEC, true), (o, positionArrivedFrom) -> o.transformArrivedFrom = positionArrivedFrom, (o) -> o.transformArrivedFrom).add()).append(new KeyedCodec("WorldCreatorUUID", Codec.UUID_STRING, true), (o, worldCreatorUuid) -> o.worldCreator = worldCreatorUuid, (o) -> o.worldCreator).add()).append(new KeyedCodec("SpawnPoint", new Vector3iArrayCodec(), true), (o, spawnPoint) -> o.spawnPoint = spawnPoint, (o) -> o.spawnPoint).add()).append(new KeyedCodec("LoadedPrefabMetadata", new ArrayCodec(PrefabEditingMetadata.CODEC, (x$0) -> new PrefabEditingMetadata[x$0]), false), (editSession, prefabEditingMetadata) -> {
for(PrefabEditingMetadata prefabEditMetadata : prefabEditingMetadata) {
editSession.loadedPrefabMetadata.put(prefabEditMetadata.getUuid(), prefabEditMetadata);
}
}, (editSession) -> (PrefabEditingMetadata[])editSession.loadedPrefabMetadata.values().toArray((x$0) -> new PrefabEditingMetadata[x$0])).add()).afterDecode((editSession) -> {
PrefabEditSessionManager prefabEditSessionManager = BuilderToolsPlugin.get().getPrefabEditSessionManager();
prefabEditSessionManager.populateActiveEditSession(editSession.getWorldCreator(), editSession);
for(PrefabEditingMetadata value : editSession.loadedPrefabMetadata.values()) {
prefabEditSessionManager.populatePrefabsBeingEdited(value.getPrefabPath());
}
prefabEditSessionManager.scheduleAnchorEntityRecreation(editSession);
})).build();
}
}