192 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.advancements;
 | |
| 
 | |
| import com.google.common.collect.Lists;
 | |
| import com.google.common.collect.Maps;
 | |
| import com.mojang.serialization.Codec;
 | |
| import com.mojang.serialization.codecs.RecordCodecBuilder;
 | |
| import java.time.Instant;
 | |
| import java.time.ZoneId;
 | |
| import java.time.format.DateTimeFormatter;
 | |
| import java.util.Comparator;
 | |
| import java.util.HashMap;
 | |
| import java.util.List;
 | |
| import java.util.Locale;
 | |
| import java.util.Map;
 | |
| import java.util.Objects;
 | |
| import java.util.Set;
 | |
| import java.util.Map.Entry;
 | |
| import java.util.stream.Collectors;
 | |
| import net.minecraft.Util;
 | |
| import net.minecraft.network.FriendlyByteBuf;
 | |
| import net.minecraft.network.chat.Component;
 | |
| import net.minecraft.util.ExtraCodecs;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| public class AdvancementProgress implements Comparable<AdvancementProgress> {
 | |
| 	private static final DateTimeFormatter OBTAINED_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z", Locale.ROOT);
 | |
| 	private static final Codec<Instant> OBTAINED_TIME_CODEC = ExtraCodecs.temporalCodec(OBTAINED_TIME_FORMAT)
 | |
| 		.xmap(Instant::from, instant -> instant.atZone(ZoneId.systemDefault()));
 | |
| 	private static final Codec<Map<String, CriterionProgress>> CRITERIA_CODEC = Codec.unboundedMap(Codec.STRING, OBTAINED_TIME_CODEC)
 | |
| 		.xmap(
 | |
| 			map -> Util.mapValues(map, CriterionProgress::new),
 | |
| 			map -> (Map)map.entrySet()
 | |
| 				.stream()
 | |
| 				.filter(entry -> ((CriterionProgress)entry.getValue()).isDone())
 | |
| 				.collect(Collectors.toMap(Entry::getKey, entry -> (Instant)Objects.requireNonNull(((CriterionProgress)entry.getValue()).getObtained())))
 | |
| 		);
 | |
| 	public static final Codec<AdvancementProgress> CODEC = RecordCodecBuilder.create(
 | |
| 		instance -> instance.group(
 | |
| 				CRITERIA_CODEC.optionalFieldOf("criteria", Map.of()).forGetter(advancementProgress -> advancementProgress.criteria),
 | |
| 				Codec.BOOL.fieldOf("done").orElse(true).forGetter(AdvancementProgress::isDone)
 | |
| 			)
 | |
| 			.apply(instance, (map, boolean_) -> new AdvancementProgress(new HashMap(map)))
 | |
| 	);
 | |
| 	private final Map<String, CriterionProgress> criteria;
 | |
| 	private AdvancementRequirements requirements = AdvancementRequirements.EMPTY;
 | |
| 
 | |
| 	private AdvancementProgress(Map<String, CriterionProgress> criteria) {
 | |
| 		this.criteria = criteria;
 | |
| 	}
 | |
| 
 | |
| 	public AdvancementProgress() {
 | |
| 		this.criteria = Maps.<String, CriterionProgress>newHashMap();
 | |
| 	}
 | |
| 
 | |
| 	public void update(AdvancementRequirements requirements) {
 | |
| 		Set<String> set = requirements.names();
 | |
| 		this.criteria.entrySet().removeIf(entry -> !set.contains(entry.getKey()));
 | |
| 
 | |
| 		for (String string : set) {
 | |
| 			this.criteria.putIfAbsent(string, new CriterionProgress());
 | |
| 		}
 | |
| 
 | |
| 		this.requirements = requirements;
 | |
| 	}
 | |
| 
 | |
| 	public boolean isDone() {
 | |
| 		return this.requirements.test(this::isCriterionDone);
 | |
| 	}
 | |
| 
 | |
| 	public boolean hasProgress() {
 | |
| 		for (CriterionProgress criterionProgress : this.criteria.values()) {
 | |
| 			if (criterionProgress.isDone()) {
 | |
| 				return true;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	public boolean grantProgress(String criterionName) {
 | |
| 		CriterionProgress criterionProgress = (CriterionProgress)this.criteria.get(criterionName);
 | |
| 		if (criterionProgress != null && !criterionProgress.isDone()) {
 | |
| 			criterionProgress.grant();
 | |
| 			return true;
 | |
| 		} else {
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public boolean revokeProgress(String criterionName) {
 | |
| 		CriterionProgress criterionProgress = (CriterionProgress)this.criteria.get(criterionName);
 | |
| 		if (criterionProgress != null && criterionProgress.isDone()) {
 | |
| 			criterionProgress.revoke();
 | |
| 			return true;
 | |
| 		} else {
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public String toString() {
 | |
| 		return "AdvancementProgress{criteria=" + this.criteria + ", requirements=" + this.requirements + "}";
 | |
| 	}
 | |
| 
 | |
| 	public void serializeToNetwork(FriendlyByteBuf buffer) {
 | |
| 		buffer.writeMap(this.criteria, FriendlyByteBuf::writeUtf, (friendlyByteBuf, criterionProgress) -> criterionProgress.serializeToNetwork(friendlyByteBuf));
 | |
| 	}
 | |
| 
 | |
| 	public static AdvancementProgress fromNetwork(FriendlyByteBuf buffer) {
 | |
| 		Map<String, CriterionProgress> map = buffer.readMap(FriendlyByteBuf::readUtf, CriterionProgress::fromNetwork);
 | |
| 		return new AdvancementProgress(map);
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public CriterionProgress getCriterion(String criterionName) {
 | |
| 		return (CriterionProgress)this.criteria.get(criterionName);
 | |
| 	}
 | |
| 
 | |
| 	private boolean isCriterionDone(String criterionName) {
 | |
| 		CriterionProgress criterionProgress = this.getCriterion(criterionName);
 | |
| 		return criterionProgress != null && criterionProgress.isDone();
 | |
| 	}
 | |
| 
 | |
| 	public float getPercent() {
 | |
| 		if (this.criteria.isEmpty()) {
 | |
| 			return 0.0F;
 | |
| 		} else {
 | |
| 			float f = this.requirements.size();
 | |
| 			float g = this.countCompletedRequirements();
 | |
| 			return g / f;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public Component getProgressText() {
 | |
| 		if (this.criteria.isEmpty()) {
 | |
| 			return null;
 | |
| 		} else {
 | |
| 			int i = this.requirements.size();
 | |
| 			if (i <= 1) {
 | |
| 				return null;
 | |
| 			} else {
 | |
| 				int j = this.countCompletedRequirements();
 | |
| 				return Component.translatable("advancements.progress", j, i);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private int countCompletedRequirements() {
 | |
| 		return this.requirements.count(this::isCriterionDone);
 | |
| 	}
 | |
| 
 | |
| 	public Iterable<String> getRemainingCriteria() {
 | |
| 		List<String> list = Lists.<String>newArrayList();
 | |
| 
 | |
| 		for (Entry<String, CriterionProgress> entry : this.criteria.entrySet()) {
 | |
| 			if (!((CriterionProgress)entry.getValue()).isDone()) {
 | |
| 				list.add((String)entry.getKey());
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return list;
 | |
| 	}
 | |
| 
 | |
| 	public Iterable<String> getCompletedCriteria() {
 | |
| 		List<String> list = Lists.<String>newArrayList();
 | |
| 
 | |
| 		for (Entry<String, CriterionProgress> entry : this.criteria.entrySet()) {
 | |
| 			if (((CriterionProgress)entry.getValue()).isDone()) {
 | |
| 				list.add((String)entry.getKey());
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return list;
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public Instant getFirstProgressDate() {
 | |
| 		return (Instant)this.criteria.values().stream().map(CriterionProgress::getObtained).filter(Objects::nonNull).min(Comparator.naturalOrder()).orElse(null);
 | |
| 	}
 | |
| 
 | |
| 	public int compareTo(AdvancementProgress other) {
 | |
| 		Instant instant = this.getFirstProgressDate();
 | |
| 		Instant instant2 = other.getFirstProgressDate();
 | |
| 		if (instant == null && instant2 != null) {
 | |
| 			return 1;
 | |
| 		} else if (instant != null && instant2 == null) {
 | |
| 			return -1;
 | |
| 		} else {
 | |
| 			return instant == null && instant2 == null ? 0 : instant.compareTo(instant2);
 | |
| 		}
 | |
| 	}
 | |
| }
 |