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;
 | |
| 		}
 | |
| 	}
 | |
| }
 |