Compare commits

...

67 commits

Author SHA1 Message Date
654589355d fix version name 2025-06-18 18:18:55 +03:00
0b3bac264f port to 1.21.6 2025-06-18 18:17:57 +03:00
59a2175fb2 port to 1.21.5 2025-06-18 16:18:48 +03:00
ac1ee8ec6d fix record list widget 2025-06-18 15:57:29 +03:00
c65e906500 port to 1.21.4, RECORDS LIST IS BROKEN 2025-06-15 20:36:55 +03:00
f082788406 set fabric mod json 1.21. 2025-06-15 20:06:31 +03:00
072efb64f6 Merge branch '1.21' 2025-06-15 19:59:44 +03:00
06634a8704 set license wtfpl in mod 2025-06-15 19:59:29 +03:00
d101b11c36 fix movements 1.21.2 2025-06-15 16:23:04 +03:00
412c3f47ab port to 1.21.2, MOVEMENTS ARE BROKEN 2025-06-14 23:46:18 +03:00
9d7ac6b213 Merge pull request 'add "compatible with" comment' (#1) from 1.21 into master
Reviewed-on: MeexReay/repeating_mod#1
2025-06-14 22:23:13 +03:00
4714b1dbfb add compatible with comment 2025-06-14 22:22:27 +03:00
5c9df13d15 fix gitea actions 2025-06-14 21:38:30 +03:00
38127eb69f make img folder for readme images 2025-06-14 20:35:23 +03:00
5d5e628cdf add dev artifacts 2025-06-14 20:18:04 +03:00
42bf96701e Merge branch 'master' of https://git.meex.lol/MeexReay/repeating_mod 2025-06-14 20:05:07 +03:00
666377e5ee fix pos event 2025-06-14 20:04:53 +03:00
63132684cd Update README.md 2025-06-14 19:28:24 +03:00
d4abb39c80 downgrade upload-artifact 2025-06-14 08:01:57 +03:00
2e62b69a21 action refactor 2025-06-14 07:45:08 +03:00
62dcb75960 fix upload artifact 2025-06-14 06:48:00 +03:00
b6084063a1 make gradlew exec 2025-06-14 06:23:35 +03:00
1e4f4fdaeb gitea actions fix x3 2025-06-14 06:00:20 +03:00
f49b1e21a3 maybefix gitea actions 2025-06-14 05:23:49 +03:00
759b6cb05e gitea action 2025-06-14 05:17:53 +03:00
2944395e54 remove some crap 2025-06-14 05:09:39 +03:00
45998bbe2e rename group-id and artifact-id, fix recording points render 2025-06-14 05:02:06 +03:00
8242b2c601 readme update 2025-06-14 03:13:26 +03:00
e7abf3e15b open source! 2025-06-14 03:04:16 +03:00
61c755aabc move to 1.21 and fix for nixos 2025-06-14 03:02:04 +03:00
c02d96edca Merge branch 'main' of https://git.meex.lol/MeexReay/repeating_mod 2024-12-08 02:40:33 +03:00
cc12eab006 wh 2024-12-08 02:39:49 +03:00
MeexReay
41706ade80
Update README.md 2024-04-26 20:08:14 +03:00
5d9b27cd9a Merge branch 'main' of https://github.com/MeexReay/repeating-mod 2024-04-26 17:54:52 +03:00
73154eff2b sort records by last modified + fix errors 2024-04-26 17:54:43 +03:00
MeexReay
1ceea8bcd4
Update README.md 2024-04-23 20:44:56 +03:00
ed998cc701 Merge branch 'main' of https://github.com/MeexReay/repeating-mod 2024-04-23 20:44:02 +03:00
e808b6ca09 import now copies file to your record folder 2024-04-23 20:43:49 +03:00
MeexReay
e5981e6e60
Update README.md 2024-04-23 20:38:34 +03:00
a345f65797 Merge branch 'main' of https://github.com/MeexReay/repeating-mod 2024-04-23 20:37:44 +03:00
8d47394acc gui not working, but im tried 2024-04-23 20:37:36 +03:00
MeexReay
5fa8fba00d
Update README.md 2024-04-23 20:23:06 +03:00
MeexReay
8a6e680ff9
Update README.md 2024-04-23 19:20:14 +03:00
f38629a294 events refactor + mixin testing 2024-04-23 19:18:22 +03:00
e76c3dfccf events refactor + mixin testing 2024-04-23 19:18:14 +03:00
28b4265a55 license 2024-04-23 15:17:39 +03:00
a255e4b804 license 2024-04-23 15:15:36 +03:00
aad9a07484 license 2024-04-23 15:13:55 +03:00
278561d374 Merge branch 'main' of https://github.com/MeexReay/repeating-mod 2024-04-23 15:07:45 +03:00
ffc4423b1f license 2024-04-23 15:07:37 +03:00
MeexReay
26496ca3f2
Update README.md 2024-04-23 14:46:56 +03:00
84eb4e026f Merge branch 'main' of https://github.com/MeexReay/repeating-mod 2024-04-23 03:55:44 +03:00
9596fedb6a license 2024-04-23 03:55:36 +03:00
MeexReay
50927fd2f7
Update README.md 2024-04-23 03:48:40 +03:00
MeexReay
99c057c692
Update README.md 2024-04-23 03:47:53 +03:00
e80ee84442 Merge branch 'main' of https://github.com/MeexReay/repeating-mod 2024-04-22 20:08:43 +03:00
MeexReay
74c061c29f
Update README.md 2024-04-22 20:08:26 +03:00
b162304a0b change icon to new one 2024-04-22 20:08:14 +03:00
MeexReay
3e96a7b360
Update README.md 2024-04-22 20:06:43 +03:00
596ca3c0d3 some fixes 2024-04-22 20:06:18 +03:00
MeexReay
70e97ecf92
Update README.md 2024-04-22 19:38:08 +03:00
MeexReay
e194d7f204
Update README.md 2024-04-22 18:55:50 +03:00
MeexReay
3f3ce10d7f
Update README.md 2024-04-22 18:52:44 +03:00
MeexReay
f603f5ad27
Update README.md 2024-04-22 18:50:46 +03:00
MeexReay
a1e4cb0c8d
Update README.md 2024-04-22 18:43:20 +03:00
27627e8404 1.20.4 compatibility 2024-04-22 18:17:31 +03:00
c5132221ae 1.20.4 compatibility 2024-04-22 18:17:22 +03:00
67 changed files with 2230 additions and 1562 deletions

29
.gitea/workflows/java.yml Normal file
View file

@ -0,0 +1,29 @@
on: [ push ]
name: Build fabric mod
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Setup Gradle 8.12.1
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582
with:
gradle-version: '8.12.1'
- name: Build with Gradle Wrapper
run: chmod +x ./gradlew; ./gradlew build
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: build
path: build/libs/*

42
.gitignore vendored Normal file
View file

@ -0,0 +1,42 @@
# 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
remappedSrc/

View file

@ -2,16 +2,49 @@
This mod can record your movements and play them back.
![Preview gif](preview.gif)
## How to use
## Controls
Simply start recording, perform any actions, stop the recording, return to the starting point, and then you can replay everything you did.
### Showcase
![Preview gif](img/preview.gif)
This is how menu looks like:
![repeating mod menu](img/menu.png)
### Controls
Default Repeating Mod keys
```
Menu | J
Toggle recording | not specified
Toggle replay | not specified
Toggle recording | not specified by default
Toggle replay | not specified by default
```
## Menu
## Where to download
![Repeating menu](https://github.com/MeexReay/repeating-mod/assets/127148610/da923fe5-d44d-421b-b601-2a65cb5543eb)
### Stable releases
You can find stable releases on [Modrinth](https://modrinth.com/mod/repeating-mod/versions) or on [Releases page](https://git.meex.lol/MeexReay/repeating_mod/releases)
### Development artifacts
Artifacts are automatically built with [Gitea Actions](https://git.meex.lol/MeexReay/repeating_mod/actions) on each commit. \
[Download latest artifact](https://git.meex.lol/MeexReay/repeating_mod/actions/runs/latest/artifacts/build)
## Roadmap
- [ ] relative mode for repeating actions (like mining)
- [ ] record mouse and keyboard in gui
- [ ] practice mode (like in geometry dash but for parkours)
### Contributing
If you would like to contribute to the project, feel free to fork the repository and submit a pull request.
### License
This project is licensed under the WTFPL License

View file

@ -1,24 +1,26 @@
plugins {
id 'fabric-loom' version '1.1-SNAPSHOT'
id 'fabric-loom' version "${loom_version}"
id 'maven-publish'
}
version = project.mod_version
group = project.maven_group
base {
archivesName = project.archives_base_name
}
repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
maven { url 'https://maven.wispforest.io' }
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
compileOnly 'org.projectlombok:lombok:1.18.38'
annotationProcessor 'org.projectlombok:lombok:1.18.38'
//add joml
modImplementation 'org.joml:joml:1.10.4'
@ -31,23 +33,6 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// Uncomment the following line to enable the deprecated Fabric API modules.
// 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 "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}"
}
base {
archivesName = project.archives_base_name
}
processResources {
@ -59,8 +44,7 @@ processResources {
}
tasks.withType(JavaCompile).configureEach {
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
it.options.release = 17
it.options.release = 21
}
java {
@ -69,20 +53,21 @@ java {
// If you remove this line, sources will not be generated.
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
jar {
from("LICENSE") {
rename { "${it}_${base.archivesName.get()}"}
rename { "${it}_${project.base.archivesName.get()}"}
}
}
// configure the maven publication
publishing {
publications {
mavenJava(MavenPublication) {
create("mavenJava", MavenPublication) {
artifactId = project.archives_base_name
from components.java
}
}

View file

@ -4,14 +4,17 @@ org.gradle.parallel=true
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.20.1
yarn_mappings=1.20.1+build.10
loader_version=0.15.10
minecraft_version=1.21.6
yarn_mappings=1.21.6+build.1
loader_version=0.16.14
loom_version=1.10-SNAPSHOT
#Fabric api
fabric_version=0.92.1+1.20.1
# Fabric API
fabric_version=0.127.0+1.21.6
# Mod Properties
mod_version = 1.1.0
maven_group = themixray.repeating.mod
mod_version = 1.1.2+1.21.6
maven_group = ru.themixray
archives_base_name = repeating-mod
# Compatible with: 1.21.6

Binary file not shown.

View file

@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

29
gradlew vendored Executable file → Normal file
View file

@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -133,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \

20
gradlew.bat vendored
View file

@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

BIN
img/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View file

Before

Width:  |  Height:  |  Size: 4.8 MiB

After

Width:  |  Height:  |  Size: 4.8 MiB

Before After
Before After

6
shell.nix Normal file
View file

@ -0,0 +1,6 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
shellHook = ''
export LD_LIBRARY_PATH="''${LD_LIBRARY_PATH}''${LD_LIBRARY_PATH:+:}${pkgs.libglvnd}/lib"
'';
}

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod;
package ru.themixray.repeating_mod;
import java.io.IOException;
import java.nio.file.Files;

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod;
package ru.themixray.repeating_mod;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
@ -15,13 +15,13 @@ import net.minecraft.util.math.Vec3d;
import org.lwjgl.glfw.GLFW;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import themixray.repeating.mod.event.RecordDelayEvent;
import themixray.repeating.mod.event.RecordEvent;
import themixray.repeating.mod.event.RecordInputEvent;
import themixray.repeating.mod.event.RecordMoveEvent;
import themixray.repeating.mod.render.RenderHelper;
import themixray.repeating.mod.render.RenderSystem;
import themixray.repeating.mod.render.buffer.WorldBuffer;
import ru.themixray.repeating_mod.event.events.DelayEvent;
import ru.themixray.repeating_mod.event.RecordEvent;
import ru.themixray.repeating_mod.event.events.InputEvent;
import ru.themixray.repeating_mod.event.events.MoveEvent;
import ru.themixray.repeating_mod.render.RenderHelper;
import ru.themixray.repeating_mod.render.RenderSystem;
import ru.themixray.repeating_mod.render.buffer.WorldBuffer;
import java.awt.*;
import java.io.File;
@ -45,7 +45,7 @@ public class Main implements ClientModInitializer {
public TickTask replay_tick = null;
public boolean is_replaying = false;
public boolean loop_replay = false;
public static RecordInputEvent input_replay = null;
public static InputEvent input_replay = null;
public long living_ticks = 0;
@ -54,7 +54,7 @@ public class Main implements ClientModInitializer {
private static KeyBinding toggle_replay_key;
private static KeyBinding toggle_record_key;
public long record_pos_delay = 20;
public long record_pos_delay = -1;
public static Random rand = new Random();
@ -75,7 +75,7 @@ public class Main implements ClientModInitializer {
record_list.loadRecords();
RenderSystem.init();
WorldRenderEvents.LAST.register(context -> {
WorldRenderEvents.AFTER_ENTITIES.register(context -> {
WorldBuffer buffer = RenderHelper.startTri(context);
if (now_record != null) {
Vec3d start_pos = now_record.getStartRecordPos();
@ -87,6 +87,10 @@ public class Main implements ClientModInitializer {
RenderHelper.endTri(buffer);
});
ClientTickEvents.END_CLIENT_TICK.register(client -> {
TickTask.tickTasks(TickTask.TickAt.CLIENT_EVENT);
});
Map<String,String> def = new HashMap<>();
def.put("record_pos_delay", String.valueOf(record_pos_delay));
@ -169,7 +173,7 @@ public class Main implements ClientModInitializer {
now_record = record_list.newRecord();
Vec3d start_pos = client.player.getPos();
now_record.addEvent(new RecordMoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch()));
recordTick(new MoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch()));
now_record.setStartRecordPos(start_pos);
if (record_pos_delay > 0) {
@ -178,7 +182,7 @@ public class Main implements ClientModInitializer {
record_pos_delay) {
@Override
public void run() {
now_record.addEvent(new RecordMoveEvent(client.player.getPos(),
recordTick(new MoveEvent(client.player.getPos(),
client.player.getHeadYaw(), client.player.getPitch()));
}
};
@ -192,7 +196,7 @@ public class Main implements ClientModInitializer {
long now = living_ticks;
if (last_record != -1) {
long diff = now - last_record - 2;
if (diff > 0) now_record.addEvent(new RecordDelayEvent(diff));
if (diff > 0) now_record.addEvent(new DelayEvent(diff));
}
now_record.addEvent(e);
last_record = now;
@ -205,46 +209,14 @@ public class Main implements ClientModInitializer {
return;
}
RecordInputEvent l = ((RecordInputEvent) now_record.getLastEvent("input"));
if (l == null) {
RecordInputEvent e = new RecordInputEvent(
client.player.input.sneaking,
client.player.input.jumping,
client.player.input.movementSideways,
client.player.input.movementForward,
client.player.input.pressingForward,
client.player.input.pressingBack,
client.player.input.pressingLeft,
client.player.input.pressingRight,
client.player.getHeadYaw(),
client.player.getBodyYaw(),
client.player.getPitch(),
client.player.isSprinting(),
client.player.getYaw(),
client.player.getMovementSpeed());
recordTick(e);
} else {
RecordInputEvent e = new RecordInputEvent(
((Boolean) client.player.input.sneaking == l.sneaking) ? null : client.player.input.sneaking,
((Boolean) client.player.input.jumping == l.jumping) ? null : client.player.input.jumping,
(((Float) client.player.input.movementSideways).equals(l.movementSideways)) ? null : client.player.input.movementSideways,
(((Float) client.player.input.movementForward).equals(l.movementForward)) ? null : client.player.input.movementForward,
((Boolean) client.player.input.pressingForward == l.pressingForward) ? null : client.player.input.pressingForward,
((Boolean) client.player.input.pressingBack == l.pressingBack) ? null : client.player.input.pressingBack,
((Boolean) client.player.input.pressingLeft == l.pressingLeft) ? null : client.player.input.pressingLeft,
((Boolean) client.player.input.pressingRight == l.pressingRight) ? null : client.player.input.pressingRight,
client.player.getHeadYaw(), Main.client.player.getBodyYaw(),client.player.getPitch(),
((Boolean) client.player.isSprinting() == l.sprinting) ? null : client.player.isSprinting(),
client.player.getYaw(),client.player.getMovementSpeed());
InputEvent curr = InputEvent.current();
if (curr == null) return;
if (!(e.isEmpty() &&
e.yaw == l.yaw &&
e.head_yaw == l.head_yaw &&
e.pitch == l.pitch &&
e.body_yaw == l.body_yaw)) {
e.fillEmpty(l);
recordTick(e);
}
InputEvent last = ((InputEvent) now_record.getLastEvent("input"));
if (last == null) {
recordTick(curr);
} else if (!curr.equals(last)) {
recordTick(curr.differs(last));
}
}
@ -273,26 +245,32 @@ public class Main implements ClientModInitializer {
List<RecordEvent> events = now_record.getEvents();
replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_TAIL) {
replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_EVENT) {
public int replay_index = 0;
@Override
public void run() {
if (!is_replaying) cancel();
if (!is_replaying) {
cancel();
return;
}
RecordEvent e = events.get(replay_index);
if (e instanceof RecordDelayEvent) {
setDelay(((RecordDelayEvent) e).delay);
if (e != null) {
if (e instanceof DelayEvent) {
setDelay(((DelayEvent) e).delay);
} else {
e.replay();
}
}
replay_index++;
if (!loop_replay) {
if (replay_index == events.size()) {
if (replay_index >= events.size()) {
stopReplay();
cancel();
}
} else if (replay_index == events.size()) {
} else if (replay_index >= events.size()) {
replay_index = 0;
}
}
@ -308,6 +286,11 @@ public class Main implements ClientModInitializer {
replay_tick.cancel();
replay_tick = null;
}
try {
now_record.save();
} catch (IOException e) {
throw new RuntimeException(e);
}
menu.updateButtons();
record_list.getWidget().getWidget(now_record).getChildren().get(3).setMessage(Text.translatable("text.repeating-mod.start"));
sendMessage(Text.translatable("message.repeating-mod.replay_stop"));
@ -317,10 +300,10 @@ public class Main implements ClientModInitializer {
client.player.sendMessage(Text.literal("[")
.append(Text.translatable("text.repeating-mod.name"))
.append("] ").formatted(Formatting.BOLD,Formatting.DARK_GRAY)
.append(text.formatted(Formatting.RESET).formatted(Formatting.GRAY)));
.append(text.formatted(Formatting.RESET).formatted(Formatting.GRAY)), false);
}
public static void sendDebug(String s) {
client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s)));
}
// public static void sendDebug(String s) {
// client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s)), false);
// }
}

View file

@ -1,23 +1,19 @@
package themixray.repeating.mod;
package ru.themixray.repeating_mod;
import net.minecraft.text.Text;
import themixray.repeating.mod.widget.RecordListWidget;
import ru.themixray.repeating_mod.widget.RecordListWidget;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.nio.file.Files;
import java.util.*;
public class RecordList {
private final File folder;
private List<RecordState> records;
private LinkedList<RecordState> records;
private RecordListWidget widget;
public RecordList(File folder) {
this.folder = folder;
this.records = new ArrayList<>();
this.records = new LinkedList<>();
this.widget = new RecordListWidget(0, 0, 180, 200);
}
@ -34,18 +30,25 @@ public class RecordList {
}
public void loadRecords() {
for (File file : folder.listFiles()) {
LinkedList<File> files = new LinkedList<>(List.of(folder.listFiles()));
files.sort(Comparator.comparingLong((f) -> f.lastModified()));
for (File file : files) {
try {
addRecord(file);
} catch (Exception e) {}
}
}
public void addRecord(File file) throws Exception {
addRecord(RecordState.load(file));
public RecordState addRecord(File file) throws Exception {
RecordState st = RecordState.load(file);
addRecord(st);
return st;
}
public void addRecord(RecordState record) {
if (record == null) return;
records.add(record);
widget.addWidget(record);
}
@ -74,4 +77,12 @@ public class RecordList {
return state;
}
public RecordState cloneRecord(File file) throws Exception {
File out = new File(Main.me.records_folder, file.getName());
Files.copy(file.toPath(), out.toPath());
RecordState state = RecordState.load(out);
addRecord(state);
return state;
}
}

View file

@ -1,10 +1,9 @@
package themixray.repeating.mod;
package ru.themixray.repeating_mod;
import com.google.common.collect.Lists;
import net.minecraft.util.math.Vec3d;
import themixray.repeating.mod.event.RecordEvent;
import ru.themixray.repeating_mod.event.RecordEvent;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@ -96,12 +95,13 @@ public class RecordState {
}
public void addEvent(RecordEvent event) {
if (event == null) return;
events.add(event);
}
public RecordEvent getLastEvent(String type) {
for (RecordEvent r: Lists.reverse(new ArrayList<>(events))) {
if (r.getType().equals(type)) {
if (r.getType() != null && r.getType().getName().equals(type)) {
return r;
}
}
@ -109,6 +109,8 @@ public class RecordState {
}
public void save() throws IOException {
if (start_record_pos == null || finish_record_pos == null) return;
StringBuilder text = new StringBuilder();
text.append(name).append("\n")
@ -122,9 +124,10 @@ public class RecordState {
.append(finish_record_pos.getY()).append("n")
.append(finish_record_pos.getZ());
for (int i = 0; i < events.size(); i++) {
for (RecordEvent event : events) {
if (event == null) continue;
text.append("\n");
text.append(events.get(i).serialize());
text.append(event.serialize());
}
Files.write(file.toPath(), text.toString().getBytes());
@ -162,8 +165,13 @@ public class RecordState {
}
public void remove() {
file.delete();
Main.me.record_list.removeRecord(this);
Main.me.record_list.getWidget().removeWidget(this);
if (Main.me.is_recording && this.equals(Main.me.now_record)) {
Main.me.stopRecording();
Main.me.now_record = null;
return;
}
file.delete();
}
}

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod;
package ru.themixray.repeating_mod;
import net.minecraft.client.gui.DrawContext;

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod;
package ru.themixray.repeating_mod;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@ -11,7 +11,7 @@ import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.SliderWidget;
import net.minecraft.text.Text;
import themixray.repeating.mod.widget.RecordListWidget;
import ru.themixray.repeating_mod.widget.RecordListWidget;
import java.awt.*;
import java.io.File;
@ -51,7 +51,7 @@ public class RepeatingScreen extends Screen {
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
renderBackground(context);
// renderBackground(context, mouseX, mouseY, delta);
for (RenderListener l : render_listeners) {
if (l.beforeRender()) {
@ -132,12 +132,6 @@ public class RepeatingScreen extends Screen {
super.onDrag(mouseX, mouseY, deltaX, deltaY);
applyValue();
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta);
updateMessage();
}
};
pos_delay_slider.setTooltip(Tooltip.of(Text.translatable("text.repeating-mod.pos_delay_tooltip")));
@ -154,7 +148,7 @@ public class RepeatingScreen extends Screen {
if (files != null) {
for (File file : files) {
try {
Main.me.record_list.addRecord(file);
Main.me.setNowRecord(Main.me.record_list.cloneRecord(file));
} catch (Exception e) {
throw new RuntimeException(e);
}

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod;
package ru.themixray.repeating_mod;
import java.util.ArrayList;
import java.util.List;
@ -23,7 +23,8 @@ public abstract class TickTask implements Runnable {
public enum TickAt {
CLIENT_HEAD, CLIENT_TAIL,
MOVEMENT_HEAD, MOVEMENT_TAIL,
RENDER_HEAD, RENDER_TAIL
RENDER_HEAD, RENDER_TAIL,
CLIENT_EVENT
}
public TickTask(long delay, TickAt at) {

View file

@ -0,0 +1,22 @@
package ru.themixray.repeating_mod.event;
import ru.themixray.repeating_mod.event.events.*;
public abstract class RecordEvent {
public abstract void replay();
public RecordEventType getType() {
for (RecordEventType ev : RecordEventType.values()) {
if (ev.getEventClass().getTypeName().equals(this.getClass().getTypeName())) {
return ev;
}
}
return null;
}
protected abstract String[] serializeArgs();
public String serialize() {
return getType().getChar() + "=" + String.join("&", serializeArgs());
}
public static RecordEvent deserialize(String t) {
return RecordEventType.getByChar(t.charAt(0)).deserialize(t.substring(2).split("&"));
}
}

View file

@ -0,0 +1,69 @@
package ru.themixray.repeating_mod.event;
import ru.themixray.repeating_mod.event.events.*;
public enum RecordEventType {
BLOCK_BREAK('b',"block_break",BlockBreakEvent.class),
BLOCK_INTERACT('i',"block_interact",BlockInteractEvent.class),
DELAY('d',"delay",DelayEvent.class),
INPUT('p',"input",InputEvent.class),
MOVE('m',"move",MoveEvent.class);
// GUI_KEY_PRESS('r',"key_press", GuiKeyPressEvent.class),
// GUI_KEY_RELEASE('s',"key_release",GuiKeyReleaseEvent.class),
// GUI_CHAR_TYPE('h',"char_type",GuiCharTypeEvent.class),
// GUI_MOUSE_CLICK('c',"mouse_click",GuiMouseClickEvent.class),
// GUI_MOUSE_RELEASE('l',"mouse_release",GuiMouseReleaseEvent.class),
// GUI_MOUSE_DRAG('g',"mouse_drag",GuiMouseDragEvent.class),
// GUI_MOUSE_MOVE('v',"mouse_move",GuiMouseMoveEvent.class),
// GUI_MOUSE_SCROLL('o',"mouse_scroll",GuiMouseScrollEvent.class),
// GUI_CLOSE('e',"close",GuiCloseEvent.class);
private Class<? extends RecordEvent> ev;
private char ch;
private String name;
RecordEventType(char ch, String name, Class<? extends RecordEvent> ev) {
this.ev = ev;
this.ch = ch;
this.name = name;
}
public Class<? extends RecordEvent> getEventClass() {
return ev;
}
public char getChar() {
return ch;
}
public String getName() {
return name;
}
public RecordEvent deserialize(String[] args) {
try {
return (RecordEvent) ev
.getMethod("deserialize", String[].class)
.invoke(null, (Object) args);
} catch (Throwable e) {
return null;
}
}
public String serialize(RecordEvent event) {
return event.serialize();
}
public static RecordEventType getByChar(String type) {
return getByChar(type.charAt(0));
}
public static RecordEventType getByChar(char ch) {
for (RecordEventType t : values()) {
if (t.getChar() == ch) {
return t;
}
}
return null;
}
}

View file

@ -0,0 +1,35 @@
package ru.themixray.repeating_mod.event.events;
import net.minecraft.util.math.BlockPos;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class BlockBreakEvent extends RecordEvent {
public BlockPos pos;
public BlockBreakEvent(
BlockPos pos) {
this.pos = pos;
}
public static BlockBreakEvent deserialize(String[] a) {
return new BlockBreakEvent(new BlockPos(
Integer.parseInt(a[0]),
Integer.parseInt(a[1]),
Integer.parseInt(a[2])));
}
protected String[] serializeArgs() {
return new String[]{
String.valueOf(pos.getX()),
String.valueOf(pos.getY()),
String.valueOf(pos.getZ())
};
}
public void replay() {
if (Main.client.interactionManager != null) {
Main.client.interactionManager.breakBlock(pos);
}
}
}

View file

@ -0,0 +1,51 @@
package ru.themixray.repeating_mod.event.events;
import net.minecraft.util.Hand;
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 ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class BlockInteractEvent extends RecordEvent {
public Hand hand;
public BlockHitResult hitResult;
public static BlockInteractEvent deserialize(String[] a) {
return new BlockInteractEvent(
Hand.valueOf(a[5]),
new BlockHitResult(new Vec3d(
Double.parseDouble(a[0]),
Double.parseDouble(a[1]),
Double.parseDouble(a[2])),
Direction.byIndex(Integer.parseInt(a[4])),
new BlockPos(
Integer.parseInt(a[0]),
Integer.parseInt(a[1]),
Integer.parseInt(a[2])),
a[3].equals("1")));
}
public BlockInteractEvent(Hand hand, BlockHitResult hitResult) {
this.hand = hand;
this.hitResult = hitResult;
}
public void replay() {
if (Main.client.interactionManager != null) {
Main.client.interactionManager.interactBlock(Main.client.player, hand, hitResult);
}
}
protected String[] serializeArgs() {
return new String[]{
String.valueOf(hitResult.getBlockPos().getX()),
String.valueOf(hitResult.getBlockPos().getY()),
String.valueOf(hitResult.getBlockPos().getZ()),
(hitResult.isInsideBlock() ? "1" : "0"),
String.valueOf(hitResult.getSide().getIndex()),
hand.name()
};
}
}

View file

@ -0,0 +1,29 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.event.RecordEvent;
public class DelayEvent extends RecordEvent {
public long delay;
public static DelayEvent deserialize(String[] a) {
return new DelayEvent(Long.parseLong(a[0]));
}
public DelayEvent(long delay) {
this.delay = delay;
}
public void replay() {
try {
Thread.sleep(delay / 20 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected String[] serializeArgs() {
return new String[]{
String.valueOf(delay)
};
}
}

View file

@ -0,0 +1,34 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiCharTypeEvent extends RecordEvent {
private char chr;
private int modifiers;
public GuiCharTypeEvent(char chr, int modifiers) {
this.chr = chr;
this.modifiers = modifiers;
}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.currentScreen.charTyped(chr, modifiers);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf((int) chr),
String.valueOf(modifiers)
};
}
public static GuiCharTypeEvent deserialize(String[] args) {
return new GuiCharTypeEvent(
(char) Integer.parseInt(args[0]),
Integer.parseInt(args[1])
);
}
}

View file

@ -0,0 +1,22 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiCloseEvent extends RecordEvent {
public GuiCloseEvent() {}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.setScreen(null);
}
}
protected String[] serializeArgs() {
return new String[] {};
}
public static GuiCloseEvent deserialize(String[] args) {
return new GuiCloseEvent();
}
}

View file

@ -0,0 +1,38 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiKeyPressEvent extends RecordEvent {
private int keyCode;
private int scanCode;
private int modifiers;
public GuiKeyPressEvent(int keyCode, int scanCode, int modifiers) {
this.keyCode = keyCode;
this.scanCode = scanCode;
this.modifiers = modifiers;
}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.currentScreen.keyPressed(keyCode, scanCode, modifiers);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf(keyCode),
String.valueOf(scanCode),
String.valueOf(modifiers)
};
}
public static GuiKeyPressEvent deserialize(String[] args) {
return new GuiKeyPressEvent(
Integer.parseInt(args[0]),
Integer.parseInt(args[1]),
Integer.parseInt(args[2])
);
}
}

View file

@ -0,0 +1,38 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiKeyReleaseEvent extends RecordEvent {
private int keyCode;
private int scanCode;
private int modifiers;
public GuiKeyReleaseEvent(int keyCode, int scanCode, int modifiers) {
this.keyCode = keyCode;
this.scanCode = scanCode;
this.modifiers = modifiers;
}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.currentScreen.keyReleased(keyCode, scanCode, modifiers);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf(keyCode),
String.valueOf(scanCode),
String.valueOf(modifiers)
};
}
public static GuiKeyReleaseEvent deserialize(String[] args) {
return new GuiKeyReleaseEvent(
Integer.parseInt(args[0]),
Integer.parseInt(args[1]),
Integer.parseInt(args[2])
);
}
}

View file

@ -0,0 +1,38 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiMouseClickEvent extends RecordEvent {
private double mouseX;
private double mouseY;
private int button;
public GuiMouseClickEvent(double mouseX, double mouseY, int button) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.button = button;
}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.currentScreen.mouseClicked(mouseX, mouseY, button);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf(mouseX),
String.valueOf(mouseY),
String.valueOf(button)
};
}
public static GuiMouseClickEvent deserialize(String[] args) {
return new GuiMouseClickEvent(
Double.parseDouble(args[0]),
Double.parseDouble(args[1]),
Integer.parseInt(args[2])
);
}
}

View file

@ -0,0 +1,46 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiMouseDragEvent extends RecordEvent {
private double mouseX;
private double mouseY;
private double deltaX;
private double deltaY;
private int button;
public GuiMouseDragEvent(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.deltaX = deltaX;
this.deltaY = deltaY;
this.button = button;
}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.currentScreen.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf(mouseX),
String.valueOf(mouseY),
String.valueOf(button),
String.valueOf(deltaX),
String.valueOf(deltaY)
};
}
public static GuiMouseDragEvent deserialize(String[] args) {
return new GuiMouseDragEvent(
Double.parseDouble(args[0]),
Double.parseDouble(args[1]),
Integer.parseInt(args[2]),
Double.parseDouble(args[3]),
Double.parseDouble(args[4])
);
}
}

View file

@ -0,0 +1,34 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiMouseMoveEvent extends RecordEvent {
private double mouseX;
private double mouseY;
public GuiMouseMoveEvent(double mouseX, double mouseY) {
this.mouseX = mouseX;
this.mouseY = mouseY;
}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.currentScreen.mouseMoved(mouseX, mouseY);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf(mouseX),
String.valueOf(mouseY)
};
}
public static GuiMouseMoveEvent deserialize(String[] args) {
return new GuiMouseMoveEvent(
Double.parseDouble(args[0]),
Double.parseDouble(args[1])
);
}
}

View file

@ -0,0 +1,38 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiMouseReleaseEvent extends RecordEvent {
private double mouseX;
private double mouseY;
private int button;
public GuiMouseReleaseEvent(double mouseX, double mouseY, int button) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.button = button;
}
public void replay() {
if (Main.client.currentScreen != null) {
Main.client.currentScreen.mouseReleased(mouseX, mouseY, button);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf(mouseX),
String.valueOf(mouseY),
String.valueOf(button)
};
}
public static GuiMouseReleaseEvent deserialize(String[] args) {
return new GuiMouseReleaseEvent(
Double.parseDouble(args[0]),
Double.parseDouble(args[1]),
Integer.parseInt(args[2])
);
}
}

View file

@ -0,0 +1,38 @@
package ru.themixray.repeating_mod.event.events;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class GuiMouseScrollEvent extends RecordEvent {
private double mouseX;
private double mouseY;
private double amount;
public GuiMouseScrollEvent(double mouseX, double mouseY, double amount) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.amount = amount;
}
public void replay() {
if (Main.client.currentScreen != null) {
// Main.client.currentScreen.mouseScrolled(mouseX, mouseY, amount);
}
}
protected String[] serializeArgs() {
return new String[] {
String.valueOf(mouseX),
String.valueOf(mouseY),
String.valueOf(amount)
};
}
public static GuiMouseScrollEvent deserialize(String[] args) {
return new GuiMouseScrollEvent(
Double.parseDouble(args[0]),
Double.parseDouble(args[1]),
Double.parseDouble(args[2])
);
}
}

View file

@ -0,0 +1,195 @@
package ru.themixray.repeating_mod.event.events;
import net.minecraft.client.input.Input;
import net.minecraft.util.PlayerInput;
import net.minecraft.util.math.Vec2f;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
import java.lang.reflect.Field;
public class InputEvent extends RecordEvent {
public Boolean forward;
public Boolean backward;
public Boolean left;
public Boolean right;
public Boolean jump;
public Boolean sneak;
public Boolean sprint;
public float yaw;
public float head_yaw;
public float body_yaw;
public float pitch;
public float speed;
public float movementForward;
public float movementSideways;
public static InputEvent current() {
if (Main.client.player == null) return null;
return new InputEvent(
Main.client.player.input.playerInput.forward(),
Main.client.player.input.playerInput.backward(),
Main.client.player.input.playerInput.left(),
Main.client.player.input.playerInput.right(),
Main.client.player.input.playerInput.jump(),
Main.client.player.input.playerInput.sneak(),
Main.client.player.input.playerInput.sprint(),
Main.client.player.getHeadYaw(),
Main.client.player.getBodyYaw(),
Main.client.player.getPitch(),
Main.client.player.getYaw(),
Main.client.player.getMovementSpeed(),
Main.client.player.input.getMovementInput().y,
Main.client.player.input.getMovementInput().x
);
}
public InputEvent(Boolean forward,
Boolean backward,
Boolean left,
Boolean right,
Boolean jump,
Boolean sneak,
Boolean sprint,
float head_yaw,
float body_yaw,
float head_pitch,
float yaw,
float speed,
float movementForward,
float movementSideways) {
this.forward = forward;
this.backward = backward;
this.left = left;
this.right = right;
this.jump = jump;
this.sneak = sneak;
this.sprint = sprint;
this.head_yaw = head_yaw;
this.body_yaw = body_yaw;
this.pitch = head_pitch;
this.yaw = yaw;
this.speed = speed;
this.movementForward = movementForward;
this.movementSideways = movementSideways;
}
/**
* Returns differences of this InputEvent to the provided one, saving first booleans if differ and first floats always
*/
public InputEvent differs(InputEvent event) {
return new InputEvent(
forward == event.forward ? null : forward,
backward == event.backward ? null : backward,
left == event.left ? null : left,
right == event.right ? null : right,
jump == event.jump ? null : jump,
sneak == event.sneak ? null : sneak,
sprint == event.sprint ? null : sprint,
head_yaw,
body_yaw,
pitch,
yaw,
speed,
movementForward,
movementSideways
);
}
public static InputEvent deserialize(String[] a) {
return new InputEvent(
(a[0].equals("n") ? null : a[0].equals("1")),
(a[1].equals("n") ? null : a[1].equals("1")),
(a[2].equals("n") ? null : a[2].equals("1")),
(a[3].equals("n") ? null : a[3].equals("1")),
(a[4].equals("n") ? null : a[4].equals("1")),
(a[5].equals("n") ? null : a[5].equals("1")),
(a[6].equals("n") ? null : a[6].equals("1")),
Float.parseFloat(a[7]),
Float.parseFloat(a[8]),
Float.parseFloat(a[9]),
Float.parseFloat(a[10]),
Float.parseFloat(a[11]),
Float.parseFloat(a[12]),
Float.parseFloat(a[13])
);
}
protected String[] serializeArgs() {
return new String[] {
((forward == null) ? "n" : (forward ? "1" : "0")),
((backward == null) ? "n" : (backward ? "1" : "0")),
((left == null) ? "n" : (left ? "1" : "0")),
((right == null) ? "n" : (right ? "1" : "0")),
((jump == null) ? "n" : (jump ? "1" : "0")),
((sneak == null) ? "n" : (sneak ? "1" : "0")),
((sprint == null) ? "n" : (sprint ? "1" : "0")),
String.valueOf(head_yaw),
String.valueOf(body_yaw),
String.valueOf(pitch),
String.valueOf(yaw),
String.valueOf(speed),
String.valueOf(movementForward),
String.valueOf(movementSideways)
};
}
public boolean equals(InputEvent event) {
return event.forward == forward &&
event.backward == backward &&
event.sprint == sprint &&
event.jump == jump &&
event.sneak == sneak &&
event.left == left &&
event.right == right &&
event.speed == speed &&
event.head_yaw == head_yaw &&
event.body_yaw == body_yaw &&
event.yaw == yaw &&
event.pitch == pitch &&
event.movementForward == movementForward &&
event.movementSideways == movementSideways;
}
public void replay() {
Main.input_replay = this;
}
public void inputCallback() {
if (Main.client.player != null) {
if (sprint != null && Main.client.player.isSprinting() != sprint)
Main.client.player.setSprinting(sprint);
if (Main.client.player.getYaw() != yaw)
Main.client.player.setYaw(yaw);
if (Main.client.player.getHeadYaw() != head_yaw)
Main.client.player.setHeadYaw(head_yaw);
if (Main.client.player.getBodyYaw() != body_yaw)
Main.client.player.setBodyYaw(body_yaw);
if (Main.client.player.getPitch() != pitch)
Main.client.player.setPitch(pitch);
if (Main.client.player.getMovementSpeed() != speed)
Main.client.player.setMovementSpeed(speed);
try {
Field field = Input.class.getDeclaredField("movementVector");
field.setAccessible(true);
field.set(Main.client.player.input, new Vec2f(movementSideways, movementForward));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
PlayerInput input = Main.client.player.input.playerInput;
Main.client.player.input.playerInput = new PlayerInput(
this.forward == null ? input.forward() : this.forward,
this.backward == null ? input.backward() : this.backward,
this.left == null ? input.left() : this.left,
this.right == null ? input.right() : this.right,
this.jump == null ? input.jump() : this.jump,
this.sneak == null ? input.sneak() : this.sneak,
this.sprint == null ? input.sprint() : this.sprint
);
}
}
}

View file

@ -0,0 +1,52 @@
package ru.themixray.repeating_mod.event.events;
import net.minecraft.entity.MovementType;
import net.minecraft.util.math.Vec3d;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.RecordEvent;
public class MoveEvent extends RecordEvent {
public Vec3d vec;
public float yaw;
public float pitch;
public static final float MOVE_THRESHOLD = 0.001f;
public static MoveEvent deserialize(String[] a) {
return new MoveEvent(new Vec3d(
Double.parseDouble(a[0]),
Double.parseDouble(a[1]),
Double.parseDouble(a[2])),
Float.parseFloat(a[3]),
Float.parseFloat(a[4]));
}
public MoveEvent(Vec3d vec, float yaw, float pitch) {
this.vec = vec;
this.yaw = yaw;
this.pitch = pitch;
}
public void replay() {
if (Main.client.player != null) {
Vec3d p = Main.client.player.getPos();
Vec3d v = new Vec3d(vec.getX() - p.getX(), vec.getY() - p.getY(), vec.getZ() - p.getZ());
if (Math.abs(v.x) > MOVE_THRESHOLD || Math.abs(v.y) > MOVE_THRESHOLD || Math.abs(v.z) > MOVE_THRESHOLD)
Main.client.player.move(MovementType.SELF, v);
if (Math.abs(Main.client.player.getYaw() - yaw) > MOVE_THRESHOLD)
Main.client.player.setYaw(yaw);
if (Math.abs(Main.client.player.getPitch() - pitch) > MOVE_THRESHOLD)
Main.client.player.setPitch(pitch);
}
}
protected String[] serializeArgs() {
return new String[]{
String.valueOf(vec.getX()),
String.valueOf(vec.getZ()),
String.valueOf(yaw),
String.valueOf(pitch)
};
}
}

View file

@ -1,12 +1,12 @@
package themixray.repeating.mod.mixin;
package ru.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.Main;
import themixray.repeating.mod.TickTask;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.TickTask;
@Mixin(MinecraftClient.class)
public abstract class ClientMixin {

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod.mixin;
package ru.themixray.repeating_mod.mixin;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@ -6,7 +6,7 @@ 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.Main;
import ru.themixray.repeating_mod.Main;
import java.util.UUID;
@ -16,13 +16,14 @@ public abstract class EntityMixin {
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
private void onSprint(boolean sprinting,CallbackInfo ci) {
if (Main.client.player != null) {
if (getUuid().equals(Main.client.player.getUuid())) {
if (Main.me.is_replaying) {
if (Main.input_replay != null &&
Main.input_replay.sprinting != null &&
Main.input_replay.sprinting != sprinting) {
Main.input_replay.sprint != null &&
Main.input_replay.sprint != sprinting) {
ci.cancel();
return;
}
}
}
}

View file

@ -1,16 +1,16 @@
package themixray.repeating.mod.mixin;
package ru.themixray.repeating_mod.mixin;
import net.minecraft.client.input.KeyboardInput;
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.Main;
import ru.themixray.repeating_mod.Main;
@Mixin(KeyboardInput.class)
public abstract class InputMixin {
@Inject(at = @At(value = "TAIL"), method = "tick")
private void onTickTail(boolean slowDown, float f, CallbackInfo ci) {
private void onTickTail(CallbackInfo ci) {
if (Main.me.is_replaying) {
if (Main.input_replay != null) {
Main.input_replay.inputCallback();

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod.mixin;
package ru.themixray.repeating_mod.mixin;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
@ -9,10 +9,10 @@ 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.Main;
import themixray.repeating.mod.event.RecordBlockBreakEvent;
import themixray.repeating.mod.event.RecordBlockInteractEvent;
import themixray.repeating.mod.TickTask;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.events.BlockBreakEvent;
import ru.themixray.repeating_mod.event.events.BlockInteractEvent;
import ru.themixray.repeating_mod.TickTask;
@Mixin(ClientPlayerEntity.class)
public abstract class MovementMixin {
@ -21,13 +21,13 @@ public abstract class MovementMixin {
private void init(CallbackInfo ci) {
PlayerBlockBreakEvents.AFTER.register((world, player, pos, blockState, blockEntity) -> {
if (Main.me.is_recording)
Main.me.recordTick(new RecordBlockBreakEvent(pos));
Main.me.recordTick(new BlockBreakEvent(pos));
});
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
if (hitResult.getType().equals(HitResult.Type.BLOCK))
if (Main.me.is_recording)
Main.me.recordTick(new RecordBlockInteractEvent(hand,hitResult));
Main.me.recordTick(new BlockInteractEvent(hand,hitResult));
return ActionResult.PASS;
});
}

View file

@ -0,0 +1,29 @@
package ru.themixray.repeating_mod.mixin;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.listener.ServerPlayPacketListener;
import net.minecraft.network.packet.Packet;
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 java.time.Duration;
import java.util.function.BooleanSupplier;
@Mixin(ClientPlayNetworkHandler.class)
public abstract class NetworkMixin {
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V")
// private void onSendPacket1Head(Packet<?> packet,
// CallbackInfo ci) {
//
// }
//
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V")
// private void onSendPacket2Head(Packet<ServerPlayPacketListener> packet,
// BooleanSupplier sendCondition,
// Duration expirationTime,
// CallbackInfo ci) {
//
// }
}

View file

@ -0,0 +1,19 @@
package ru.themixray.repeating_mod.mixin;
import net.minecraft.network.ClientConnection;
import net.minecraft.text.Text;
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 ru.themixray.repeating_mod.Main;
@Mixin(ClientConnection.class)
public abstract class PlayerMixin {
@Inject(at = @At(value = "HEAD"), method = "disconnect")
private void disconnect(Text disconnectReason, CallbackInfo ci) {
if (Main.me.is_replaying) {
Main.me.stopReplay();
}
}
}

View file

@ -1,11 +1,11 @@
package themixray.repeating.mod.mixin;
package ru.themixray.repeating_mod.mixin;
import net.minecraft.client.render.*;
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.TickTask;
import ru.themixray.repeating_mod.TickTask;
@Mixin(GameRenderer.class)
public abstract class RendererMixin {

View file

@ -0,0 +1,85 @@
package ru.themixray.repeating_mod.mixin;
import net.minecraft.client.gui.AbstractParentElement;
import net.minecraft.client.gui.Drawable;
import net.minecraft.client.gui.screen.Screen;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.event.events.*;
@Mixin(Screen.class)
public abstract class ScreenMixin extends AbstractParentElement implements Drawable {
@Inject(at = @At(value = "HEAD"), method = "close")
private void close(CallbackInfo ci) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiCloseEvent());
}
}
@Inject(at = @At(value = "HEAD"), method = "keyPressed")
private void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiKeyPressEvent(keyCode, scanCode, modifiers));
}
}
@Override
public boolean charTyped(char chr, int modifiers) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiCharTypeEvent(chr, modifiers));
}
return super.charTyped(chr, modifiers);
}
@Override
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiKeyReleaseEvent(keyCode, scanCode, modifiers));
}
return super.keyReleased(keyCode, scanCode, modifiers);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiMouseClickEvent(mouseX, mouseY, button));
}
return super.mouseClicked(mouseX, mouseY, button);
}
@Override
public void mouseMoved(double mouseX, double mouseY) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiMouseMoveEvent(mouseX, mouseY));
}
super.mouseMoved(mouseX, mouseY);
}
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiMouseDragEvent(mouseX, mouseY, button, deltaX, deltaY));
}
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
if (Main.me.is_recording) {
// Main.me.now_record.addEvent(new GuiMouseReleaseEvent(mouseX, mouseY, button));
}
return super.mouseReleased(mouseX, mouseY, button);
}
// @Override
// public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
// if (Main.me.is_recording) {
//// Main.me.now_record.addEvent(new GuiMouseScrollEvent(mouseX, mouseY, amount));
// }
// return super.mouseScrolled(mouseX, mouseY, amount);
// }
}

View file

@ -1,10 +1,10 @@
package themixray.repeating.mod.render;
package ru.themixray.repeating_mod.render;
import lombok.experimental.UtilityClass;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.util.math.Vec3d;
import themixray.repeating.mod.render.buffer.WorldBuffer;
import themixray.repeating.mod.render.shader.ShaderManager;
import org.joml.Vector3f;
import ru.themixray.repeating_mod.render.buffer.WorldBuffer;
import ru.themixray.repeating_mod.render.shader.ShaderManager;
import java.awt.*;
@ -27,8 +27,8 @@ public class RenderHelper {
}
public void drawLine(WorldBuffer buffer, float x1, float y1, float z1, float x2, float y2, float z2, Color color) {
buffer.vert(x1, y1, z1, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(x2, y2, z2, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(new Vector3f(x1, y1, z1), color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(new Vector3f(x2, y2, z2), color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
}
public static WorldBuffer startTri(WorldRenderContext context) {
@ -49,9 +49,9 @@ public class RenderHelper {
}
public void drawTri(WorldBuffer buffer, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, Color color) {
buffer.vert(x1, y1, z1, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(x2, y2, z2, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(x3, y3, z3, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(new Vector3f(x1, y1, z1), color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(new Vector3f(x2, y2, z2), color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
buffer.vert(new Vector3f(x3, y3, z3), color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
}
public static void drawRectFromTri(WorldBuffer buffer,

View file

@ -1,8 +1,8 @@
package themixray.repeating.mod.render;
package ru.themixray.repeating_mod.render;
import lombok.experimental.UtilityClass;
import themixray.repeating.mod.render.buffer.BufferManager;
import themixray.repeating.mod.render.shader.ShaderManager;
import ru.themixray.repeating_mod.render.buffer.BufferManager;
import ru.themixray.repeating_mod.render.shader.ShaderManager;
@UtilityClass
public class RenderSystem {

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod.render.buffer;
package ru.themixray.repeating_mod.render.buffer;
import lombok.experimental.UtilityClass;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;

View file

@ -1,14 +1,11 @@
package themixray.repeating.mod.render.buffer;
package ru.themixray.repeating_mod.render.buffer;
import lombok.Getter;
import org.joml.Vector3f;
public class Vertex {
@Getter
private float x;
@Getter
private float y;
@Getter
private float z;
private Vector3f pos;
@Getter
private float r;
@Getter
@ -18,10 +15,8 @@ public class Vertex {
@Getter
private float a;
public Vertex(float x, float y, float z, float r, float g, float b, float a) {
this.x = x;
this.y = y;
this.z = z;
public Vertex(Vector3f pos, float r, float g, float b, float a) {
this.pos = pos;
this.r = r;
this.g = g;
this.b = b;

View file

@ -1,11 +1,12 @@
package themixray.repeating.mod.render.buffer;
package ru.themixray.repeating_mod.render.buffer;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.util.math.Vec3d;
import org.apache.commons.lang3.ArrayUtils;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.lwjgl.BufferUtils;
import themixray.repeating.mod.render.shader.Shader;
import ru.themixray.repeating_mod.render.shader.Shader;
import java.nio.FloatBuffer;
import java.util.ArrayList;
@ -18,17 +19,19 @@ public class WorldBuffer {
private final int drawMode;
private final Shader shader;
private FloatBuffer projectionMatrix;
private final Vec3d cameraPos;
private final Vector3f cameraPos;
private final Quaternionf cameraRot;
public WorldBuffer(int drawMode, Shader shader, WorldRenderContext worldRenderContext) {
this.drawMode = drawMode;
this.shader = shader;
this.cameraPos = worldRenderContext.camera().getPos();
makeProjectionMatrix(worldRenderContext.projectionMatrix(), worldRenderContext.matrixStack().peek().getPositionMatrix());
this.cameraPos = worldRenderContext.camera().getPos().toVector3f();
this.cameraRot = worldRenderContext.camera().getRotation().invert();
this.projectionMatrix = worldRenderContext.projectionMatrix().mul(worldRenderContext.matrixStack().peek().getPositionMatrix()).get(BufferUtils.createFloatBuffer(16));
}
public void vert(float x, float y, float z, float r, float g, float b, float a) {
vertices.add(new Vertex(x - (float) cameraPos.x, y - (float) cameraPos.y, z - (float) cameraPos.z, r, g, b, a));
public void vert(Vector3f pos, float r, float g, float b, float a) {
vertices.add(new Vertex(cameraRot.transform(pos.sub(cameraPos)), r, g, b, a));
}
public void draw() {
@ -36,7 +39,7 @@ public class WorldBuffer {
BufferManager.bindBuffer();
BufferManager.writeBuffer(getBuffer());
applyProjectionMatrix();
shader.uniformMatrix4f("u_projection", projectionMatrix);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0);
@ -55,12 +58,12 @@ public class WorldBuffer {
private FloatBuffer getBuffer() {
FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(vertices.size() * 7);
ArrayList<Float> floats = new ArrayList<>();
for (Vertex vertex : vertices) {
floats.add(vertex.getX());
floats.add(vertex.getY());
floats.add(vertex.getZ());
for (ru.themixray.repeating_mod.render.buffer.Vertex vertex : vertices) {
floats.add(vertex.getPos().x);
floats.add(vertex.getPos().y);
floats.add(vertex.getPos().z);
}
for (Vertex vertex : vertices) {
for (ru.themixray.repeating_mod.render.buffer.Vertex vertex : vertices) {
floats.add(vertex.getR());
floats.add(vertex.getG());
floats.add(vertex.getB());
@ -71,12 +74,4 @@ public class WorldBuffer {
floatBuffer.put(ArrayUtils.toPrimitive(floatArray));
return floatBuffer.flip();
}
private void makeProjectionMatrix(Matrix4f projectionMatrix, Matrix4f viewModelMatrix) {
this.projectionMatrix = projectionMatrix.mul(viewModelMatrix).get(BufferUtils.createFloatBuffer(16));
}
private void applyProjectionMatrix() {
shader.uniformMatrix4f("u_projection", projectionMatrix);
}
}

View file

@ -1,4 +1,4 @@
package themixray.repeating.mod.render.shader;
package ru.themixray.repeating_mod.render.shader;
import lombok.Getter;
@ -12,8 +12,8 @@ public class Shader {
public Shader(String name) {
int v = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.VERTEX);
int f = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.FRAGMENT);
int v = ru.themixray.repeating_mod.render.shader.ShaderManager.loadShaderProgram(name, ru.themixray.repeating_mod.render.shader.ShaderManager.ShaderType.VERTEX);
int f = ru.themixray.repeating_mod.render.shader.ShaderManager.loadShaderProgram(name, ru.themixray.repeating_mod.render.shader.ShaderManager.ShaderType.FRAGMENT);
this.id = glCreateProgram();
glAttachShader(id, v);
glAttachShader(id, f);

View file

@ -1,6 +1,6 @@
package themixray.repeating.mod.render.shader;
package ru.themixray.repeating_mod.render.shader;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.opengl.GlStateManager;
import com.mojang.blaze3d.platform.TextureUtil;
import lombok.Getter;
import lombok.SneakyThrows;
@ -27,21 +27,21 @@ import static org.lwjgl.opengl.GL33.*;
@UtilityClass
public class ShaderManager {
@Getter
private Shader positionColorShader;
private ru.themixray.repeating_mod.render.shader.Shader positionColorShader;
public void init() {
ClientLifecycleEvents.CLIENT_STARTED.register(client -> loadShaders());
}
private void loadShaders() {
positionColorShader = new Shader("position_color");
positionColorShader = new ru.themixray.repeating_mod.render.shader.Shader("position_color");
}
public int loadShaderProgram(String name, ShaderType type) {
try {
boolean file_present = true;
ResourceFactory resourceFactory = MinecraftClient.getInstance().getResourceManager();
Optional<Resource> resource = resourceFactory.getResource(new Identifier("renderer", "shader/" + name + type.fileExtension));
Optional<Resource> resource = resourceFactory.getResource(Identifier.of("renderer", "shader/" + name + type.fileExtension));
int i = glCreateShader(type.glType);
if (resource.isPresent()) {
GlStateManager.glShaderSource(i, new GlImportProcessor() {
@ -51,7 +51,7 @@ public class ShaderManager {
public String loadImport(boolean inline, String name) {
return IOUtils.toString(resource.get().getInputStream(), StandardCharsets.UTF_8);
}
}.readSource(readResourceAsString(resource.get().getInputStream())));
}.readSource(readResourceAsString(resource.get().getInputStream())).getFirst());
} else file_present = false;
glCompileShader(i);
if (glGetShaderi(i, GL_COMPILE_STATUS) == 0 || !file_present) {

View file

@ -1,24 +1,17 @@
package themixray.repeating.mod.widget;
package ru.themixray.repeating_mod.widget;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Drawable;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.Selectable;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.*;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import themixray.repeating.mod.Main;
import themixray.repeating.mod.RecordState;
import themixray.repeating.mod.RepeatingScreen;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.RecordState;
import ru.themixray.repeating_mod.RepeatingScreen;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.LinkedList;
public class RecordListWidget extends ScrollableWidget {
private List<RecordWidget> widgets = new ArrayList<>();
private LinkedList<RecordWidget> widgets = new LinkedList<>();
private boolean focused = false;
public RecordListWidget(int x, int y, int width, int height) {
@ -33,27 +26,40 @@ public class RecordListWidget extends ScrollableWidget {
return res;
}
@Override
protected int getContentsHeightWithPadding() {
return !widgets.isEmpty() ? widgets.size() * 55 + (widgets.size() - 1) * 2 : 0;
}
@Override
protected double getDeltaYPerScroll() {
return 10;
}
@Override
protected void renderContents(DrawContext ctx, int mouseX, int mouseY, float delta) {
int y = 0;
protected void renderWidget(DrawContext ctx, int mouseX, int mouseY, float delta) {
ctx.fill(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight(), 0xff000000);
ctx.enableScissor(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight());
int y = (int) -this.getScrollY();
for (RecordWidget wid: widgets) {
wid.setY(y);
wid.render(ctx, mouseX, (int) (mouseY + this.getScrollY()), delta);
wid.render(ctx, mouseX, (int) (mouseY), delta);
y += wid.getHeight();
y += 2;
}
ctx.disableScissor();
this.drawScrollbar(ctx);
}
public void addWidget(RecordState record) {
RecordWidget widget = new RecordWidget(0, 0, width, 55, record, this);
RecordWidget widget = new RecordWidget(0, 0, width - 6, 55, record, this);
widget.init(null);
widgets.add(0, widget);
widgets.addFirst(widget);
}
public void removeWidget(RecordState record) {
@ -70,11 +76,6 @@ public class RecordListWidget extends ScrollableWidget {
return focused;
}
@Override
protected int getContentsHeight() {
return !widgets.isEmpty() ? widgets.size() * 55 + (widgets.size() - 1) * 2 : 0;
}
public void init(RepeatingScreen screen) {
for (RecordWidget widget : widgets) {
widget.init(screen);
@ -104,7 +105,7 @@ public class RecordListWidget extends ScrollableWidget {
public boolean checkTransport(transport tr) {
for (RecordWidget wid : widgets) {
for (ClickableWidget child : wid.getChildren()) {
if (tr.check(child)) {
if (child.isFocused() && tr.check(child)) {
return true;
}
}
@ -112,12 +113,14 @@ public class RecordListWidget extends ScrollableWidget {
return false;
}
public boolean checkTransportNF(transport tr) {
public boolean checkTransportNF(double mouseX, double mouseY, int button) {
for (RecordWidget wid : widgets) {
for (ClickableWidget child : wid.getChildren()) {
boolean res = tr.check(child);
if (wid.contains((int) mouseX, (int) mouseY)) {
Main.me.setNowRecord(wid.getRecord());
}
if (res) {
for (ClickableWidget child : wid.getChildren()) {
if (child.mouseClicked(mouseX, mouseY, button)) {
child.setFocused(true);
return true;
} else {
@ -130,7 +133,7 @@ public class RecordListWidget extends ScrollableWidget {
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
return checkTransportNF((c) -> c.mouseClicked(mouseX, mouseY + this.getScrollY(), button)) || super.mouseClicked(mouseX, mouseY, button);
return checkTransportNF(mouseX, mouseY, button) || super.checkScrollbarDragged(mouseX, mouseY, button);
}
@Override

View file

@ -1,15 +1,15 @@
package themixray.repeating.mod.widget;
package ru.themixray.repeating_mod.widget;
import lombok.Getter;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Drawable;
import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.*;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import themixray.repeating.mod.Main;
import themixray.repeating.mod.RecordState;
import themixray.repeating.mod.RenderListener;
import themixray.repeating.mod.RepeatingScreen;
import net.minecraft.util.Formatting;
import ru.themixray.repeating_mod.Main;
import ru.themixray.repeating_mod.RecordState;
import ru.themixray.repeating_mod.RepeatingScreen;
import java.awt.*;
import java.io.IOException;
@ -19,6 +19,7 @@ import java.util.List;
import java.util.function.Consumer;
public class RecordWidget implements Drawable, Widget {
@Getter
private RecordState record;
private List<ClickableWidget> children;
@ -42,6 +43,13 @@ public class RecordWidget implements Drawable, Widget {
this.children = new ArrayList<>();
}
public boolean contains(int x, int y) {
return parent.getX() + getX() <= x &&
parent.getY() + getY() <= y &&
x <= parent.getX() + getX() + getWidth() &&
y <= parent.getY() + getY() + getHeight();
}
public void setX(int x) {
this.x = x;
}
@ -101,6 +109,11 @@ public class RecordWidget implements Drawable, Widget {
children.add(delete_button);
ButtonWidget export_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.export"), (i) -> {
try {
record.save();
} catch (IOException e) {
throw new RuntimeException(e);
}
if (Desktop.isDesktopSupported()) {
Desktop desk = Desktop.getDesktop();
try {
@ -112,41 +125,40 @@ public class RecordWidget implements Drawable, Widget {
throw new RuntimeException(ex);
}
}
} else {
Main.sendMessage(Text.literal("Record file is ").append(
Text.literal("["+record.getFile().getAbsolutePath()+"]").styled((s) -> s.withColor(Formatting.GRAY))));
}
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 14, 65, 13).build();
children.add(export_button);
ButtonWidget replay_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.start"), (i) -> {
ButtonWidget replay_button = ButtonWidget.builder(Text.translatable("text.repeating-mod." +
(getRecord().equals(Main.me.now_record) && Main.me.is_replaying ? "stop" : "start")), (i) -> {
if (Main.me.is_replaying) {
Main.me.stopReplay();
if (getRecord().equals(Main.me.now_record)) {
return;
}
}
i.setMessage(Text.translatable("text.repeating-mod.stop"));
Main.me.now_record = record;
Main.me.now_record = getRecord();
Main.me.startReplay();
Main.client.setScreen(null);
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 28, 65, 13)
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.replay_tooltip"))).build();
children.add(replay_button);
}
public RecordState getRecord() {
return record;
}
public void drawText(int x, int y, DrawContext ctx, List<Text> lines, float size, int line_height, boolean shadow) {
ctx.getMatrices().push();
ctx.getMatrices().scale(size, size, size);
public void drawText(int x, int y, DrawContext ctx, List<Text> lines, int line_height, boolean shadow) {
int now_y = y;
for (Text line : lines) {
ctx.drawText(Main.client.textRenderer, line, (int) (x / size), (int) (now_y / size), line.getStyle().getColor().getRgb(), shadow);
ctx.drawText(Main.client.textRenderer, line, x, now_y, 0xff000000 + line.getStyle().getColor().getRgb(), shadow);
now_y += line_height;
}
ctx.getMatrices().pop();
}
@Override
@ -171,7 +183,7 @@ public class RecordWidget implements Drawable, Widget {
.append(": ")
.styled((s) -> s.withColor(0xbbbbbb)),
Text.literal(record.getAuthor()).styled((s) -> s.withColor(0xffffff))
), 1,
),
9,
false);

View file

@ -1,32 +0,0 @@
package themixray.repeating.mod.event;
import net.minecraft.util.math.BlockPos;
import themixray.repeating.mod.Main;
public class RecordBlockBreakEvent extends RecordEvent {
public BlockPos pos;
public static RecordBlockBreakEvent fromArgs(String[] a) {
return new RecordBlockBreakEvent(new BlockPos(
Integer.parseInt(a[0]),
Integer.parseInt(a[1]),
Integer.parseInt(a[2])));
}
public RecordBlockBreakEvent(
BlockPos pos) {
this.pos = pos;
}
public void replay() {
Main.client.interactionManager.breakBlock(pos);
}
public String serialize() {
return "b=" + pos.getX() + "&" + pos.getY() + "&" + pos.getZ();
}
public String getType() {
return "block_break";
}
}

View file

@ -1,46 +0,0 @@
package themixray.repeating.mod.event;
import net.minecraft.util.Hand;
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 themixray.repeating.mod.Main;
public class RecordBlockInteractEvent extends RecordEvent {
public Hand hand;
public BlockHitResult hitResult;
public static RecordBlockInteractEvent fromArgs(String[] a) {
return new RecordBlockInteractEvent(
Hand.valueOf(a[5]),
new BlockHitResult(new Vec3d(
Double.parseDouble(a[0]),
Double.parseDouble(a[1]),
Double.parseDouble(a[2])),
Direction.byId(Integer.parseInt(a[4])),
new BlockPos(
Integer.parseInt(a[0]),
Integer.parseInt(a[1]),
Integer.parseInt(a[2])),
a[3].equals("1")));
}
public RecordBlockInteractEvent(Hand hand, BlockHitResult hitResult) {
this.hand = hand;
this.hitResult = hitResult;
}
public void replay() {
Main.client.interactionManager.interactBlock(Main.client.player, hand, hitResult);
}
public String serialize() {
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";
}
}

View file

@ -1,29 +0,0 @@
package themixray.repeating.mod.event;
public class RecordDelayEvent extends RecordEvent {
public long delay;
public static RecordDelayEvent fromArgs(String[] a) {
return new RecordDelayEvent(Long.parseLong(a[0]));
}
public RecordDelayEvent(long delay) {
this.delay = delay;
}
public void replay() {
try {
Thread.sleep(delay / 20 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String serialize() {
return "d=" + delay;
}
public String getType() {
return "delay";
}
}

View file

@ -1,28 +0,0 @@
package themixray.repeating.mod.event;
public abstract class RecordEvent {
public abstract void replay();
public abstract String serialize();
public abstract String getType();
public static RecordEvent deserialize(String t) {
try {
String type = String.valueOf(t.charAt(0));
String[] args = t.substring(2).split("&");
if (type.equals("d")) {
return RecordDelayEvent.fromArgs(args);
} else if (type.equals("m")) {
return RecordMoveEvent.fromArgs(args);
} else if (type.equals("p")) {
return RecordInputEvent.fromArgs(args);
} else if (type.equals("b")) {
return RecordBlockBreakEvent.fromArgs(args);
} else if (type.equals("i")) {
return RecordBlockInteractEvent.fromArgs(args);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View file

@ -1,147 +0,0 @@
package themixray.repeating.mod.event;
import themixray.repeating.mod.Main;
public class RecordInputEvent extends RecordEvent {
public Boolean sneaking;
public Boolean jumping;
public Boolean pressingForward;
public Boolean pressingBack;
public Boolean pressingLeft;
public Boolean pressingRight;
public Boolean sprinting;
public Float movementSideways;
public Float movementForward;
public float yaw;
public float head_yaw;
public float body_yaw;
public float pitch;
public float speed;
public static RecordInputEvent fromArgs(String[] a) {
return new RecordInputEvent(
(a[0].equals("n") ? null : a[0].equals("1")),
(a[1].equals("n") ? null : a[1].equals("1")),
(a[2].equals("n") ? null : Float.parseFloat(a[2])),
(a[3].equals("n") ? null : Float.parseFloat(a[3])),
(a[4].equals("n") ? null : a[4].equals("1")),
(a[5].equals("n") ? null : a[5].equals("1")),
(a[6].equals("n") ? null : a[6].equals("1")),
(a[7].equals("n") ? null : a[7].equals("1")),
Float.parseFloat(a[8]), Float.parseFloat(a[9]),
Float.parseFloat(a[10]),
(a[11].equals("n") ? null : a[11].equals("1")),
Float.parseFloat(a[12]),
Float.parseFloat(a[13]));
}
public RecordInputEvent(Boolean sneaking,
Boolean jumping,
Float movementSideways,
Float movementForward,
Boolean pressingForward,
Boolean pressingBack,
Boolean pressingLeft,
Boolean pressingRight,
float head_yaw,
float body_yaw,
float head_pitch,
Boolean sprinting,
float yaw,
float speed) {
this.sneaking = sneaking;
this.jumping = jumping;
this.movementSideways = movementSideways;
this.movementForward = movementForward;
this.pressingForward = pressingForward;
this.pressingBack = pressingBack;
this.pressingLeft = pressingLeft;
this.pressingRight = pressingRight;
this.head_yaw = head_yaw;
this.body_yaw = body_yaw;
this.pitch = head_pitch;
this.sprinting = sprinting;
this.yaw = yaw;
this.speed = speed;
}
public void fillEmpty(RecordInputEvent e) {
if (sneaking == null) sneaking = e.sneaking;
if (jumping == null) jumping = e.jumping;
if (movementSideways == null) movementSideways = e.movementSideways;
if (movementForward == null) movementForward = e.movementForward;
if (pressingForward == null) pressingForward = e.pressingForward;
if (pressingBack == null) pressingBack = e.pressingBack;
if (pressingLeft == null) pressingLeft = e.pressingLeft;
if (pressingRight == null) pressingRight = e.pressingRight;
if (sprinting == null) sprinting = e.sprinting;
}
public boolean isEmpty() {
return sneaking == null &&
jumping == null &&
movementSideways == null &&
movementForward == null &&
pressingForward == null &&
pressingBack == null &&
pressingLeft == null &&
pressingRight == null &&
sprinting == null;
}
public void replay() {
Main.input_replay = this;
}
public void inputCallback() {
if (sprinting != null && Main.client.player.isSprinting() != sprinting)
Main.client.player.setSprinting(sprinting);
if (Main.client.player.getYaw() != yaw)
Main.client.player.setYaw(yaw);
if (Main.client.player.getHeadYaw() != head_yaw)
Main.client.player.setHeadYaw(head_yaw);
if (Main.client.player.getBodyYaw() != body_yaw)
Main.client.player.setBodyYaw(body_yaw);
if (Main.client.player.getPitch() != pitch)
Main.client.player.setPitch(pitch);
if (Main.client.player.getMovementSpeed() != speed)
Main.client.player.setMovementSpeed(speed);
if (sneaking != null && Main.client.player.input.sneaking != sneaking)
Main.client.player.input.sneaking = sneaking;
if (jumping != null && Main.client.player.input.jumping != jumping)
Main.client.player.input.jumping = jumping;
if (movementSideways != null && Main.client.player.input.movementSideways != movementSideways)
Main.client.player.input.movementSideways = movementSideways;
if (movementForward != null && Main.client.player.input.movementForward != movementForward)
Main.client.player.input.movementForward = movementForward;
if (pressingForward != null && Main.client.player.input.pressingForward != pressingForward)
Main.client.player.input.pressingForward = pressingForward;
if (pressingBack != null && Main.client.player.input.pressingBack != pressingBack)
Main.client.player.input.pressingBack = pressingBack;
if (pressingLeft != null && Main.client.player.input.pressingLeft != pressingLeft)
Main.client.player.input.pressingLeft = pressingLeft;
if (pressingRight != null && Main.client.player.input.pressingRight != pressingRight)
Main.client.player.input.pressingRight = pressingRight;
}
public String serialize() {
return "p=" +
((sneaking == null) ? "n" : (sneaking ? "1" : "0")) + "&" +
((jumping == null) ? "n" : (jumping ? "1" : "0")) + "&" +
((movementSideways == null) ? "n" : movementSideways) + "&" +
((movementForward == null) ? "n" : movementForward) + "&" +
((pressingForward == null) ? "n" : (pressingForward ? "1" : "0")) + "&" +
((pressingBack == null) ? "n" : (pressingBack ? "1" : "0")) + "&" +
((pressingLeft == null) ? "n" : (pressingLeft ? "1" : "0")) + "&" +
((pressingRight == null) ? "n" : (pressingRight ? "1" : "0")) + "&" +
head_yaw + "&" + body_yaw + "&" + pitch + "&" +
((sprinting == null) ? "n" : (sprinting ? "1" : "0") +
"&" + yaw + "&" + speed);
}
public String getType() {
return "input";
}
}

View file

@ -1,42 +0,0 @@
package themixray.repeating.mod.event;
import net.minecraft.entity.MovementType;
import net.minecraft.util.math.Vec3d;
import themixray.repeating.mod.Main;
public class RecordMoveEvent extends RecordEvent {
public Vec3d vec;
public float yaw;
public float pitch;
public static RecordMoveEvent fromArgs(String[] a) {
return new RecordMoveEvent(new Vec3d(
Double.parseDouble(a[0]),
Double.parseDouble(a[1]),
Double.parseDouble(a[2])),
Float.parseFloat(a[3]),
Float.parseFloat(a[4]));
}
public RecordMoveEvent(Vec3d vec, float yaw, float pitch) {
this.vec = vec;
this.yaw = yaw;
this.pitch = pitch;
}
public void replay() {
Vec3d p = Main.client.player.getPos();
Vec3d v = new Vec3d(vec.getX() - p.getX(), vec.getY() - p.getY(), vec.getZ() - p.getZ());
Main.client.player.move(MovementType.SELF, v);
Main.client.player.setYaw(yaw);
Main.client.player.setPitch(pitch);
}
public String serialize() {
return "m=" + vec.getX() + "&" + vec.getY() + "&" + vec.getZ() + "&" + yaw + "&" + pitch;
}
public String getType() {
return "move";
}
}

View file

@ -1,29 +0,0 @@
package themixray.repeating.mod.mixin;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.network.listener.ServerPlayPacketListener;
import net.minecraft.network.packet.Packet;
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 java.time.Duration;
import java.util.function.BooleanSupplier;
@Mixin(ClientPlayNetworkHandler.class)
public abstract class NetworkMixin {
@Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V")
private void onSendPacket1Head(Packet<?> packet,
CallbackInfo ci) {
}
@Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V")
private void onSendPacket2Head(Packet<ServerPlayPacketListener> packet,
BooleanSupplier sendCondition,
Duration expirationTime,
CallbackInfo ci) {
}
}

View file

@ -13,13 +13,13 @@
"sources": "https://github.com/MeexReay/repeating-mod"
},
"license": "CC0-1.0",
"license": "WTFPL",
"icon": "icon.png",
"environment": "client",
"entrypoints": {
"client": [
"themixray.repeating.mod.Main"
"ru.themixray.repeating_mod.Main"
]
},
"mixins": [
@ -29,7 +29,7 @@
"depends": {
"fabricloader": ">=0.14.14",
"fabric-api": "*",
"minecraft": ">=1.20",
"minecraft": ">=1.21.4",
"java": ">=17"
},
"suggests": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

View file

@ -1,7 +1,7 @@
{
"required": true,
"minVersion": "0.8",
"package": "themixray.repeating.mod.mixin",
"package": "ru.themixray.repeating_mod.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
@ -10,7 +10,9 @@
"InputMixin",
"RendererMixin",
"EntityMixin",
"ClientMixin"
"ClientMixin",
"ScreenMixin",
"PlayerMixin"
],
"injectors": {
"defaultRequire": 1