File size: 6,742 Bytes
d46f4a3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package net.minecraft.server.chase;

import com.google.common.base.Charsets;
import com.mojang.logging.LogUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.Socket;
import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Scanner;
import javax.annotation.Nullable;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.commands.ChaseCommand;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;

public class ChaseClient {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final int RECONNECT_INTERVAL_SECONDS = 5;
    private final String serverHost;
    private final int serverPort;
    private final MinecraftServer server;
    private volatile boolean wantsToRun;
    @Nullable
    private Socket socket;
    @Nullable
    private Thread thread;

    public ChaseClient(String p_195990_, int p_195991_, MinecraftServer p_195992_) {
        this.serverHost = p_195990_;
        this.serverPort = p_195991_;
        this.server = p_195992_;
    }

    public void start() {
        if (this.thread != null && this.thread.isAlive()) {
            LOGGER.warn("Remote control client was asked to start, but it is already running. Will ignore.");
        }

        this.wantsToRun = true;
        this.thread = new Thread(this::run, "chase-client");
        this.thread.setDaemon(true);
        this.thread.start();
    }

    public void stop() {
        this.wantsToRun = false;
        IOUtils.closeQuietly(this.socket);
        this.socket = null;
        this.thread = null;
    }

    public void run() {
        String s = this.serverHost + ":" + this.serverPort;

        while (this.wantsToRun) {
            try {
                LOGGER.info("Connecting to remote control server {}", s);
                this.socket = new Socket(this.serverHost, this.serverPort);
                LOGGER.info("Connected to remote control server! Will continuously execute the command broadcasted by that server.");

                try (BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), Charsets.US_ASCII))) {
                    while (this.wantsToRun) {
                        String s1 = bufferedreader.readLine();
                        if (s1 == null) {
                            LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", s, 5);
                            break;
                        }

                        this.handleMessage(s1);
                    }
                } catch (IOException ioexception) {
                    LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", s, 5);
                }
            } catch (IOException ioexception1) {
                LOGGER.warn("Failed to connect to remote control server {}. Will retry in {}s.", s, 5);
            }

            if (this.wantsToRun) {
                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException interruptedexception) {
                }
            }
        }
    }

    private void handleMessage(String p_195995_) {
        try (Scanner scanner = new Scanner(new StringReader(p_195995_))) {
            scanner.useLocale(Locale.ROOT);
            String s = scanner.next();
            if ("t".equals(s)) {
                this.handleTeleport(scanner);
            } else {
                LOGGER.warn("Unknown message type '{}'", s);
            }
        } catch (NoSuchElementException nosuchelementexception) {
            LOGGER.warn("Could not parse message '{}', ignoring", p_195995_);
        }
    }

    private void handleTeleport(Scanner p_195997_) {
        this.parseTarget(p_195997_)
            .ifPresent(
                p_195999_ -> this.executeCommand(
                        String.format(
                            Locale.ROOT,
                            "execute in %s run tp @s %.3f %.3f %.3f %.3f %.3f",
                            p_195999_.level.location(),
                            p_195999_.pos.x,
                            p_195999_.pos.y,
                            p_195999_.pos.z,
                            p_195999_.rot.y,
                            p_195999_.rot.x
                        )
                    )
            );
    }

    private Optional<ChaseClient.TeleportTarget> parseTarget(Scanner p_196004_) {
        ResourceKey<Level> resourcekey = ChaseCommand.DIMENSION_NAMES.get(p_196004_.next());
        if (resourcekey == null) {
            return Optional.empty();
        } else {
            float f = p_196004_.nextFloat();
            float f1 = p_196004_.nextFloat();
            float f2 = p_196004_.nextFloat();
            float f3 = p_196004_.nextFloat();
            float f4 = p_196004_.nextFloat();
            return Optional.of(new ChaseClient.TeleportTarget(resourcekey, new Vec3((double)f, (double)f1, (double)f2), new Vec2(f4, f3)));
        }
    }

    private void executeCommand(String p_196002_) {
        this.server
            .execute(
                () -> {
                    List<ServerPlayer> list = this.server.getPlayerList().getPlayers();
                    if (!list.isEmpty()) {
                        ServerPlayer serverplayer = list.get(0);
                        ServerLevel serverlevel = this.server.overworld();
                        CommandSourceStack commandsourcestack = new CommandSourceStack(
                            serverplayer.commandSource(),
                            Vec3.atLowerCornerOf(serverlevel.getSharedSpawnPos()),
                            Vec2.ZERO,
                            serverlevel,
                            4,
                            "",
                            CommonComponents.EMPTY,
                            this.server,
                            serverplayer
                        );
                        Commands commands = this.server.getCommands();
                        commands.performPrefixedCommand(commandsourcestack, p_196002_);
                    }
                }
            );
    }

    static record TeleportTarget(ResourceKey<Level> level, Vec3 pos, Vec2 rot) {
    }
}