mega update
This commit is contained in:
parent
ed627ca2f6
commit
94549c51e0
40
.github/workflows/build.yml
vendored
40
.github/workflows/build.yml
vendored
@ -1,40 +0,0 @@
|
|||||||
# Automatically build the project and run any configured tests for every push
|
|
||||||
# and submitted pull request. This can help catch issues that only occur on
|
|
||||||
# certain platforms or Java versions, and provides a first line of defence
|
|
||||||
# against bad commits.
|
|
||||||
|
|
||||||
name: build
|
|
||||||
on: [pull_request, push]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
# Use these Java versions
|
|
||||||
java: [
|
|
||||||
17, # Current Java LTS & minimum supported by Minecraft
|
|
||||||
]
|
|
||||||
# and run on both Linux and Windows
|
|
||||||
os: [ubuntu-22.04, windows-2022]
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
steps:
|
|
||||||
- name: checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
- name: validate gradle wrapper
|
|
||||||
uses: gradle/wrapper-validation-action@v1
|
|
||||||
- name: setup jdk ${{ matrix.java }}
|
|
||||||
uses: actions/setup-java@v3
|
|
||||||
with:
|
|
||||||
java-version: ${{ matrix.java }}
|
|
||||||
distribution: 'microsoft'
|
|
||||||
- name: make gradle wrapper executable
|
|
||||||
if: ${{ runner.os != 'Windows' }}
|
|
||||||
run: chmod +x ./gradlew
|
|
||||||
- name: build
|
|
||||||
run: ./gradlew build
|
|
||||||
- name: capture build artifacts
|
|
||||||
if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: Artifacts
|
|
||||||
path: build/libs/
|
|
40
.gitignore
vendored
40
.gitignore
vendored
@ -1,40 +0,0 @@
|
|||||||
# gradle
|
|
||||||
|
|
||||||
.gradle/
|
|
||||||
build/
|
|
||||||
out/
|
|
||||||
classes/
|
|
||||||
|
|
||||||
# eclipse
|
|
||||||
|
|
||||||
*.launch
|
|
||||||
|
|
||||||
# idea
|
|
||||||
|
|
||||||
.idea/
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
*.iws
|
|
||||||
|
|
||||||
# vscode
|
|
||||||
|
|
||||||
.settings/
|
|
||||||
.vscode/
|
|
||||||
bin/
|
|
||||||
.classpath
|
|
||||||
.project
|
|
||||||
|
|
||||||
# macos
|
|
||||||
|
|
||||||
*.DS_Store
|
|
||||||
|
|
||||||
# fabric
|
|
||||||
|
|
||||||
run/
|
|
||||||
|
|
||||||
# java
|
|
||||||
|
|
||||||
hs_err_*.log
|
|
||||||
replay_*.log
|
|
||||||
*.hprof
|
|
||||||
*.jfr
|
|
11
build.gradle
11
build.gradle
@ -12,6 +12,7 @@ repositories {
|
|||||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
// for more information about repositories.
|
// for more information about repositories.
|
||||||
|
maven { url 'https://maven.wispforest.io' }
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -27,6 +28,16 @@ dependencies {
|
|||||||
// These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time.
|
// These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time.
|
||||||
|
|
||||||
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
||||||
|
|
||||||
|
modImplementation "io.wispforest:owo-lib:${project.owo_version}"
|
||||||
|
// only if you plan to use owo-config
|
||||||
|
annotationProcessor "io.wispforest:owo-lib:${project.owo_version}"
|
||||||
|
|
||||||
|
// include this if you don't want force your users to install owo
|
||||||
|
// sentinel will warn them and give the option to download it automatically
|
||||||
|
include "io.wispforest:owo-sentinel:${project.owo_version}"
|
||||||
|
// https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple
|
||||||
|
implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
base {
|
base {
|
||||||
|
@ -4,14 +4,16 @@ org.gradle.parallel=true
|
|||||||
|
|
||||||
# Fabric Properties
|
# Fabric Properties
|
||||||
# check these on https://fabricmc.net/develop
|
# check these on https://fabricmc.net/develop
|
||||||
minecraft_version=1.19.4
|
minecraft_version=1.19.3
|
||||||
yarn_mappings=1.19.4+build.1
|
yarn_mappings=1.19.3+build.1
|
||||||
loader_version=0.14.17
|
loader_version=0.14.17
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version = 1.0.0
|
mod_version = 1.0.0
|
||||||
maven_group = com.example
|
maven_group = themixray.repeating.mod
|
||||||
archives_base_name = fabric-example-mod
|
archives_base_name = repeating-mod
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
fabric_version=0.75.3+1.19.4
|
fabric_version=0.76.1+1.19.3
|
||||||
|
|
||||||
|
owo_version=0.10.3+1.19.3
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package net.fabricmc.example;
|
|
||||||
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class ExampleMod implements ModInitializer {
|
|
||||||
// This logger is used to write text to the console and the log file.
|
|
||||||
// It is considered best practice to use your mod id as the logger's name.
|
|
||||||
// That way, it's clear which mod wrote info, warnings, and errors.
|
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger("modid");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInitialize() {
|
|
||||||
// This code runs as soon as Minecraft is in a mod-load-ready state.
|
|
||||||
// However, some things (like resources) may still be uninitialized.
|
|
||||||
// Proceed with mild caution.
|
|
||||||
|
|
||||||
LOGGER.info("Hello Fabric world!");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package net.fabricmc.example.mixin;
|
|
||||||
|
|
||||||
import net.fabricmc.example.ExampleMod;
|
|
||||||
import net.minecraft.client.gui.screen.TitleScreen;
|
|
||||||
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;
|
|
||||||
|
|
||||||
@Mixin(TitleScreen.class)
|
|
||||||
public class ExampleMixin {
|
|
||||||
@Inject(at = @At("HEAD"), method = "init()V")
|
|
||||||
private void init(CallbackInfo info) {
|
|
||||||
ExampleMod.LOGGER.info("This line is printed by an example mod mixin!");
|
|
||||||
}
|
|
||||||
}
|
|
338
src/main/java/themixray/repeating/mod/RepeatingMod.java
Normal file
338
src/main/java/themixray/repeating/mod/RepeatingMod.java
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
|
||||||
|
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
|
||||||
|
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.option.KeyBinding;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.registry.Registry;
|
||||||
|
import net.minecraft.resource.Resource;
|
||||||
|
import net.minecraft.resource.ResourceManager;
|
||||||
|
import net.minecraft.resource.ResourceType;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class RepeatingMod implements ClientModInitializer {
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger("repeating-mod");
|
||||||
|
public static final MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
public static final FabricLoader loader = FabricLoader.getInstance();
|
||||||
|
public static RepeatingMod me;
|
||||||
|
|
||||||
|
public List<RecordEvent> record = new ArrayList<>();
|
||||||
|
public boolean is_recording = false;
|
||||||
|
public Date last_record = null;
|
||||||
|
|
||||||
|
public Thread replay = null;
|
||||||
|
public boolean is_replaying = false;
|
||||||
|
public boolean loop_replay = false;
|
||||||
|
public static boolean replay_sneaking = false;
|
||||||
|
|
||||||
|
public static RepeatingScreen menu;
|
||||||
|
private static KeyBinding menu_key;
|
||||||
|
private static KeyBinding toggle_replay_key;
|
||||||
|
private static KeyBinding toggle_record_key;
|
||||||
|
|
||||||
|
public double record_blocks_limit = 2;
|
||||||
|
public long record_time_limit = 50;
|
||||||
|
|
||||||
|
public EasyConfig conf;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient() {
|
||||||
|
LOGGER.info("Repeating mod initialized");
|
||||||
|
me = this;
|
||||||
|
|
||||||
|
Map<String,Object> def = new HashMap<>();
|
||||||
|
def.put("record_blocks_limit", record_blocks_limit);
|
||||||
|
def.put("record_time_limit", record_time_limit);
|
||||||
|
conf = new EasyConfig(new File(loader.getConfigDir().toFile(),"repeating-mod").toPath(),def);
|
||||||
|
|
||||||
|
record_blocks_limit = (double) conf.data.get("record_blocks_limit");
|
||||||
|
record_time_limit = (long) conf.data.get("record_time_limit");
|
||||||
|
|
||||||
|
menu_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.menu",InputUtil.Type.KEYSYM,
|
||||||
|
GLFW.GLFW_KEY_J,"text.repeating-mod.name"));
|
||||||
|
toggle_replay_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.toggle_replay",InputUtil.Type.KEYSYM,
|
||||||
|
-1,"text.repeating-mod.name"));
|
||||||
|
toggle_record_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.toggle_record",InputUtil.Type.KEYSYM,
|
||||||
|
-1,"text.repeating-mod.name"));
|
||||||
|
|
||||||
|
menu = new RepeatingScreen();
|
||||||
|
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||||
|
if (menu_key.wasPressed()) {
|
||||||
|
client.setScreen(menu);
|
||||||
|
}
|
||||||
|
if (toggle_replay_key.wasPressed()) {
|
||||||
|
if (!is_recording) {
|
||||||
|
if (is_replaying)
|
||||||
|
stopReplay();
|
||||||
|
else startReplay();
|
||||||
|
menu.update_btns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toggle_record_key.wasPressed()) {
|
||||||
|
if (!is_replaying) {
|
||||||
|
if (is_recording)
|
||||||
|
stopRecording();
|
||||||
|
else startRecording();
|
||||||
|
menu.update_btns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordEvent getLastRecord(String t) {
|
||||||
|
for (RecordEvent r:Lists.reverse(new ArrayList<>(record))) {
|
||||||
|
if (r.getType().equals(t)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void startRecording() {
|
||||||
|
is_recording = true;
|
||||||
|
menu.update_btns();
|
||||||
|
record.clear();
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.record_start"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordTick(RecordEvent e) {
|
||||||
|
Date now = new Date();
|
||||||
|
if (last_record != null) {
|
||||||
|
long diff = now.getTime() - last_record.getTime();
|
||||||
|
if (diff >= 0) record.add(new RecordDelayEvent(diff));
|
||||||
|
}
|
||||||
|
record.add(e);
|
||||||
|
last_record = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopRecording() {
|
||||||
|
is_recording = false;
|
||||||
|
menu.update_btns();
|
||||||
|
last_record = null;
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.record_stop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void startReplay() {
|
||||||
|
is_recording = false;
|
||||||
|
is_replaying = true;
|
||||||
|
menu.update_btns();
|
||||||
|
client.player.setNoGravity(true);
|
||||||
|
replay = new Thread(() -> {
|
||||||
|
while (true) {
|
||||||
|
for (RecordEvent e : record)
|
||||||
|
if (is_replaying)
|
||||||
|
e.callback();
|
||||||
|
if (!loop_replay || !is_replaying) break;
|
||||||
|
}
|
||||||
|
stopReplay();
|
||||||
|
});
|
||||||
|
replay.start();
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.replay_start"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopReplay() {
|
||||||
|
is_recording = false;
|
||||||
|
is_replaying = false;
|
||||||
|
menu.update_btns();
|
||||||
|
client.player.setNoGravity(false);
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.replay_stop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double round(double value, int places) {
|
||||||
|
if (places < 0) throw new IllegalArgumentException();
|
||||||
|
long factor = (long) Math.pow(10, places);
|
||||||
|
return (double) Math.round(value * factor) / factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendMessage(Text text) {
|
||||||
|
client.player.sendMessage(Text.literal("[")
|
||||||
|
.append(Text.translatable("text.repeating-mod.name"))
|
||||||
|
.append("] ").append(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class RecordEvent {
|
||||||
|
abstract void callback();
|
||||||
|
abstract String toText();
|
||||||
|
abstract String getType();
|
||||||
|
|
||||||
|
public static RecordEvent fromText(String t) {
|
||||||
|
try {
|
||||||
|
String type = String.valueOf(t.charAt(0));
|
||||||
|
String[] args = t.substring(2).split("&");
|
||||||
|
if (type.equals("d")) {
|
||||||
|
return new RecordDelayEvent(
|
||||||
|
Long.parseLong(args[0]));
|
||||||
|
} else if (type.equals("m")) {
|
||||||
|
return new RecordMoveEvent(new Vec3d(
|
||||||
|
Double.parseDouble(args[0]),
|
||||||
|
Double.parseDouble(args[1]),
|
||||||
|
Double.parseDouble(args[2])),
|
||||||
|
Float.parseFloat(args[3]),
|
||||||
|
Float.parseFloat(args[4]));
|
||||||
|
} else if (type.equals("s")) {
|
||||||
|
return new RecordSneakEvent(
|
||||||
|
args[0].equals("1"));
|
||||||
|
} else if (type.equals("b")) {
|
||||||
|
return new RecordBlockBreakEvent(new BlockPos(
|
||||||
|
Integer.parseInt(args[0]),
|
||||||
|
Integer.parseInt(args[1]),
|
||||||
|
Integer.parseInt(args[2])));
|
||||||
|
} else if (type.equals("i")) {
|
||||||
|
return new RecordBlockInteractEvent(
|
||||||
|
Hand.valueOf(args[5]),
|
||||||
|
new BlockHitResult(new Vec3d(
|
||||||
|
Double.parseDouble(args[0]),
|
||||||
|
Double.parseDouble(args[1]),
|
||||||
|
Double.parseDouble(args[2])),
|
||||||
|
Direction.byId(Integer.parseInt(args[4])),
|
||||||
|
new BlockPos(
|
||||||
|
Integer.parseInt(args[0]),
|
||||||
|
Integer.parseInt(args[1]),
|
||||||
|
Integer.parseInt(args[2])),
|
||||||
|
args[3].equals("1")));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordDelayEvent extends RecordEvent {
|
||||||
|
public long delay;
|
||||||
|
|
||||||
|
public RecordDelayEvent(long delay) {
|
||||||
|
this.delay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "d="+delay;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "delay";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordMoveEvent extends RecordEvent {
|
||||||
|
public Vec3d vec;
|
||||||
|
public float yaw;
|
||||||
|
public float pitch;
|
||||||
|
|
||||||
|
public RecordMoveEvent(Vec3d vec,float yaw,float pitch) {
|
||||||
|
this.vec = vec;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
Vec3d p = client.player.getPos();
|
||||||
|
Vec3d v = new Vec3d(vec.getX()-p.getX(),vec.getY()-p.getY(),vec.getZ()-p.getZ());
|
||||||
|
client.player.move(MovementType.SELF,v);
|
||||||
|
client.player.setYaw(yaw);
|
||||||
|
client.player.setPitch(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "m="+vec.getX()+"&"+vec.getY()+"&"+vec.getZ()+"&"+yaw+"&"+pitch;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "move";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordSneakEvent extends RecordEvent {
|
||||||
|
public boolean sneaking;
|
||||||
|
|
||||||
|
public RecordSneakEvent(boolean sneaking) {
|
||||||
|
this.sneaking = sneaking;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
RepeatingMod.replay_sneaking = sneaking;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "s="+(sneaking?"1":"0");
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "sneak";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordBlockBreakEvent extends RecordEvent {
|
||||||
|
public BlockPos pos;
|
||||||
|
|
||||||
|
public RecordBlockBreakEvent(
|
||||||
|
BlockPos pos) {
|
||||||
|
this.pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
client.interactionManager.breakBlock(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "b="+pos.getX()+"&"+pos.getY()+"&"+pos.getZ();
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "block_break";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordBlockInteractEvent extends RecordEvent {
|
||||||
|
public Hand hand;
|
||||||
|
public BlockHitResult hitResult;
|
||||||
|
|
||||||
|
public RecordBlockInteractEvent(Hand hand, BlockHitResult hitResult) {
|
||||||
|
this.hand = hand;
|
||||||
|
this.hitResult = hitResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
client.interactionManager.interactBlock(client.player,hand,hitResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "i="+hitResult.getBlockPos().getX()+"&"+hitResult.getBlockPos().getY()+"&"+hitResult.getBlockPos().getZ()+
|
||||||
|
"&"+(hitResult.isInsideBlock()?"1":"0")+"&"+hitResult.getSide().getId()+"&"+hand.name();
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "block_interact";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
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.MinecraftClient;
|
||||||
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.hit.HitResult;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
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 java.util.Date;
|
||||||
|
|
||||||
|
@Mixin(ClientPlayerEntity.class)
|
||||||
|
public abstract class MovementMixin {
|
||||||
|
public Vec3d lastVec = null;
|
||||||
|
@Shadow public abstract void sendMessage(Text message);
|
||||||
|
@Shadow @Final protected MinecraftClient client;
|
||||||
|
@Shadow public abstract float getYaw(float tickDelta);
|
||||||
|
@Shadow private float lastYaw;
|
||||||
|
@Shadow private float lastPitch;
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "init")
|
||||||
|
private void init(CallbackInfo ci) {
|
||||||
|
PlayerBlockBreakEvents.AFTER.register((world, player, pos, blockState, blockEntity) -> {
|
||||||
|
if (RepeatingMod.me.is_recording)
|
||||||
|
RepeatingMod.me.recordTick(new RepeatingMod.RecordBlockBreakEvent(pos));
|
||||||
|
});
|
||||||
|
|
||||||
|
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
||||||
|
if (hitResult.getType().equals(HitResult.Type.BLOCK))
|
||||||
|
if (RepeatingMod.me.is_recording)
|
||||||
|
RepeatingMod.me.recordTick(new RepeatingMod.RecordBlockInteractEvent(hand,hitResult));
|
||||||
|
return ActionResult.PASS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "move")
|
||||||
|
private void onMove(MovementType movementType, Vec3d vec, CallbackInfo ci) {
|
||||||
|
if (RepeatingMod.me.is_recording) {
|
||||||
|
if (vec != lastVec) {
|
||||||
|
double dist = 0;
|
||||||
|
if (lastVec != null)
|
||||||
|
dist = vec.distanceTo(lastVec);
|
||||||
|
if (dist > 0.0) {
|
||||||
|
Vec3d c = client.player.getPos();
|
||||||
|
|
||||||
|
RepeatingMod.RecordMoveEvent ev = new RepeatingMod.RecordMoveEvent(
|
||||||
|
new Vec3d(c.getX() + vec.getX(),
|
||||||
|
c.getY() + vec.getY(),
|
||||||
|
c.getZ() + vec.getZ()),
|
||||||
|
lastYaw, lastPitch);
|
||||||
|
|
||||||
|
boolean just_add = true;
|
||||||
|
Date now = new Date();
|
||||||
|
if (RepeatingMod.me.last_record != null) {
|
||||||
|
long diff = now.getTime() - RepeatingMod.me.last_record.getTime();
|
||||||
|
boolean add_delay = true;
|
||||||
|
if (diff > 0) {
|
||||||
|
RepeatingMod.RecordEvent last_ev = RepeatingMod.me.record.get(RepeatingMod.me.record.size()-1);
|
||||||
|
if (last_ev instanceof RepeatingMod.RecordMoveEvent) {
|
||||||
|
RepeatingMod.RecordMoveEvent last_ev1 = (RepeatingMod.RecordMoveEvent) last_ev;
|
||||||
|
if (last_ev1.vec.distanceTo(ev.vec) < RepeatingMod.me.record_blocks_limit &&
|
||||||
|
diff < RepeatingMod.me.record_time_limit) {
|
||||||
|
just_add = false;
|
||||||
|
add_delay = false;
|
||||||
|
last_ev1.vec = ev.vec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (add_delay) {
|
||||||
|
RepeatingMod.me.record.add(new RepeatingMod.RecordDelayEvent(diff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (just_add) {
|
||||||
|
RepeatingMod.me.record.add(ev);
|
||||||
|
RepeatingMod.me.last_record = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastVec = vec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 453 B |
26
src/main/resources/assets/repeating-mod/lang/en_us.json
Normal file
26
src/main/resources/assets/repeating-mod/lang/en_us.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"key.repeating-mod.menu": "Repeating menu",
|
||||||
|
"key.repeating-mod.toggle_replay": "Toggle replay",
|
||||||
|
"key.repeating-mod.toggle_record": "Toggle recording",
|
||||||
|
|
||||||
|
"text.repeating-mod.name": "Repeating Mod",
|
||||||
|
"text.repeating-mod.record": "record",
|
||||||
|
"text.repeating-mod.replay": "replay",
|
||||||
|
"text.repeating-mod.start": "Start",
|
||||||
|
"text.repeating-mod.stop": "Stop",
|
||||||
|
"text.repeating-mod.export": "Export record",
|
||||||
|
"text.repeating-mod.import": "Import record",
|
||||||
|
"text.repeating-mod.basic": "Basic mode",
|
||||||
|
"text.repeating-mod.parkour": "Parkour mode",
|
||||||
|
"text.repeating-mod.settings": "Settings",
|
||||||
|
"text.repeating-mod.dev": "In development...",
|
||||||
|
"text.repeating-mod.block_limit": "Block limit: %s",
|
||||||
|
"text.repeating-mod.block_limit_tooltip": "Two recording events will\nbe summed up if the\ndistance between them is\nless than the limit.",
|
||||||
|
"text.repeating-mod.time_limit": "Time limit: %s ms",
|
||||||
|
"text.repeating-mod.time_limit_tooltip": "Two recording events will\nbe summed up if the time\nbetween them is less than\nthe limit.",
|
||||||
|
|
||||||
|
"message.repeating-mod.replay_start": "Replay started",
|
||||||
|
"message.repeating-mod.replay_stop": "Replay finished",
|
||||||
|
"message.repeating-mod.record_start": "Record started",
|
||||||
|
"message.repeating-mod.record_stop": "Record finished"
|
||||||
|
}
|
27
src/main/resources/assets/repeating-mod/lang/ru_ru.json
Normal file
27
src/main/resources/assets/repeating-mod/lang/ru_ru.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"key.repeating-mod.menu": "Меню репитинга",
|
||||||
|
"key.repeating-mod.toggle_replay": "Вкл/выкл повтор",
|
||||||
|
"key.repeating-mod.toggle_record": "Вкл/выкл запись",
|
||||||
|
|
||||||
|
"text.repeating-mod.name": "Репитинг Мод",
|
||||||
|
"text.repeating-mod.record": "запись",
|
||||||
|
"text.repeating-mod.replay": "повтор",
|
||||||
|
"text.repeating-mod.start": "Начать",
|
||||||
|
"text.repeating-mod.stop": "Остановить",
|
||||||
|
"text.repeating-mod.export": "Экспорт записи",
|
||||||
|
"text.repeating-mod.import": "Импорт записи",
|
||||||
|
"text.repeating-mod.basic": "Обычный режим",
|
||||||
|
"text.repeating-mod.parkour": "Режим паркура",
|
||||||
|
"text.repeating-mod.settings": "Настройки",
|
||||||
|
"text.repeating-mod.dev": "В разработке...",
|
||||||
|
"text.repeating-mod.block_limit": "Лимит блоков: %s",
|
||||||
|
"text.repeating-mod.block_limit_tooltip": "Два ивента записи будут\nсуммироваться, если\nрасстояние между ними\nменьше лимита.",
|
||||||
|
"text.repeating-mod.time_limit": "Лимит времени: %s мс",
|
||||||
|
"text.repeating-mod.time_limit_tooltip": "Два ивента записи будут\nсуммироваться, если время\nмежду ними меньше лимита.",
|
||||||
|
|
||||||
|
"message.repeating-mod.replay_start": "Повтор начат",
|
||||||
|
"message.repeating-mod.replay_stop": "Повтор закончен",
|
||||||
|
"message.repeating-mod.record_start": "Запись начата",
|
||||||
|
"message.repeating-mod.record_stop": "Запись закончена"
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "modid",
|
"id": "repeating-mod",
|
||||||
"version": "${version}",
|
"version": "${version}",
|
||||||
|
|
||||||
"name": "Example Mod",
|
"name": "Repeating Mod",
|
||||||
"description": "This is an example description! Tell everyone what your mod is about!",
|
"description": "Mod that repeats your actions. ",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Me!"
|
"TheMixRay"
|
||||||
],
|
],
|
||||||
"contact": {
|
"contact": {
|
||||||
"homepage": "https://fabricmc.net/",
|
"homepage": "https://fabricmc.net/",
|
||||||
@ -14,22 +14,22 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"license": "CC0-1.0",
|
"license": "CC0-1.0",
|
||||||
"icon": "assets/modid/icon.png",
|
"icon": "icon.png",
|
||||||
|
|
||||||
"environment": "*",
|
"environment": "client",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"main": [
|
"client": [
|
||||||
"net.fabricmc.example.ExampleMod"
|
"themixray.repeating.mod.RepeatingMod"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"modid.mixins.json"
|
"repeating-mod.mixins.json"
|
||||||
],
|
],
|
||||||
|
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.14.17",
|
"fabricloader": ">=0.14.14",
|
||||||
"fabric-api": "*",
|
"fabric-api": "*",
|
||||||
"minecraft": "~1.19.4",
|
"minecraft": "~1.19.3",
|
||||||
"java": ">=17"
|
"java": ">=17"
|
||||||
},
|
},
|
||||||
"suggests": {
|
"suggests": {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"minVersion": "0.8",
|
"minVersion": "0.8",
|
||||||
"package": "net.fabricmc.example.mixin",
|
"package": "themixray.repeating.mod.mixin",
|
||||||
"compatibilityLevel": "JAVA_17",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"ExampleMixin"
|
"MovementMixin",
|
||||||
|
"InputMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
Loading…
Reference in New Issue
Block a user