PrefabEditSaveCommand.java
package com.hypixel.hytale.builtin.buildertools.prefabeditor.commands;
import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.PrefabEditSession;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.PrefabEditSessionManager;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.PrefabEditingMetadata;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.saving.PrefabSaver;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.saving.PrefabSaverSettings;
import com.hypixel.hytale.common.util.PathUtil;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.arguments.system.FlagArg;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncPlayerCommand;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.modules.singleplayer.SingleplayerModule;
import com.hypixel.hytale.server.core.prefab.PrefabStore;
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.world.World;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import javax.annotation.Nonnull;
public class PrefabEditSaveCommand extends AbstractAsyncPlayerCommand {
@Nonnull
private static final Message MESSAGE_COMMANDS_EDIT_PREFAB_NOT_IN_EDIT_SESSION = Message.translation("server.commands.editprefab.notInEditSession");
@Nonnull
private static final Message MESSAGE_PATH_OUTSIDE_PREFABS_DIR = Message.translation("server.builderTools.attemptedToSaveOutsidePrefabsDir");
@Nonnull
private final FlagArg saveAllArg = (FlagArg)this.withFlagArg("saveAll", "server.commands.editprefab.save.saveAll.desc").addAliases(new String[]{"all"});
@Nonnull
private final FlagArg noEntitiesArg = this.withFlagArg("noEntities", "server.commands.editprefab.save.noEntities.desc");
@Nonnull
private final FlagArg emptyArg = this.withFlagArg("empty", "server.commands.editprefab.save.empty.desc");
@Nonnull
private final FlagArg confirmArg = this.withFlagArg("confirm", "server.commands.editprefab.save.confirm.desc");
private static boolean isPathInAllowedPrefabDirectory(@Nonnull Path path) {
PrefabStore prefabStore = PrefabStore.get();
return PathUtil.isChildOf(prefabStore.getServerPrefabsPath(), path) || PathUtil.isChildOf(prefabStore.getAssetPrefabsPath(), path) || PathUtil.isChildOf(prefabStore.getWorldGenPrefabsPath(), path);
}
public PrefabEditSaveCommand() {
super("save", "server.commands.editprefab.save.desc");
}
@Nonnull
protected CompletableFuture<Void> executeAsync(@Nonnull CommandContext context, @Nonnull Store<EntityStore> store, @Nonnull Ref<EntityStore> ref, @Nonnull PlayerRef playerRef, @Nonnull World world) {
Player playerComponent = (Player)store.getComponent(ref, Player.getComponentType());
assert playerComponent != null;
PrefabEditSessionManager prefabEditSessionManager = BuilderToolsPlugin.get().getPrefabEditSessionManager();
PrefabEditSession prefabEditSession = prefabEditSessionManager.getPrefabEditSession(playerRef.getUuid());
if (prefabEditSession == null) {
context.sendMessage(MESSAGE_COMMANDS_EDIT_PREFAB_NOT_IN_EDIT_SESSION);
return CompletableFuture.completedFuture((Object)null);
} else {
PrefabSaverSettings prefabSaverSettings = new PrefabSaverSettings();
prefabSaverSettings.setBlocks(true);
prefabSaverSettings.setEntities(!this.noEntitiesArg.provided(context));
prefabSaverSettings.setOverwriteExisting(true);
prefabSaverSettings.setEmpty((Boolean)this.emptyArg.get(context));
boolean confirm = this.confirmArg.provided(context);
if (!this.saveAllArg.provided(context)) {
PrefabEditingMetadata selectedPrefab = prefabEditSession.getSelectedPrefab(playerRef.getUuid());
if (selectedPrefab == null) {
context.sendMessage(Message.translation("server.commands.editprefab.noPrefabSelected"));
return CompletableFuture.completedFuture((Object)null);
} else if (selectedPrefab.isReadOnly() && !confirm) {
Path redirectPath = getWritableSavePath(selectedPrefab, true);
context.sendMessage(Message.translation("server.commands.editprefab.save.readOnlyNeedsConfirmSingle").param("path", selectedPrefab.getPrefabPath().toString()).param("redirectPath", redirectPath.toString()));
return CompletableFuture.completedFuture((Object)null);
} else {
BlockSelection selection = BuilderToolsPlugin.getState(playerComponent, playerRef).getSelection();
if (selectedPrefab.getMinPoint().equals(selection.getSelectionMin()) && selectedPrefab.getMaxPoint().equals(selection.getSelectionMax())) {
Path savePath = getWritableSavePath(selectedPrefab, confirm);
if (!SingleplayerModule.isOwner(playerRef) && !isPathInAllowedPrefabDirectory(savePath)) {
context.sendMessage(MESSAGE_PATH_OUTSIDE_PREFABS_DIR);
return CompletableFuture.completedFuture((Object)null);
} else {
return PrefabSaver.savePrefab(playerComponent, world, savePath, selectedPrefab.getAnchorPoint(), selectedPrefab.getMinPoint(), selectedPrefab.getMaxPoint(), selectedPrefab.getPastePosition(), selectedPrefab.getOriginalFileAnchor(), prefabSaverSettings).thenAccept((success) -> {
if (success) {
selectedPrefab.setDirty(false);
}
context.sendMessage(Message.translation("server.commands.editprefab.save." + (success ? "success" : "failure")).param("name", savePath.toString()));
});
}
} else {
context.sendMessage(Message.translation("server.commands.editprefab.save.selectionMismatch"));
return CompletableFuture.completedFuture((Object)null);
}
}
} else {
PrefabEditingMetadata[] values = (PrefabEditingMetadata[])prefabEditSession.getLoadedPrefabMetadata().values().toArray(new PrefabEditingMetadata[0]);
int readOnlyCount = 0;
for(PrefabEditingMetadata value : values) {
if (value.isReadOnly()) {
++readOnlyCount;
}
}
if (readOnlyCount > 0 && !confirm) {
context.sendMessage(Message.translation("server.commands.editprefab.save.readOnlyNeedsConfirm").param("count", readOnlyCount));
return CompletableFuture.completedFuture((Object)null);
} else {
if (!SingleplayerModule.isOwner(playerRef)) {
for(PrefabEditingMetadata value : values) {
Path savePath = getWritableSavePath(value, confirm);
if (!isPathInAllowedPrefabDirectory(savePath)) {
context.sendMessage(MESSAGE_PATH_OUTSIDE_PREFABS_DIR);
return CompletableFuture.completedFuture((Object)null);
}
}
}
context.sendMessage(Message.translation("server.commands.editprefab.save.saveAll.start").param("amount", values.length));
CompletableFuture<Boolean>[] prefabSavingFutures = new CompletableFuture[values.length];
for(int i = 0; i < values.length; ++i) {
PrefabEditingMetadata value = values[i];
Path savePath = getWritableSavePath(value, confirm);
prefabSavingFutures[i] = PrefabSaver.savePrefab(playerComponent, world, savePath, value.getAnchorPoint(), value.getMinPoint(), value.getMaxPoint(), value.getPastePosition(), value.getOriginalFileAnchor(), prefabSaverSettings);
}
return CompletableFuture.allOf(prefabSavingFutures).thenAccept((unused) -> {
List<Integer> failedPrefabFutures = new IntArrayList();
for(int i1 = 0; i1 < prefabSavingFutures.length; ++i1) {
if ((Boolean)prefabSavingFutures[i1].join()) {
values[i1].setDirty(false);
} else {
failedPrefabFutures.add(i1);
}
}
context.sendMessage(Message.translation("server.commands.editprefab.save.saveAll.success").param("successes", prefabSavingFutures.length - failedPrefabFutures.size()).param("failures", failedPrefabFutures.size()));
});
}
}
}
}
@Nonnull
private static Path getWritableSavePath(@Nonnull PrefabEditingMetadata metadata, boolean confirm) {
if (metadata.isReadOnly() && confirm) {
Path originalPath = metadata.getPrefabPath();
String fileName = originalPath.getFileName().toString();
Path parent = originalPath.getParent();
if (parent != null && parent.getFileName() != null) {
String parentName = parent.getFileName().toString();
return PrefabStore.get().getServerPrefabsPath().resolve(parentName).resolve(fileName);
} else {
return PrefabStore.get().getServerPrefabsPath().resolve(fileName);
}
} else {
return metadata.getPrefabPath();
}
}
}