104 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.telemetry;
 | |
| 
 | |
| import com.google.common.base.Suppliers;
 | |
| import com.mojang.authlib.minecraft.TelemetrySession;
 | |
| import com.mojang.authlib.minecraft.UserApiService;
 | |
| import java.nio.file.Path;
 | |
| import java.time.Duration;
 | |
| import java.time.Instant;
 | |
| import java.util.Optional;
 | |
| import java.util.UUID;
 | |
| import java.util.concurrent.CompletableFuture;
 | |
| import java.util.concurrent.CompletionStage;
 | |
| import java.util.concurrent.Executor;
 | |
| import java.util.concurrent.Executors;
 | |
| import java.util.concurrent.atomic.AtomicInteger;
 | |
| import java.util.function.Supplier;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.SharedConstants;
 | |
| import net.minecraft.Util;
 | |
| import net.minecraft.client.Minecraft;
 | |
| import net.minecraft.client.User;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class ClientTelemetryManager implements AutoCloseable {
 | |
| 	private static final AtomicInteger THREAD_COUNT = new AtomicInteger(1);
 | |
| 	private static final Executor EXECUTOR = Executors.newSingleThreadExecutor(runnable -> {
 | |
| 		Thread thread = new Thread(runnable);
 | |
| 		thread.setName("Telemetry-Sender-#" + THREAD_COUNT.getAndIncrement());
 | |
| 		return thread;
 | |
| 	});
 | |
| 	private final Minecraft minecraft;
 | |
| 	private final UserApiService userApiService;
 | |
| 	private final TelemetryPropertyMap deviceSessionProperties;
 | |
| 	private final Path logDirectory;
 | |
| 	private final CompletableFuture<Optional<TelemetryLogManager>> logManager;
 | |
| 	private final Supplier<TelemetryEventSender> outsideSessionSender = Suppliers.memoize(this::createEventSender);
 | |
| 
 | |
| 	public ClientTelemetryManager(Minecraft minecraft, UserApiService userApiService, User user) {
 | |
| 		this.minecraft = minecraft;
 | |
| 		this.userApiService = userApiService;
 | |
| 		TelemetryPropertyMap.Builder builder = TelemetryPropertyMap.builder();
 | |
| 		user.getXuid().ifPresent(string -> builder.put(TelemetryProperty.USER_ID, string));
 | |
| 		user.getClientId().ifPresent(string -> builder.put(TelemetryProperty.CLIENT_ID, string));
 | |
| 		builder.put(TelemetryProperty.MINECRAFT_SESSION_ID, UUID.randomUUID());
 | |
| 		builder.put(TelemetryProperty.GAME_VERSION, SharedConstants.getCurrentVersion().id());
 | |
| 		builder.put(TelemetryProperty.OPERATING_SYSTEM, Util.getPlatform().telemetryName());
 | |
| 		builder.put(TelemetryProperty.PLATFORM, System.getProperty("os.name"));
 | |
| 		builder.put(TelemetryProperty.CLIENT_MODDED, Minecraft.checkModStatus().shouldReportAsModified());
 | |
| 		builder.putIfNotNull(TelemetryProperty.LAUNCHER_NAME, Minecraft.getLauncherBrand());
 | |
| 		this.deviceSessionProperties = builder.build();
 | |
| 		this.logDirectory = minecraft.gameDirectory.toPath().resolve("logs/telemetry");
 | |
| 		this.logManager = TelemetryLogManager.open(this.logDirectory);
 | |
| 	}
 | |
| 
 | |
| 	public WorldSessionTelemetryManager createWorldSessionManager(boolean newWorld, @Nullable Duration worldLoadDuration, @Nullable String minigameName) {
 | |
| 		return new WorldSessionTelemetryManager(this.createEventSender(), newWorld, worldLoadDuration, minigameName);
 | |
| 	}
 | |
| 
 | |
| 	public TelemetryEventSender getOutsideSessionSender() {
 | |
| 		return (TelemetryEventSender)this.outsideSessionSender.get();
 | |
| 	}
 | |
| 
 | |
| 	private TelemetryEventSender createEventSender() {
 | |
| 		if (!this.minecraft.allowsTelemetry()) {
 | |
| 			return TelemetryEventSender.DISABLED;
 | |
| 		} else {
 | |
| 			TelemetrySession telemetrySession = this.userApiService.newTelemetrySession(EXECUTOR);
 | |
| 			if (!telemetrySession.isEnabled()) {
 | |
| 				return TelemetryEventSender.DISABLED;
 | |
| 			} else {
 | |
| 				CompletableFuture<Optional<TelemetryEventLogger>> completableFuture = this.logManager
 | |
| 					.thenCompose(
 | |
| 						optional -> (CompletionStage)optional.map(TelemetryLogManager::openLogger).orElseGet(() -> CompletableFuture.completedFuture(Optional.empty()))
 | |
| 					);
 | |
| 				return (telemetryEventType, consumer) -> {
 | |
| 					if (!telemetryEventType.isOptIn() || Minecraft.getInstance().telemetryOptInExtra()) {
 | |
| 						TelemetryPropertyMap.Builder builder = TelemetryPropertyMap.builder();
 | |
| 						builder.putAll(this.deviceSessionProperties);
 | |
| 						builder.put(TelemetryProperty.EVENT_TIMESTAMP_UTC, Instant.now());
 | |
| 						builder.put(TelemetryProperty.OPT_IN, telemetryEventType.isOptIn());
 | |
| 						consumer.accept(builder);
 | |
| 						TelemetryEventInstance telemetryEventInstance = new TelemetryEventInstance(telemetryEventType, builder.build());
 | |
| 						completableFuture.thenAccept(optional -> {
 | |
| 							if (!optional.isEmpty()) {
 | |
| 								((TelemetryEventLogger)optional.get()).log(telemetryEventInstance);
 | |
| 								telemetryEventInstance.export(telemetrySession).send();
 | |
| 							}
 | |
| 						});
 | |
| 					}
 | |
| 				};
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public Path getLogDirectory() {
 | |
| 		return this.logDirectory;
 | |
| 	}
 | |
| 
 | |
| 	public void close() {
 | |
| 		this.logManager.thenAccept(optional -> optional.ifPresent(TelemetryLogManager::close));
 | |
| 	}
 | |
| }
 |