ms -> ticks

This commit is contained in:
MeexReay 2023-05-31 22:42:20 +03:00
parent 51b68dd48f
commit 7dfbbdc959
11 changed files with 245 additions and 77 deletions

View File

@ -19,7 +19,6 @@ import org.lwjgl.glfw.GLFW;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*; import java.util.*;
public class RepeatingMod implements ClientModInitializer { public class RepeatingMod implements ClientModInitializer {
@ -28,22 +27,24 @@ public class RepeatingMod implements ClientModInitializer {
public static final FabricLoader loader = FabricLoader.getInstance(); public static final FabricLoader loader = FabricLoader.getInstance();
public static RepeatingMod me; public static RepeatingMod me;
public Thread move_tick = null;
public List<RecordEvent> record = new ArrayList<>(); public List<RecordEvent> record = new ArrayList<>();
public boolean is_recording = false; public boolean is_recording = false;
public Date last_record = null; public long last_record = -1;
public TickTask move_tick = null;
public Thread replay = null; public TickTask replay_tick = null;
public boolean is_replaying = false; public boolean is_replaying = false;
public boolean loop_replay = false; public boolean loop_replay = false;
public static RecordInputEvent input_replay = null; public static RecordInputEvent input_replay = null;
public long living_ticks = 0;
public static RepeatingScreen menu; public static RepeatingScreen menu;
private static KeyBinding menu_key; private static KeyBinding menu_key;
private static KeyBinding toggle_replay_key; private static KeyBinding toggle_replay_key;
private static KeyBinding toggle_record_key; private static KeyBinding toggle_record_key;
public long record_pos_delay = 1000; public long record_pos_delay = 20;
public EasyConfig conf; public EasyConfig conf;
@ -90,6 +91,13 @@ public class RepeatingMod implements ClientModInitializer {
} }
} }
}); });
new TickTask(0,0) {
@Override
public void run() {
living_ticks++;
}
};
} }
public RecordEvent getLastRecord(String t) { public RecordEvent getLastRecord(String t) {
@ -111,31 +119,30 @@ public class RepeatingMod implements ClientModInitializer {
client.player.getHeadYaw(), client.player.getPitch())); client.player.getHeadYaw(), client.player.getPitch()));
if (record_pos_delay > 0) { if (record_pos_delay > 0) {
move_tick = new Thread(() -> { move_tick = new TickTask(
while (is_recording) { record_pos_delay,
try { record_pos_delay) {
Thread.sleep(record_pos_delay); @Override
} catch (InterruptedException e) { public void run() {
e.printStackTrace();
}
record.add(new RecordMoveEvent(client.player.getPos(), record.add(new RecordMoveEvent(client.player.getPos(),
client.player.getHeadYaw(), client.player.getPitch())); client.player.getHeadYaw(), client.player.getPitch()));
} }
}); };
move_tick.start();
} }
sendMessage(Text.translatable("message.repeating-mod.record_start")); sendMessage(Text.translatable("message.repeating-mod.record_start"));
} }
public void recordTick(RecordEvent e) { public void recordTick(RecordEvent e) {
Date now = new Date(); if (is_recording) {
if (last_record != null) { long now = living_ticks;
long diff = now.getTime() - last_record.getTime(); if (last_record != -1) {
if (diff >= 0) record.add(new RecordDelayEvent(diff)); long diff = now - last_record - 2;
if (diff > 0) record.add(new RecordDelayEvent(diff));
}
record.add(e);
last_record = now;
} }
record.add(e);
last_record = now;
} }
public void recordAllInput() { public void recordAllInput() {
@ -219,9 +226,12 @@ public class RepeatingMod implements ClientModInitializer {
public void stopRecording() { public void stopRecording() {
is_recording = false; is_recording = false;
move_tick = null; if (move_tick != null) {
move_tick.cancel();
move_tick = null;
}
menu.update_btns(); menu.update_btns();
last_record = null; last_record = -1;
sendMessage(Text.translatable("message.repeating-mod.record_stop")); sendMessage(Text.translatable("message.repeating-mod.record_stop"));
} }
@ -230,25 +240,41 @@ public class RepeatingMod implements ClientModInitializer {
is_recording = false; is_recording = false;
is_replaying = true; is_replaying = true;
menu.update_btns(); menu.update_btns();
replay = new Thread(() -> { replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_TAIL) {
while (true) { public int replay_index = 0;
for (RecordEvent e : record) {
if (is_replaying) { @Override
e.callback(); public void run() {
} if (!is_replaying) cancel();
RecordEvent e = record.get(replay_index);
if (e instanceof RecordDelayEvent) {
setDelay(((RecordDelayEvent) e).delay);
} else {
e.callback();
}
replay_index++;
if (!loop_replay) {
if (replay_index == record.size()) {
stopReplay();
cancel();
}
} else if (replay_index == record.size()) {
replay_index = 0;
} }
if (!loop_replay || !is_replaying) break;
} }
stopReplay(); };
});
replay.start();
sendMessage(Text.translatable("message.repeating-mod.replay_start")); sendMessage(Text.translatable("message.repeating-mod.replay_start"));
} }
public void stopReplay() { public void stopReplay() {
is_recording = false; is_recording = false;
is_replaying = false; is_replaying = false;
replay = null; if (replay_tick != null) {
replay_tick.cancel();
replay_tick = null;
}
menu.update_btns(); menu.update_btns();
sendMessage(Text.translatable("message.repeating-mod.replay_stop")); sendMessage(Text.translatable("message.repeating-mod.replay_stop"));
} }
@ -265,6 +291,10 @@ public class RepeatingMod implements ClientModInitializer {
.append("] ").append(text)); .append("] ").append(text));
} }
public static void sendDebug(String s) {
client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s)));
}
public static abstract class RecordEvent { public static abstract class RecordEvent {
abstract void callback(); abstract void callback();
abstract String toText(); abstract String toText();
@ -305,7 +335,7 @@ public class RepeatingMod implements ClientModInitializer {
public void callback() { public void callback() {
try { try {
Thread.sleep(delay); Thread.sleep(delay/20*1000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -169,7 +169,7 @@ public class RepeatingScreen extends BaseOwoScreen<FlowLayout> {
.horizontalAlignment(HorizontalAlignment.CENTER) .horizontalAlignment(HorizontalAlignment.CENTER)
.margins(Insets.of(1))) .margins(Insets.of(1)))
.child(Containers.verticalFlow(Sizing.content(), Sizing.content()) .child(Containers.verticalFlow(Sizing.content(), Sizing.content())
.child(Components.discreteSlider(Sizing.fixed(120),-24,5000) .child(Components.discreteSlider(Sizing.fixed(120),-20,100)
.setFromDiscreteValue(mod.record_pos_delay) .setFromDiscreteValue(mod.record_pos_delay)
.message((String s)->{ .message((String s)->{
mod.record_pos_delay = Long.parseLong(s); mod.record_pos_delay = Long.parseLong(s);
@ -177,7 +177,7 @@ public class RepeatingScreen extends BaseOwoScreen<FlowLayout> {
mod.conf.save(); mod.conf.save();
if (mod.record_pos_delay > -1) if (mod.record_pos_delay > -1)
return Text.translatable("text.repeating-mod.pos_delay", s); return Text.translatable("text.repeating-mod.pos_delay", s);
return Text.translatable("text.repeating-mod.nan_pos_delay", s); return Text.translatable("text.repeating-mod.nan_pos_delay");
}).scrollStep(25) }).scrollStep(25)
.margins(Insets.of(1)) .margins(Insets.of(1))
.tooltip(Text.translatable("text.repeating-mod.pos_delay_text"))) .tooltip(Text.translatable("text.repeating-mod.pos_delay_text")))

View File

@ -0,0 +1,94 @@
package themixray.repeating.mod;
import java.util.ArrayList;
import java.util.List;
public abstract class TickTask implements Runnable {
public static List<TickTask> tasks = new ArrayList<>();
public static void tickTasks(TickAt at) {
for (TickTask t:new ArrayList<>(tasks))
if (t.getAt() == at) t.tick();
}
private long living;
private long delay;
private boolean is_repeating;
private long period;
private boolean is_cancelled;
private TickAt at;
public enum TickAt {
CLIENT_HEAD, CLIENT_TAIL,
MOVEMENT_HEAD, MOVEMENT_TAIL,
RENDER_HEAD, RENDER_TAIL
}
public TickTask(long delay, TickAt at) {
this.is_cancelled = false;
this.is_repeating = false;
this.delay = delay;
this.living = 0;
this.period = 0;
this.at = at;
tasks.add(this);
}
public TickTask(long delay, long period, TickAt at) {
this.is_cancelled = false;
this.is_repeating = true;
this.delay = delay;
this.period = period;
this.living = 0;
this.at = at;
tasks.add(this);
}
public TickTask(long delay) {
this(delay,TickAt.CLIENT_HEAD);
}
public TickTask(long delay, long period) {
this(delay,period,TickAt.CLIENT_HEAD);
}
public void cancel() {
if (!is_cancelled) {
is_cancelled = true;
tasks.remove(this);
}
}
public boolean isCancelled() {
return is_cancelled;
}
public TickAt getAt() {
return at;
}
public void setDelay(long delay) {
if (is_repeating) {
this.delay = delay;
}
}
public long getDelay() {
return this.delay;
}
public void tick() {
if (living >= delay) {
if (is_repeating) {
delay = period;
run();
living = -1;
} else {
run();
cancel();
}
}
living++;
}
}

View File

@ -0,0 +1,24 @@
package themixray.repeating.mod.mixin;
import net.minecraft.client.MinecraftClient;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import themixray.repeating.mod.RepeatingMod;
import themixray.repeating.mod.TickTask;
@Mixin(MinecraftClient.class)
public abstract class ClientMixin {
@Inject(at = @At(value = "HEAD"), method = "tick")
private void onTickHead(CallbackInfo ci) {
if (RepeatingMod.me.is_recording)
RepeatingMod.me.recordAllInput();
TickTask.tickTasks(TickTask.TickAt.CLIENT_HEAD);
}
@Inject(at = @At(value = "TAIL"), method = "tick")
private void onTickTail(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.CLIENT_TAIL);
}
}

View File

@ -0,0 +1,36 @@
package themixray.repeating.mod.mixin;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.hit.HitResult;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import themixray.repeating.mod.RepeatingMod;
import themixray.repeating.mod.TickTask;
import java.util.UUID;
@Mixin(Entity.class)
public abstract class EntityMixin {
@Shadow public abstract UUID getUuid();
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
private void onSprint(boolean sprinting,CallbackInfo ci) {
if (getUuid().equals(RepeatingMod.client.player.getUuid())) {
if (RepeatingMod.me.is_replaying) {
if (RepeatingMod.input_replay != null &&
RepeatingMod.input_replay.sprinting != null &&
RepeatingMod.input_replay.sprinting != sprinting) {
ci.cancel();
return;
}
}
}
}
}

View File

@ -12,6 +12,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import themixray.repeating.mod.RepeatingMod; import themixray.repeating.mod.RepeatingMod;
import themixray.repeating.mod.TickTask; import themixray.repeating.mod.TickTask;
import java.util.ArrayList;
@Mixin(ClientPlayerEntity.class) @Mixin(ClientPlayerEntity.class)
public abstract class MovementMixin { public abstract class MovementMixin {
@ -30,36 +32,13 @@ public abstract class MovementMixin {
}); });
} }
@Inject(at = @At(value = "HEAD"), method = "tick") @Inject(at = @At(value = "HEAD"), method = "tickMovement")
private void onTickHead(CallbackInfo ci) { private void onMoveHead(CallbackInfo ci) {
for (TickTask t:TickTask.ticks) TickTask.tickTasks(TickTask.TickAt.MOVEMENT_HEAD);
if (t.getAt() == TickTask.TickAt.HEAD)
t.tick();
} }
@Inject(at = @At(value = "TAIL"), method = "tick") @Inject(at = @At(value = "TAIL"), method = "tick")
private void onTickTail(CallbackInfo ci) { private void onMoveTail(CallbackInfo ci) {
for (TickTask t:TickTask.ticks) TickTask.tickTasks(TickTask.TickAt.MOVEMENT_TAIL);
if (t.getAt() == TickTask.TickAt.TAIL)
t.tick();
}
@Inject(at = @At(value = "HEAD"), method = "tickMovement")
private void onMove(CallbackInfo ci) {
if (RepeatingMod.me.is_recording) {
RepeatingMod.me.recordAllInput();
}
}
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
private void onSprint(boolean sprinting,CallbackInfo ci) {
if (RepeatingMod.me.is_replaying) {
if (RepeatingMod.input_replay != null &&
RepeatingMod.input_replay.sprinting != null &&
RepeatingMod.input_replay.sprinting != sprinting) {
ci.cancel();
return;
}
}
} }
} }

View File

@ -7,15 +7,17 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import themixray.repeating.mod.RepeatingMod; import themixray.repeating.mod.RepeatingMod;
import themixray.repeating.mod.TickTask;
@Mixin(GameRenderer.class) @Mixin(GameRenderer.class)
public abstract class RendererMixin { public abstract class RendererMixin {
@Inject(at = @At(value = "HEAD"), method = "tick")
private void onTickHead(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.RENDER_HEAD);
}
@Inject(at = @At(value = "TAIL"), method = "tick") @Inject(at = @At(value = "TAIL"), method = "tick")
private void onTickTail(CallbackInfo ci) { private void onTickTail(CallbackInfo ci) {
if (RepeatingMod.me.is_replaying) { TickTask.tickTasks(TickTask.TickAt.RENDER_TAIL);
if (RepeatingMod.input_replay != null) {
RepeatingMod.me.recordCameraInput();
}
}
} }
} }

View File

@ -14,9 +14,9 @@
"text.repeating-mod.parkour": "Parkour mode", "text.repeating-mod.parkour": "Parkour mode",
"text.repeating-mod.settings": "Settings", "text.repeating-mod.settings": "Settings",
"text.repeating-mod.dev": "In development...", "text.repeating-mod.dev": "In development...",
"text.repeating-mod.nan_pos_delay": "No pos delay", "text.repeating-mod.nan_pos_delay": "No pos timer",
"text.repeating-mod.pos_delay": "Pos delay: %s ms", "text.repeating-mod.pos_delay": "Pos timer: %s ticks",
"text.repeating-mod.pos_delay_text": "Delay after which the pos event is added", "text.repeating-mod.pos_delay_text": "Timer after which the pos\nevent is added (20 ticks = 1 sec)",
"message.repeating-mod.replay_start": "Replay started", "message.repeating-mod.replay_start": "Replay started",
"message.repeating-mod.replay_stop": "Replay finished", "message.repeating-mod.replay_stop": "Replay finished",

View File

@ -14,9 +14,9 @@
"text.repeating-mod.parkour": "Режим паркура", "text.repeating-mod.parkour": "Режим паркура",
"text.repeating-mod.settings": "Настройки", "text.repeating-mod.settings": "Настройки",
"text.repeating-mod.dev": "В разработке...", "text.repeating-mod.dev": "В разработке...",
"text.repeating-mod.nan_pos_delay": "Задержки позиции нету", "text.repeating-mod.nan_pos_delay": "Таймера позиции нету",
"text.repeating-mod.pos_delay": "Задержка позиции: %s мс", "text.repeating-mod.pos_delay": "Таймер позиции: %s тиков",
"text.repeating-mod.pos_delay_text": "Задержка, после которой добавляется ивент позиции", "text.repeating-mod.pos_delay_text": "Таймер, после которой добавляется\nивент позиции (20 тиков = 1 сек)",
"message.repeating-mod.replay_start": "Повтор начат", "message.repeating-mod.replay_start": "Повтор начат",
"message.repeating-mod.replay_stop": "Повтор закончен", "message.repeating-mod.replay_stop": "Повтор закончен",

View File

@ -29,7 +29,7 @@
"depends": { "depends": {
"fabricloader": ">=0.14.14", "fabricloader": ">=0.14.14",
"fabric-api": "*", "fabric-api": "*",
"minecraft": "~1.19.3", "minecraft": "1.19.x",
"java": ">=17" "java": ">=17"
}, },
"suggests": { "suggests": {

View File

@ -7,7 +7,10 @@
], ],
"client": [ "client": [
"MovementMixin", "MovementMixin",
"InputMixin" "InputMixin",
"RendererMixin",
"EntityMixin",
"ClientMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1