Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 7 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@

<p align="center">
<img src="https://meteorclient.com/icon.png" alt="meteor-client-logo" width="15%"/>
<img src="https://meteorclient.com/icon.png" alt="krypto-client-logo" width="15%"/>
</p>

<h1 align="center">Meteor</h1>
<p align="center">A Minecraft Fabric Utility Mod for anarchy servers.</p>

<div align="center">
<a href="https://discord.gg/bBGQZvd"><img src="https://img.shields.io/discord/689197705683140636?logo=discord" alt="Discord"/></a>
<br>
<img src="https://img.shields.io/github/last-commit/MeteorDevelopment/meteor-client" alt="GitHub last commit"/>
<img src="https://img.shields.io/github/commit-activity/w/MeteorDevelopment/meteor-client" alt="GitHub commit activity"/>
<img src="https://img.shields.io/github/contributors/MeteorDevelopment/meteor-client" alt="GitHub contributors"/>
<br>
<img src="https://img.shields.io/github/languages/code-size/MeteorDevelopment/meteor-client" alt="GitHub code size in bytes"/>
<img src="https://img.shields.io/endpoint?url=https://ghloc.vercel.app/api/MeteorDevelopment/meteor-client/badge?filter=.java$&label=lines%20of%20code&color=blue" alt="GitHub lines of code"/>
</div>
<h1 align="center">Krypto</h1>
<p align="center">A upstream fork of Meteor Client, A Minecraft Fabric Utility Mod for anarchy servers.</p>

## Usage

Expand All @@ -36,15 +24,9 @@ We will review and help with all reasonable pull requests as long as the guideli
- If you need help, check out the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html) for a reference.

## Bugs and Suggestions
Bug reports and suggestions should be made in this repo's [issue tracker](https://github.com/MeteorDevelopment/meteor-client/issues) using the templates provided.
Bug reports and suggestions should be made in this repo's [issue tracker](https://github.com/casefir/krypto-client/issues) using the templates provided.
Please provide as much information as you can to best help us understand your issue and give a better chance of it being resolved.

## Donations
All of our work is completely free and non-profit (donations pay only for hosting costs), therefore we are very grateful for all donations made to support us in running our community.
Donations can be made via our [website](https://meteorclient.com/donate) and the minimum amount to get donor benefits is €5.
You will be rewarded with a role on our Discord server and a customisable in-game cape.
⚠️ _Make sure to create a Meteor account and link your Discord and Minecraft accounts to fully experience your rewards._ ⚠️

## Credits
[Cabaletta](https://github.com/cabaletta) and [WagYourTail](https://github.com/wagyourtail) for [Baritone](https://github.com/cabaletta/baritone)
The [Fabric Team](https://github.com/FabricMC) for [Fabric](https://github.com/FabricMC/fabric-loader) and [Yarn](https://github.com/FabricMC/yarn)
Expand All @@ -53,8 +35,8 @@ The [Fabric Team](https://github.com/FabricMC) for [Fabric](https://github.com/F
This project is licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).

If you use **ANY** code from the source:
- You must disclose the source code of your modified work and the source code you took from this project. This means you are not allowed to use code from this project (even partially) in a closed-source and/or obfuscated application.
- You must disclose the source code of your modified work and the source code you took from this project. This means you are not allowed to use code from this project (even partially) in a closed-source application.
- You must state clearly and obviously to all end users that you are using code from this project.
- Your application must also be licensed under the same license.
- Your application must also be licensed under the same license. [METOR CLIENT](https://github.com/MetorDevelopment/)

*If you have any other questions, check our [FAQ](https://meteorclient.com/faq) or ask in our [Discord](https://meteorclient.com/discord) server.*
*If you have any other questions, check our [FAQ](https://meteorclient.com/faq)*
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static void init() {
add(new BindsCommand());
add(new GiveCommand());
add(new NameHistoryCommand());
add(new PlayerHistoryCommand());
add(new BindCommand());
add(new FovCommand());
add(new RotationCommand());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.commands.commands;

import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import meteordevelopment.meteorclient.commands.Command;
import meteordevelopment.meteorclient.systems.playerhistory.PlayerHistory;
import net.minecraft.client.multiplayer.ClientSuggestionProvider;

import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class PlayerHistoryCommand extends Command {
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());

public PlayerHistoryCommand() {
super("player-history", "Searches your locally saved player sightings.", "phistory");
}

@Override
public void build(LiteralArgumentBuilder<ClientSuggestionProvider> builder) {
builder.then(literal("search")
.then(argument("player", StringArgumentType.word()).executes(context -> {
String query = StringArgumentType.getString(context, "player");
var results = PlayerHistory.get().search(query);

if (results.isEmpty()) {
info("No saved sightings found for %s.", query);
return SINGLE_SUCCESS;
}

info("--- Player sightings for %s (latest %d) ---", query, results.size());
for (PlayerHistory.Sighting sighting : results) {
info("%s: %s at %d, %d, %d in %s; gear: %s",
sighting.name,
DATE_FORMAT.format(Instant.ofEpochMilli(sighting.timestamp)),
sighting.x, sighting.y, sighting.z,
sighting.dimension,
sighting.gear
);
}
return SINGLE_SUCCESS;
}))
);

builder.then(literal("list").executes(_ -> {
info("Player history contains %d sightings. Search with %s search <player>.", PlayerHistory.get().size(), this);
return SINGLE_SUCCESS;
}));

builder.then(literal("clear").executes(_ -> {
PlayerHistory.get().clear();
info("Cleared player history for this server.");
return SINGLE_SUCCESS;
}));

builder.executes(_ -> {
info("Use %s search <player>, %s list, or %s clear.", this, this, this);
return SINGLE_SUCCESS;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import meteordevelopment.meteorclient.systems.hud.Hud;
import meteordevelopment.meteorclient.systems.macros.Macros;
import meteordevelopment.meteorclient.systems.modules.Modules;
import meteordevelopment.meteorclient.systems.playerhistory.PlayerHistory;
import meteordevelopment.meteorclient.systems.profiles.Profiles;
import meteordevelopment.meteorclient.systems.proxies.Proxies;
import meteordevelopment.meteorclient.systems.waypoints.Waypoints;
Expand Down Expand Up @@ -49,6 +50,7 @@ public static void init() {
add(new Friends());
add(new Accounts());
add(new Waypoints());
add(new PlayerHistory());
add(new Profiles());
add(new Proxies());
add(new Hud());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ private void initMisc() {
add(new Notifier());
add(new PacketCanceller());
add(new PacketLogger());
add(new PlayerLoadNotifier());
add(new ServerSpoof());
add(new SoundBlocker());
add(new Spam());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.systems.modules.misc;

import meteordevelopment.meteorclient.events.entity.EntityAddedEvent;
import meteordevelopment.meteorclient.systems.modules.Categories;
import meteordevelopment.meteorclient.systems.modules.Module;
import meteordevelopment.orbit.EventHandler;
import net.minecraft.world.entity.player.Player;

public class PlayerLoadNotifier extends Module {
public PlayerLoadNotifier() {
super(Categories.Misc, "player-load-notifier", "Notifies you when another player loads into your client world.");
}

@EventHandler
private void onEntityAdded(EntityAddedEvent event) {
if (!(event.entity instanceof Player player) || mc.player == null || player == mc.player) return;

info("%s loaded.", player.getName().getString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.systems.playerhistory;

import meteordevelopment.meteorclient.MeteorClient;
import meteordevelopment.meteorclient.events.entity.EntityAddedEvent;
import meteordevelopment.meteorclient.events.game.GameJoinedEvent;
import meteordevelopment.meteorclient.events.world.TickEvent;
import meteordevelopment.meteorclient.systems.System;
import meteordevelopment.meteorclient.systems.Systems;
import meteordevelopment.meteorclient.utils.Utils;
import meteordevelopment.orbit.EventHandler;
import net.minecraft.core.UUIDUtil;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;

import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;

public class PlayerHistory extends System<PlayerHistory> {
private static final long RECORD_INTERVAL_MS = 30_000;
private static final int MAX_ENTRIES = 10_000;
private static final int MAX_RESULTS = 5;

private final List<Sighting> sightings = new ArrayList<>();
private final Map<UUID, Long> lastRecorded = new HashMap<>();
private long nextPeriodicRecord;

public PlayerHistory() {
super(null);
}

public static PlayerHistory get() {
return Systems.get(PlayerHistory.class);
}

@EventHandler
private void onGameJoined(GameJoinedEvent event) {
sightings.clear();
lastRecorded.clear();
load();
nextPeriodicRecord = 0;
}

@EventHandler
private void onEntityAdded(EntityAddedEvent event) {
if (event.entity instanceof Player player) record(player);
}

@EventHandler
private void onTick(TickEvent.Post event) {
if (System.currentTimeMillis() < nextPeriodicRecord || MeteorClient.mc.level == null) return;

nextPeriodicRecord = System.currentTimeMillis() + RECORD_INTERVAL_MS;
for (Player player : MeteorClient.mc.level.players()) record(player);
}

private void record(Player player) {
if (MeteorClient.mc.player == null || MeteorClient.mc.level == null || player == MeteorClient.mc.player) return;

long now = System.currentTimeMillis();
Long previous = lastRecorded.get(player.getUUID());
if (previous != null && now - previous < RECORD_INTERVAL_MS) return;
lastRecorded.put(player.getUUID(), now);

sightings.add(new Sighting(
player.getUUID(),
player.getName().getString(),
now,
MeteorClient.mc.level.dimension().identifier().toString(),
player.getBlockX(),
player.getBlockY(),
player.getBlockZ(),
getGear(player)
));

if (sightings.size() > MAX_ENTRIES) sightings.removeFirst();
save();
}

private String getGear(Player player) {
return "head=" + itemName(player.getItemBySlot(EquipmentSlot.HEAD))
+ ", chest=" + itemName(player.getItemBySlot(EquipmentSlot.CHEST))
+ ", legs=" + itemName(player.getItemBySlot(EquipmentSlot.LEGS))
+ ", feet=" + itemName(player.getItemBySlot(EquipmentSlot.FEET))
+ ", mainhand=" + itemName(player.getMainHandItem())
+ ", offhand=" + itemName(player.getOffhandItem());
}

private String itemName(ItemStack stack) {
return stack.isEmpty() ? "empty" : stack.getHoverName().getString();
}

public List<Sighting> search(String name) {
String query = name.toLowerCase(Locale.ROOT);
return sightings.stream()
.filter(sighting -> sighting.name.toLowerCase(Locale.ROOT).contains(query))
.sorted(Comparator.comparingLong((Sighting sighting) -> sighting.timestamp).reversed())
.limit(MAX_RESULTS)
.toList();
}

public int size() {
return sightings.size();
}

public void clear() {
sightings.clear();
lastRecorded.clear();
save();
}

@Override
public File getFile() {
if (!Utils.canUpdate()) return null;
return new File(new File(MeteorClient.FOLDER, "player-history"), Utils.getFileWorldName() + ".nbt");
}

@Override
public CompoundTag toTag() {
CompoundTag tag = new CompoundTag();
ListTag list = new ListTag();
for (Sighting sighting : sightings) list.add(sighting.toTag());
tag.put("sightings", list);
return tag;
}

@Override
public PlayerHistory fromTag(CompoundTag tag) {
sightings.clear();
lastRecorded.clear();

for (Tag item : tag.getListOrEmpty("sightings")) {
if (!(item instanceof CompoundTag sightingTag)) continue;
try {
Sighting sighting = new Sighting(sightingTag);
sightings.add(sighting);
lastRecorded.merge(sighting.uuid, sighting.timestamp, Math::max);
} catch (IllegalArgumentException ignored) {
// Ignore malformed records while preserving the rest of the history.
}
}

if (sightings.size() > MAX_ENTRIES) {
sightings.subList(0, sightings.size() - MAX_ENTRIES).clear();
}
return this;
}

public static class Sighting {
public final UUID uuid;
public final String name;
public final long timestamp;
public final String dimension;
public final int x, y, z;
public final String gear;

private Sighting(UUID uuid, String name, long timestamp, String dimension, int x, int y, int z, String gear) {
this.uuid = uuid;
this.name = name;
this.timestamp = timestamp;
this.dimension = dimension;
this.x = x;
this.y = y;
this.z = z;
this.gear = gear;
}

private Sighting(CompoundTag tag) {
this.uuid = tag.read("uuid", UUIDUtil.CODEC).orElseThrow(() -> new IllegalArgumentException("Missing UUID"));
this.name = tag.getStringOr("name", "");
this.timestamp = tag.getLongOr("timestamp", 0);
this.dimension = tag.getStringOr("dimension", "unknown");
this.x = tag.getIntOr("x", 0);
this.y = tag.getIntOr("y", 0);
this.z = tag.getIntOr("z", 0);
this.gear = tag.getStringOr("gear", "unknown");
}

private CompoundTag toTag() {
CompoundTag tag = new CompoundTag();
tag.store("uuid", UUIDUtil.CODEC, uuid);
tag.putString("name", name);
tag.putLong("timestamp", timestamp);
tag.putString("dimension", dimension);
tag.putInt("x", x);
tag.putInt("y", y);
tag.putInt("z", z);
tag.putString("gear", gear);
return tag;
}
}
}