391 lines
12 KiB
Java
391 lines
12 KiB
Java
package net.minecraft.client.resources.server;
|
|
|
|
import com.google.common.hash.HashCode;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URL;
|
|
import java.nio.file.Path;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.UUID;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.server.packs.DownloadQueue;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class ServerPackManager {
|
|
private final PackDownloader downloader;
|
|
final PackLoadFeedback packLoadFeedback;
|
|
private final PackReloadConfig reloadConfig;
|
|
private final Runnable updateRequest;
|
|
private ServerPackManager.PackPromptStatus packPromptStatus;
|
|
final List<ServerPackManager.ServerPackData> packs = new ArrayList();
|
|
|
|
public ServerPackManager(
|
|
PackDownloader downloader,
|
|
PackLoadFeedback packLoadFeedback,
|
|
PackReloadConfig reloadConfig,
|
|
Runnable updateRequest,
|
|
ServerPackManager.PackPromptStatus packPromptStatus
|
|
) {
|
|
this.downloader = downloader;
|
|
this.packLoadFeedback = packLoadFeedback;
|
|
this.reloadConfig = reloadConfig;
|
|
this.updateRequest = updateRequest;
|
|
this.packPromptStatus = packPromptStatus;
|
|
}
|
|
|
|
void registerForUpdate() {
|
|
this.updateRequest.run();
|
|
}
|
|
|
|
private void markExistingPacksAsRemoved(UUID id) {
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
if (serverPackData.id.equals(id)) {
|
|
serverPackData.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.SERVER_REPLACED);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void pushPack(UUID id, URL url, @Nullable HashCode hash) {
|
|
if (this.packPromptStatus == ServerPackManager.PackPromptStatus.DECLINED) {
|
|
this.packLoadFeedback.reportFinalResult(id, PackLoadFeedback.FinalResult.DECLINED);
|
|
} else {
|
|
this.pushNewPack(id, new ServerPackManager.ServerPackData(id, url, hash));
|
|
}
|
|
}
|
|
|
|
public void pushLocalPack(UUID id, Path path) {
|
|
if (this.packPromptStatus == ServerPackManager.PackPromptStatus.DECLINED) {
|
|
this.packLoadFeedback.reportFinalResult(id, PackLoadFeedback.FinalResult.DECLINED);
|
|
} else {
|
|
URL uRL;
|
|
try {
|
|
uRL = path.toUri().toURL();
|
|
} catch (MalformedURLException var5) {
|
|
throw new IllegalStateException("Can't convert path to URL " + path, var5);
|
|
}
|
|
|
|
ServerPackManager.ServerPackData serverPackData = new ServerPackManager.ServerPackData(id, uRL, null);
|
|
serverPackData.downloadStatus = ServerPackManager.PackDownloadStatus.DONE;
|
|
serverPackData.path = path;
|
|
this.pushNewPack(id, serverPackData);
|
|
}
|
|
}
|
|
|
|
private void pushNewPack(UUID id, ServerPackManager.ServerPackData packData) {
|
|
this.markExistingPacksAsRemoved(id);
|
|
this.packs.add(packData);
|
|
if (this.packPromptStatus == ServerPackManager.PackPromptStatus.ALLOWED) {
|
|
this.acceptPack(packData);
|
|
}
|
|
|
|
this.registerForUpdate();
|
|
}
|
|
|
|
private void acceptPack(ServerPackManager.ServerPackData packData) {
|
|
this.packLoadFeedback.reportUpdate(packData.id, PackLoadFeedback.Update.ACCEPTED);
|
|
packData.promptAccepted = true;
|
|
}
|
|
|
|
@Nullable
|
|
private ServerPackManager.ServerPackData findPackInfo(UUID id) {
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
if (!serverPackData.isRemoved() && serverPackData.id.equals(id)) {
|
|
return serverPackData;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void popPack(UUID id) {
|
|
ServerPackManager.ServerPackData serverPackData = this.findPackInfo(id);
|
|
if (serverPackData != null) {
|
|
serverPackData.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.SERVER_REMOVED);
|
|
this.registerForUpdate();
|
|
}
|
|
}
|
|
|
|
public void popAll() {
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
serverPackData.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.SERVER_REMOVED);
|
|
}
|
|
|
|
this.registerForUpdate();
|
|
}
|
|
|
|
public void allowServerPacks() {
|
|
this.packPromptStatus = ServerPackManager.PackPromptStatus.ALLOWED;
|
|
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
if (!serverPackData.promptAccepted && !serverPackData.isRemoved()) {
|
|
this.acceptPack(serverPackData);
|
|
}
|
|
}
|
|
|
|
this.registerForUpdate();
|
|
}
|
|
|
|
public void rejectServerPacks() {
|
|
this.packPromptStatus = ServerPackManager.PackPromptStatus.DECLINED;
|
|
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
if (!serverPackData.promptAccepted) {
|
|
serverPackData.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.DECLINED);
|
|
}
|
|
}
|
|
|
|
this.registerForUpdate();
|
|
}
|
|
|
|
public void resetPromptStatus() {
|
|
this.packPromptStatus = ServerPackManager.PackPromptStatus.PENDING;
|
|
}
|
|
|
|
public void tick() {
|
|
boolean bl = this.updateDownloads();
|
|
if (!bl) {
|
|
this.triggerReloadIfNeeded();
|
|
}
|
|
|
|
this.cleanupRemovedPacks();
|
|
}
|
|
|
|
private void cleanupRemovedPacks() {
|
|
this.packs.removeIf(serverPackData -> {
|
|
if (serverPackData.activationStatus != ServerPackManager.ActivationStatus.INACTIVE) {
|
|
return false;
|
|
} else if (serverPackData.removalReason != null) {
|
|
PackLoadFeedback.FinalResult finalResult = serverPackData.removalReason.serverResponse;
|
|
if (finalResult != null) {
|
|
this.packLoadFeedback.reportFinalResult(serverPackData.id, finalResult);
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
private void onDownload(Collection<ServerPackManager.ServerPackData> packs, DownloadQueue.BatchResult batchResult) {
|
|
if (!batchResult.failed().isEmpty()) {
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
if (serverPackData.activationStatus != ServerPackManager.ActivationStatus.ACTIVE) {
|
|
if (batchResult.failed().contains(serverPackData.id)) {
|
|
serverPackData.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.DOWNLOAD_FAILED);
|
|
} else {
|
|
serverPackData.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.DISCARDED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (ServerPackManager.ServerPackData serverPackDatax : packs) {
|
|
Path path = (Path)batchResult.downloaded().get(serverPackDatax.id);
|
|
if (path != null) {
|
|
serverPackDatax.downloadStatus = ServerPackManager.PackDownloadStatus.DONE;
|
|
serverPackDatax.path = path;
|
|
if (!serverPackDatax.isRemoved()) {
|
|
this.packLoadFeedback.reportUpdate(serverPackDatax.id, PackLoadFeedback.Update.DOWNLOADED);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.registerForUpdate();
|
|
}
|
|
|
|
private boolean updateDownloads() {
|
|
List<ServerPackManager.ServerPackData> list = new ArrayList();
|
|
boolean bl = false;
|
|
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
if (!serverPackData.isRemoved() && serverPackData.promptAccepted) {
|
|
if (serverPackData.downloadStatus != ServerPackManager.PackDownloadStatus.DONE) {
|
|
bl = true;
|
|
}
|
|
|
|
if (serverPackData.downloadStatus == ServerPackManager.PackDownloadStatus.REQUESTED) {
|
|
serverPackData.downloadStatus = ServerPackManager.PackDownloadStatus.PENDING;
|
|
list.add(serverPackData);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!list.isEmpty()) {
|
|
Map<UUID, DownloadQueue.DownloadRequest> map = new HashMap();
|
|
|
|
for (ServerPackManager.ServerPackData serverPackData2 : list) {
|
|
map.put(serverPackData2.id, new DownloadQueue.DownloadRequest(serverPackData2.url, serverPackData2.hash));
|
|
}
|
|
|
|
this.downloader.download(map, batchResult -> this.onDownload(list, batchResult));
|
|
}
|
|
|
|
return bl;
|
|
}
|
|
|
|
private void triggerReloadIfNeeded() {
|
|
boolean bl = false;
|
|
final List<ServerPackManager.ServerPackData> list = new ArrayList();
|
|
final List<ServerPackManager.ServerPackData> list2 = new ArrayList();
|
|
|
|
for (ServerPackManager.ServerPackData serverPackData : this.packs) {
|
|
if (serverPackData.activationStatus == ServerPackManager.ActivationStatus.PENDING) {
|
|
return;
|
|
}
|
|
|
|
boolean bl2 = serverPackData.promptAccepted && serverPackData.downloadStatus == ServerPackManager.PackDownloadStatus.DONE && !serverPackData.isRemoved();
|
|
if (bl2 && serverPackData.activationStatus == ServerPackManager.ActivationStatus.INACTIVE) {
|
|
list.add(serverPackData);
|
|
bl = true;
|
|
}
|
|
|
|
if (serverPackData.activationStatus == ServerPackManager.ActivationStatus.ACTIVE) {
|
|
if (!bl2) {
|
|
bl = true;
|
|
list2.add(serverPackData);
|
|
} else {
|
|
list.add(serverPackData);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bl) {
|
|
for (ServerPackManager.ServerPackData serverPackData : list) {
|
|
if (serverPackData.activationStatus != ServerPackManager.ActivationStatus.ACTIVE) {
|
|
serverPackData.activationStatus = ServerPackManager.ActivationStatus.PENDING;
|
|
}
|
|
}
|
|
|
|
for (ServerPackManager.ServerPackData serverPackDatax : list2) {
|
|
serverPackDatax.activationStatus = ServerPackManager.ActivationStatus.PENDING;
|
|
}
|
|
|
|
this.reloadConfig.scheduleReload(new PackReloadConfig.Callbacks() {
|
|
@Override
|
|
public void onSuccess() {
|
|
for (ServerPackManager.ServerPackData serverPackDatax : list) {
|
|
serverPackDatax.activationStatus = ServerPackManager.ActivationStatus.ACTIVE;
|
|
if (serverPackDatax.removalReason == null) {
|
|
ServerPackManager.this.packLoadFeedback.reportFinalResult(serverPackDatax.id, PackLoadFeedback.FinalResult.APPLIED);
|
|
}
|
|
}
|
|
|
|
for (ServerPackManager.ServerPackData serverPackDatax : list2) {
|
|
serverPackDatax.activationStatus = ServerPackManager.ActivationStatus.INACTIVE;
|
|
}
|
|
|
|
ServerPackManager.this.registerForUpdate();
|
|
}
|
|
|
|
@Override
|
|
public void onFailure(boolean recoveryFailure) {
|
|
if (!recoveryFailure) {
|
|
list.clear();
|
|
|
|
for (ServerPackManager.ServerPackData serverPackDatax : ServerPackManager.this.packs) {
|
|
switch (serverPackDatax.activationStatus) {
|
|
case INACTIVE:
|
|
serverPackDatax.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.DISCARDED);
|
|
break;
|
|
case PENDING:
|
|
serverPackDatax.activationStatus = ServerPackManager.ActivationStatus.INACTIVE;
|
|
serverPackDatax.setRemovalReasonIfNotSet(ServerPackManager.RemovalReason.ACTIVATION_FAILED);
|
|
break;
|
|
case ACTIVE:
|
|
list.add(serverPackDatax);
|
|
}
|
|
}
|
|
|
|
ServerPackManager.this.registerForUpdate();
|
|
} else {
|
|
for (ServerPackManager.ServerPackData serverPackDatax : ServerPackManager.this.packs) {
|
|
if (serverPackDatax.activationStatus == ServerPackManager.ActivationStatus.PENDING) {
|
|
serverPackDatax.activationStatus = ServerPackManager.ActivationStatus.INACTIVE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public List<PackReloadConfig.IdAndPath> packsToLoad() {
|
|
return list.stream().map(serverPackDatax -> new PackReloadConfig.IdAndPath(serverPackDatax.id, serverPackDatax.path)).toList();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static enum ActivationStatus {
|
|
INACTIVE,
|
|
PENDING,
|
|
ACTIVE;
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static enum PackDownloadStatus {
|
|
REQUESTED,
|
|
PENDING,
|
|
DONE;
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public static enum PackPromptStatus {
|
|
PENDING,
|
|
ALLOWED,
|
|
DECLINED;
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static enum RemovalReason {
|
|
DOWNLOAD_FAILED(PackLoadFeedback.FinalResult.DOWNLOAD_FAILED),
|
|
ACTIVATION_FAILED(PackLoadFeedback.FinalResult.ACTIVATION_FAILED),
|
|
DECLINED(PackLoadFeedback.FinalResult.DECLINED),
|
|
DISCARDED(PackLoadFeedback.FinalResult.DISCARDED),
|
|
SERVER_REMOVED(null),
|
|
SERVER_REPLACED(null);
|
|
|
|
@Nullable
|
|
final PackLoadFeedback.FinalResult serverResponse;
|
|
|
|
private RemovalReason(@Nullable final PackLoadFeedback.FinalResult serverResponse) {
|
|
this.serverResponse = serverResponse;
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
static class ServerPackData {
|
|
final UUID id;
|
|
final URL url;
|
|
@Nullable
|
|
final HashCode hash;
|
|
@Nullable
|
|
Path path;
|
|
@Nullable
|
|
ServerPackManager.RemovalReason removalReason;
|
|
ServerPackManager.PackDownloadStatus downloadStatus = ServerPackManager.PackDownloadStatus.REQUESTED;
|
|
ServerPackManager.ActivationStatus activationStatus = ServerPackManager.ActivationStatus.INACTIVE;
|
|
boolean promptAccepted;
|
|
|
|
ServerPackData(UUID id, URL url, @Nullable HashCode hash) {
|
|
this.id = id;
|
|
this.url = url;
|
|
this.hash = hash;
|
|
}
|
|
|
|
public void setRemovalReasonIfNotSet(ServerPackManager.RemovalReason removalReason) {
|
|
if (this.removalReason == null) {
|
|
this.removalReason = removalReason;
|
|
}
|
|
}
|
|
|
|
public boolean isRemoved() {
|
|
return this.removalReason != null;
|
|
}
|
|
}
|
|
}
|