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

@ -10,4 +10,4 @@ as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
0. You just DO WHAT THE FUCK YOU WANT TO.

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
}
}
@ -94,4 +79,4 @@ publishing {
// The repositories here will be used for publishing your artifact, not for
// retrieving dependencies.
}
}
}

View file

@ -1,17 +1,20 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
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
#Fabric api
fabric_version=0.92.1+1.20.1
# Mod Properties
mod_version = 1.1.0
maven_group = themixray.repeating.mod
archives_base_name = repeating-mod
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
org.gradle.parallel=true
# Fabric Properties
# check these on https://fabricmc.net/develop
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.127.0+1.21.6
# Mod Properties
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

View file

@ -1,10 +1,10 @@
pluginManagement {
repositories {
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
mavenCentral()
gradlePluginPortal()
}
}
repositories {
maven {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
mavenCentral()
gradlePluginPortal()
}
}

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,103 +1,103 @@
package themixray.repeating.mod;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.io.File;
public class EasyConfig {
public final Path path;
public final File file;
public Map<String,String> data;
public EasyConfig(File f, Map<String,String> def) {
this.path = f.toPath();
this.file = f;
this.data = new HashMap<>();
if (!file.exists()) {
try {
file.createNewFile();
write(def);
} catch (IOException e) {
e.printStackTrace();
}
}
reload();
for (Map.Entry<String,String> m:def.entrySet())
if (!data.containsKey(m.getKey()))
data.put(m.getKey(),m.getValue());
save();
}
public EasyConfig(Path f, Map<String,String> def) {
this(f.toFile(),def);
}
public EasyConfig(String parent,String child,Map<String,String> def) {
this(new File(parent,child),def);
}
public EasyConfig(File parent,String child,Map<String,String> def) {
this(new File(parent,child),def);
}
public EasyConfig(Path parent,String child,Map<String,String> def) {
this(new File(parent.toFile(),child),def);
}
public EasyConfig(File f) {
this(f,new HashMap<>());
}
public EasyConfig(Path path) {
this(path.toFile(),new HashMap<>());
}
public EasyConfig(String parent,String child) {
this(new File(parent,child),new HashMap<>());
}
public EasyConfig(File parent,String child) {
this(new File(parent,child),new HashMap<>());
}
public EasyConfig(Path parent,String child) {
this(new File(parent.toFile(),child),new HashMap<>());
}
public void reload() {
data = read();
}
public void save() {
write(data);
}
private String toText(Map<String,String> p) {
StringBuilder t = new StringBuilder();
for (Map.Entry<String,String> e:p.entrySet())
t.append(e.getKey()).append("=").append(e.getValue()).append("\n");
return t.toString();
}
private Map<String,String> toMap(String j) {
Map<String,String> m = new HashMap<>();
for (String l:j.split("\n")) {
String s[] = l.split("=");
m.put(s[0],s[1]);
}
return m;
}
private Map<String,String> read() {
try {
return toMap(Files.readString(path));
} catch (IOException e) {
e.printStackTrace();
}
return new HashMap<>();
}
private void write(Map<String,String> p) {
try {
Files.write(path, toText(p).getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
package ru.themixray.repeating_mod;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.io.File;
public class EasyConfig {
public final Path path;
public final File file;
public Map<String,String> data;
public EasyConfig(File f, Map<String,String> def) {
this.path = f.toPath();
this.file = f;
this.data = new HashMap<>();
if (!file.exists()) {
try {
file.createNewFile();
write(def);
} catch (IOException e) {
e.printStackTrace();
}
}
reload();
for (Map.Entry<String,String> m:def.entrySet())
if (!data.containsKey(m.getKey()))
data.put(m.getKey(),m.getValue());
save();
}
public EasyConfig(Path f, Map<String,String> def) {
this(f.toFile(),def);
}
public EasyConfig(String parent,String child,Map<String,String> def) {
this(new File(parent,child),def);
}
public EasyConfig(File parent,String child,Map<String,String> def) {
this(new File(parent,child),def);
}
public EasyConfig(Path parent,String child,Map<String,String> def) {
this(new File(parent.toFile(),child),def);
}
public EasyConfig(File f) {
this(f,new HashMap<>());
}
public EasyConfig(Path path) {
this(path.toFile(),new HashMap<>());
}
public EasyConfig(String parent,String child) {
this(new File(parent,child),new HashMap<>());
}
public EasyConfig(File parent,String child) {
this(new File(parent,child),new HashMap<>());
}
public EasyConfig(Path parent,String child) {
this(new File(parent.toFile(),child),new HashMap<>());
}
public void reload() {
data = read();
}
public void save() {
write(data);
}
private String toText(Map<String,String> p) {
StringBuilder t = new StringBuilder();
for (Map.Entry<String,String> e:p.entrySet())
t.append(e.getKey()).append("=").append(e.getValue()).append("\n");
return t.toString();
}
private Map<String,String> toMap(String j) {
Map<String,String> m = new HashMap<>();
for (String l:j.split("\n")) {
String s[] = l.split("=");
m.put(s[0],s[1]);
}
return m;
}
private Map<String,String> read() {
try {
return toMap(Files.readString(path));
} catch (IOException e) {
e.printStackTrace();
}
return new HashMap<>();
}
private void write(Map<String,String> p) {
try {
Files.write(path, toText(p).getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}

View file

@ -1,326 +1,309 @@
package themixray.repeating.mod;
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.client.rendering.v1.WorldRenderEvents;
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.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
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 java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
public class Main 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 Main me;
public RecordList record_list;
public RecordState now_record;
public boolean is_recording = false;
public long last_record = -1;
public TickTask move_tick = null;
public TickTask replay_tick = null;
public boolean is_replaying = false;
public boolean loop_replay = false;
public static RecordInputEvent input_replay = null;
public long living_ticks = 0;
public static RepeatingScreen menu;
private static KeyBinding menu_key;
private static KeyBinding toggle_replay_key;
private static KeyBinding toggle_record_key;
public long record_pos_delay = 20;
public static Random rand = new Random();
public EasyConfig conf;
public File records_folder;
@Override
public void onInitializeClient() {
LOGGER.info("Repeating mod initialized");
me = this;
now_record = null;
records_folder = new File(FabricLoader.getInstance().getGameDir().toFile(),"repeating_mod_records");
if (!records_folder.exists()) records_folder.mkdir();
record_list = new RecordList(records_folder);
record_list.loadRecords();
RenderSystem.init();
WorldRenderEvents.LAST.register(context -> {
WorldBuffer buffer = RenderHelper.startTri(context);
if (now_record != null) {
Vec3d start_pos = now_record.getStartRecordPos();
Vec3d finish_pos = now_record.getFinishRecordPos();
if (start_pos != null) drawRecordPos(buffer, start_pos, new Color(70, 230, 70, 128));
if (finish_pos != null) drawRecordPos(buffer, finish_pos, new Color(230, 70, 70, 128));
}
RenderHelper.endTri(buffer);
});
Map<String,String> def = new HashMap<>();
def.put("record_pos_delay", String.valueOf(record_pos_delay));
conf = new EasyConfig(loader.getConfigDir(),"repeating-mod",def);
record_pos_delay = Long.parseLong(conf.data.get("record_pos_delay"));
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 (now_record != null) {
if (!is_recording) {
if (is_replaying)
stopReplay();
else startReplay();
menu.updateButtons();
}
}
}
if (toggle_record_key.wasPressed()) {
if (!is_replaying) {
if (is_recording)
stopRecording();
else startRecording();
menu.updateButtons();
}
}
});
new TickTask(0,0) {
@Override
public void run() {
living_ticks++;
}
};
System.setProperty("java.awt.headless", "false");
}
public void setNowRecord(RecordState record) {
now_record = record;
}
public void drawRecordPos(WorldBuffer buffer, Vec3d pos, Color color) {
RenderHelper.drawRectFromTri(buffer,
(float) pos.getX() - 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() - 0.25F,
(float) pos.getX() + 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() - 0.25F,
(float) pos.getX() + 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() + 0.25F,
(float) pos.getX() - 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() + 0.25F,
color);
}
public void startRecording() {
is_recording = true;
menu.updateButtons();
now_record = record_list.newRecord();
Vec3d start_pos = client.player.getPos();
now_record.addEvent(new RecordMoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch()));
now_record.setStartRecordPos(start_pos);
if (record_pos_delay > 0) {
move_tick = new TickTask(
record_pos_delay,
record_pos_delay) {
@Override
public void run() {
now_record.addEvent(new RecordMoveEvent(client.player.getPos(),
client.player.getHeadYaw(), client.player.getPitch()));
}
};
}
sendMessage(Text.translatable("message.repeating-mod.record_start"));
}
public void recordTick(RecordEvent e) {
if (is_recording) {
long now = living_ticks;
if (last_record != -1) {
long diff = now - last_record - 2;
if (diff > 0) now_record.addEvent(new RecordDelayEvent(diff));
}
now_record.addEvent(e);
last_record = now;
}
}
public void recordAllInput() {
if (client.player == null) {
stopRecording();
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());
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);
}
}
}
public void stopRecording() {
is_recording = false;
now_record.setFinishRecordPos(client.player.getPos());
try {
now_record.save();
} catch (IOException e) {
throw new RuntimeException(e);
}
if (move_tick != null) {
move_tick.cancel();
move_tick = null;
}
menu.updateButtons();
last_record = -1;
sendMessage(Text.translatable("message.repeating-mod.record_stop"));
}
public void startReplay() {
is_recording = false;
is_replaying = true;
menu.updateButtons();
List<RecordEvent> events = now_record.getEvents();
replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_TAIL) {
public int replay_index = 0;
@Override
public void run() {
if (!is_replaying) cancel();
RecordEvent e = events.get(replay_index);
if (e instanceof RecordDelayEvent) {
setDelay(((RecordDelayEvent) e).delay);
} else {
e.replay();
}
replay_index++;
if (!loop_replay) {
if (replay_index == events.size()) {
stopReplay();
cancel();
}
} else if (replay_index == events.size()) {
replay_index = 0;
}
}
};
sendMessage(Text.translatable("message.repeating-mod.replay_start"));
}
public void stopReplay() {
is_recording = false;
is_replaying = false;
if (replay_tick != null) {
replay_tick.cancel();
replay_tick = null;
}
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"));
}
public static void sendMessage(MutableText text) {
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)));
}
public static void sendDebug(String s) {
client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s)));
}
}
package ru.themixray.repeating_mod;
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.client.rendering.v1.WorldRenderEvents;
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.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.math.Vec3d;
import org.lwjgl.glfw.GLFW;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import java.io.IOException;
import java.util.*;
import java.util.List;
public class Main 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 Main me;
public RecordList record_list;
public RecordState now_record;
public boolean is_recording = false;
public long last_record = -1;
public TickTask move_tick = null;
public TickTask replay_tick = null;
public boolean is_replaying = false;
public boolean loop_replay = false;
public static InputEvent input_replay = null;
public long living_ticks = 0;
public static RepeatingScreen menu;
private static KeyBinding menu_key;
private static KeyBinding toggle_replay_key;
private static KeyBinding toggle_record_key;
public long record_pos_delay = -1;
public static Random rand = new Random();
public EasyConfig conf;
public File records_folder;
@Override
public void onInitializeClient() {
LOGGER.info("Repeating mod initialized");
me = this;
now_record = null;
records_folder = new File(FabricLoader.getInstance().getGameDir().toFile(),"repeating_mod_records");
if (!records_folder.exists()) records_folder.mkdir();
record_list = new RecordList(records_folder);
record_list.loadRecords();
RenderSystem.init();
WorldRenderEvents.AFTER_ENTITIES.register(context -> {
WorldBuffer buffer = RenderHelper.startTri(context);
if (now_record != null) {
Vec3d start_pos = now_record.getStartRecordPos();
Vec3d finish_pos = now_record.getFinishRecordPos();
if (start_pos != null) drawRecordPos(buffer, start_pos, new Color(70, 230, 70, 128));
if (finish_pos != null) drawRecordPos(buffer, finish_pos, new Color(230, 70, 70, 128));
}
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));
conf = new EasyConfig(loader.getConfigDir(),"repeating-mod",def);
record_pos_delay = Long.parseLong(conf.data.get("record_pos_delay"));
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 (now_record != null) {
if (!is_recording) {
if (is_replaying)
stopReplay();
else startReplay();
menu.updateButtons();
}
}
}
if (toggle_record_key.wasPressed()) {
if (!is_replaying) {
if (is_recording)
stopRecording();
else startRecording();
menu.updateButtons();
}
}
});
new TickTask(0,0) {
@Override
public void run() {
living_ticks++;
}
};
System.setProperty("java.awt.headless", "false");
}
public void setNowRecord(RecordState record) {
now_record = record;
}
public void drawRecordPos(WorldBuffer buffer, Vec3d pos, Color color) {
RenderHelper.drawRectFromTri(buffer,
(float) pos.getX() - 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() - 0.25F,
(float) pos.getX() + 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() - 0.25F,
(float) pos.getX() + 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() + 0.25F,
(float) pos.getX() - 0.25F,
(float) pos.getY() + 0.01F,
(float) pos.getZ() + 0.25F,
color);
}
public void startRecording() {
is_recording = true;
menu.updateButtons();
now_record = record_list.newRecord();
Vec3d start_pos = client.player.getPos();
recordTick(new MoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch()));
now_record.setStartRecordPos(start_pos);
if (record_pos_delay > 0) {
move_tick = new TickTask(
record_pos_delay,
record_pos_delay) {
@Override
public void run() {
recordTick(new MoveEvent(client.player.getPos(),
client.player.getHeadYaw(), client.player.getPitch()));
}
};
}
sendMessage(Text.translatable("message.repeating-mod.record_start"));
}
public void recordTick(RecordEvent e) {
if (is_recording) {
long now = living_ticks;
if (last_record != -1) {
long diff = now - last_record - 2;
if (diff > 0) now_record.addEvent(new DelayEvent(diff));
}
now_record.addEvent(e);
last_record = now;
}
}
public void recordAllInput() {
if (client.player == null) {
stopRecording();
return;
}
InputEvent curr = InputEvent.current();
if (curr == null) return;
InputEvent last = ((InputEvent) now_record.getLastEvent("input"));
if (last == null) {
recordTick(curr);
} else if (!curr.equals(last)) {
recordTick(curr.differs(last));
}
}
public void stopRecording() {
is_recording = false;
now_record.setFinishRecordPos(client.player.getPos());
try {
now_record.save();
} catch (IOException e) {
throw new RuntimeException(e);
}
if (move_tick != null) {
move_tick.cancel();
move_tick = null;
}
menu.updateButtons();
last_record = -1;
sendMessage(Text.translatable("message.repeating-mod.record_stop"));
}
public void startReplay() {
is_recording = false;
is_replaying = true;
menu.updateButtons();
List<RecordEvent> events = now_record.getEvents();
replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_EVENT) {
public int replay_index = 0;
@Override
public void run() {
if (!is_replaying) {
cancel();
return;
}
RecordEvent e = events.get(replay_index);
if (e != null) {
if (e instanceof DelayEvent) {
setDelay(((DelayEvent) e).delay);
} else {
e.replay();
}
}
replay_index++;
if (!loop_replay) {
if (replay_index >= events.size()) {
stopReplay();
cancel();
}
} else if (replay_index >= events.size()) {
replay_index = 0;
}
}
};
sendMessage(Text.translatable("message.repeating-mod.replay_start"));
}
public void stopReplay() {
is_recording = false;
is_replaying = false;
if (replay_tick != null) {
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"));
}
public static void sendMessage(MutableText text) {
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)), false);
}
// 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,193 +1,187 @@
package themixray.repeating.mod;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
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.Screen;
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 java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@Environment(EnvType.CLIENT)
public class RepeatingScreen extends Screen {
private static List<RenderListener> render_listeners = new ArrayList<>();
public ButtonWidget record_btn;
public ButtonWidget loop_btn;
public ButtonWidget import_btn;
public SliderWidget pos_delay_slider;
public boolean was_build = false;
protected RepeatingScreen() {
super(Text.empty());
}
public static void addRenderListener(RenderListener render) {
render_listeners.add(render);
}
public static void removeRenderListener(RenderListener render) {
render_listeners.remove(render);
}
public void updateButtons() {
if (was_build) {
record_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.is_recording) ? "stop_record" : "start_record")));
loop_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.loop_replay) ? "off_loop" : "on_loop")));
}
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
renderBackground(context);
for (RenderListener l : render_listeners) {
if (l.beforeRender()) {
l.render(context, mouseX, mouseY, delta);
}
}
super.render(context, mouseX, mouseY, delta);
for (RenderListener l : render_listeners) {
if (!l.beforeRender()) {
l.render(context, mouseX, mouseY, delta);
}
}
}
@Override
protected void init() {
RecordListWidget list_widget = Main.me.record_list.getWidget();
list_widget.setX(width / 2 + 2);
list_widget.setY(height / 2 - list_widget.getHeight() / 2);
list_widget.init(this);
record_btn = ButtonWidget.builder(
Text.translatable("text.repeating-mod.start_record"), button -> {
if (!Main.me.is_replaying) {
if (Main.me.is_recording)
Main.me.stopRecording();
else Main.me.startRecording();
updateButtons();
}
})
.dimensions(width / 2 - 120, height / 2 - 32, 120, 20)
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.record_tooltip")))
.build();
loop_btn = ButtonWidget.builder(Text.empty(), button -> {
Main.me.loop_replay = !Main.me.loop_replay;
updateButtons();
})
.dimensions(width / 2 - 120, height / 2 - 10, 120, 20)
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.loop_tooltip")))
.build();
pos_delay_slider = new SliderWidget(
width / 2 - 120, height / 2 + 12, 120, 20,
(Main.me.record_pos_delay < 0) ? Text.translatable("text.repeating-mod.nan_pos_delay") :
Text.translatable("text.repeating-mod.pos_delay", String.valueOf(Main.me.record_pos_delay)),
(Main.me.record_pos_delay+1d)/101d) {
@Override
protected void updateMessage() {
double v = value*101d-1d;
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
}
@Override
protected void applyValue() {
double v = value*101d-1d;
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
Main.me.record_pos_delay = (long) v;
Main.me.conf.data.put("record_pos_delay",String.valueOf(Main.me.record_pos_delay));
Main.me.conf.save();
}
@Override
public void onRelease(double mouseX, double mouseY) {
super.onRelease(mouseX, mouseY);
applyValue();
}
@Override
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) {
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")));
import_btn = ButtonWidget.builder(Text.translatable("text.repeating-mod.import"), button -> {
new Thread(() -> {
FileDialog fd = new FileDialog((java.awt.Frame) null);
fd.setMultipleMode(true);
fd.setName("Choose record files");
fd.setTitle("Choose record files");
fd.setFilenameFilter((dir, name) -> name.endsWith(".rrm"));
fd.setVisible(true);
File[] files = fd.getFiles();
if (files != null) {
for (File file : files) {
try {
Main.me.record_list.addRecord(file);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}}).start();
})
.dimensions(width / 2 + 2, height / 2 - list_widget.getHeight() / 2 - 22, 180, 20)
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.import_tooltip")))
.build();
was_build = true;
updateButtons();
addDrawableChild(loop_btn);
addDrawableChild(record_btn);
addDrawableChild(import_btn);
addDrawableChild(pos_delay_slider);
}
public <T extends Element & Drawable & Selectable> T addDrawableChild(T drawableElement) {
return super.addDrawableChild(drawableElement);
}
public <T extends Drawable> T addDrawable(T drawable) {
return super.addDrawable(drawable);
}
public <T extends Element & Selectable> T addSelectableChild(T child) {
return super.addSelectableChild(child);
}
public void remove(Element child) {
super.remove(child);
}
}
package ru.themixray.repeating_mod;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
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.Screen;
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 ru.themixray.repeating_mod.widget.RecordListWidget;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@Environment(EnvType.CLIENT)
public class RepeatingScreen extends Screen {
private static List<RenderListener> render_listeners = new ArrayList<>();
public ButtonWidget record_btn;
public ButtonWidget loop_btn;
public ButtonWidget import_btn;
public SliderWidget pos_delay_slider;
public boolean was_build = false;
protected RepeatingScreen() {
super(Text.empty());
}
public static void addRenderListener(RenderListener render) {
render_listeners.add(render);
}
public static void removeRenderListener(RenderListener render) {
render_listeners.remove(render);
}
public void updateButtons() {
if (was_build) {
record_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.is_recording) ? "stop_record" : "start_record")));
loop_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.loop_replay) ? "off_loop" : "on_loop")));
}
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
// renderBackground(context, mouseX, mouseY, delta);
for (RenderListener l : render_listeners) {
if (l.beforeRender()) {
l.render(context, mouseX, mouseY, delta);
}
}
super.render(context, mouseX, mouseY, delta);
for (RenderListener l : render_listeners) {
if (!l.beforeRender()) {
l.render(context, mouseX, mouseY, delta);
}
}
}
@Override
protected void init() {
RecordListWidget list_widget = Main.me.record_list.getWidget();
list_widget.setX(width / 2 + 2);
list_widget.setY(height / 2 - list_widget.getHeight() / 2);
list_widget.init(this);
record_btn = ButtonWidget.builder(
Text.translatable("text.repeating-mod.start_record"), button -> {
if (!Main.me.is_replaying) {
if (Main.me.is_recording)
Main.me.stopRecording();
else Main.me.startRecording();
updateButtons();
}
})
.dimensions(width / 2 - 120, height / 2 - 32, 120, 20)
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.record_tooltip")))
.build();
loop_btn = ButtonWidget.builder(Text.empty(), button -> {
Main.me.loop_replay = !Main.me.loop_replay;
updateButtons();
})
.dimensions(width / 2 - 120, height / 2 - 10, 120, 20)
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.loop_tooltip")))
.build();
pos_delay_slider = new SliderWidget(
width / 2 - 120, height / 2 + 12, 120, 20,
(Main.me.record_pos_delay < 0) ? Text.translatable("text.repeating-mod.nan_pos_delay") :
Text.translatable("text.repeating-mod.pos_delay", String.valueOf(Main.me.record_pos_delay)),
(Main.me.record_pos_delay+1d)/101d) {
@Override
protected void updateMessage() {
double v = value*101d-1d;
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
}
@Override
protected void applyValue() {
double v = value*101d-1d;
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
Main.me.record_pos_delay = (long) v;
Main.me.conf.data.put("record_pos_delay",String.valueOf(Main.me.record_pos_delay));
Main.me.conf.save();
}
@Override
public void onRelease(double mouseX, double mouseY) {
super.onRelease(mouseX, mouseY);
applyValue();
}
@Override
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) {
super.onDrag(mouseX, mouseY, deltaX, deltaY);
applyValue();
}
};
pos_delay_slider.setTooltip(Tooltip.of(Text.translatable("text.repeating-mod.pos_delay_tooltip")));
import_btn = ButtonWidget.builder(Text.translatable("text.repeating-mod.import"), button -> {
new Thread(() -> {
FileDialog fd = new FileDialog((java.awt.Frame) null);
fd.setMultipleMode(true);
fd.setName("Choose record files");
fd.setTitle("Choose record files");
fd.setFilenameFilter((dir, name) -> name.endsWith(".rrm"));
fd.setVisible(true);
File[] files = fd.getFiles();
if (files != null) {
for (File file : files) {
try {
Main.me.setNowRecord(Main.me.record_list.cloneRecord(file));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}}).start();
})
.dimensions(width / 2 + 2, height / 2 - list_widget.getHeight() / 2 - 22, 180, 20)
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.import_tooltip")))
.build();
was_build = true;
updateButtons();
addDrawableChild(loop_btn);
addDrawableChild(record_btn);
addDrawableChild(import_btn);
addDrawableChild(pos_delay_slider);
}
public <T extends Element & Drawable & Selectable> T addDrawableChild(T drawableElement) {
return super.addDrawableChild(drawableElement);
}
public <T extends Drawable> T addDrawable(T drawable) {
return super.addDrawable(drawable);
}
public <T extends Element & Selectable> T addSelectableChild(T child) {
return super.addSelectableChild(child);
}
public void remove(Element child) {
super.remove(child);
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -1,44 +1,44 @@
package themixray.repeating.mod.mixin;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.hit.HitResult;
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;
@Mixin(ClientPlayerEntity.class)
public abstract class MovementMixin {
@Inject(at = @At(value = "HEAD"), method = "init")
private void init(CallbackInfo ci) {
PlayerBlockBreakEvents.AFTER.register((world, player, pos, blockState, blockEntity) -> {
if (Main.me.is_recording)
Main.me.recordTick(new RecordBlockBreakEvent(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));
return ActionResult.PASS;
});
}
@Inject(at = @At(value = "HEAD"), method = "tickMovement")
private void onMoveHead(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_HEAD);
}
@Inject(at = @At(value = "TAIL"), method = "tick")
private void onMoveTail(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_TAIL);
}
}
package ru.themixray.repeating_mod.mixin;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.hit.HitResult;
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;
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 {
@Inject(at = @At(value = "HEAD"), method = "init")
private void init(CallbackInfo ci) {
PlayerBlockBreakEvents.AFTER.register((world, player, pos, blockState, blockEntity) -> {
if (Main.me.is_recording)
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 BlockInteractEvent(hand,hitResult));
return ActionResult.PASS;
});
}
@Inject(at = @At(value = "HEAD"), method = "tickMovement")
private void onMoveHead(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_HEAD);
}
@Inject(at = @At(value = "TAIL"), method = "tick")
private void onMoveTail(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_TAIL);
}
}

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,21 +1,21 @@
package 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;
@Mixin(GameRenderer.class)
public abstract class RendererMixin {
@Inject(at = @At(value = "HEAD"), method = "tick")
private void onTickHead(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.RENDER_HEAD);
}
@Inject(at = @At(value = "TAIL"), method = "tick")
private void onTickTail(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.RENDER_TAIL);
}
}
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 ru.themixray.repeating_mod.TickTask;
@Mixin(GameRenderer.class)
public abstract class RendererMixin {
@Inject(at = @At(value = "HEAD"), method = "tick")
private void onTickHead(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.RENDER_HEAD);
}
@Inject(at = @At(value = "TAIL"), method = "tick")
private void onTickTail(CallbackInfo ci) {
TickTask.tickTasks(TickTask.TickAt.RENDER_TAIL);
}
}

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

@ -1,17 +1,17 @@
{
"providers": [
{
"file":"repeating-mod:ui/no-loop.png",
"chars":["\ueffe"],
"height":16,
"ascent":12,
"type":"bitmap"
},{
"file":"repeating-mod:ui/loop.png",
"chars":["\uefff"],
"height":16,
"ascent":12,
"type":"bitmap"
}
]
{
"providers": [
{
"file":"repeating-mod:ui/no-loop.png",
"chars":["\ueffe"],
"height":16,
"ascent":12,
"type":"bitmap"
},{
"file":"repeating-mod:ui/loop.png",
"chars":["\uefff"],
"height":16,
"ascent":12,
"type":"bitmap"
}
]
}

View file

@ -1,36 +1,36 @@
{
"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.start_record": "Start record",
"text.repeating-mod.stop_record": "Stop record",
"text.repeating-mod.start_replay": "Start replay",
"text.repeating-mod.stop_replay": "Stop replay",
"text.repeating-mod.record_tooltip": "Start/stop recording all activities",
"text.repeating-mod.replay_tooltip": "Start/stop repeating recorded actions",
"text.repeating-mod.loop_tooltip": "Enable/disable repeating of recorded actions replay",
"text.repeating-mod.export_record": "Export record",
"text.repeating-mod.import": "Import record",
"text.repeating-mod.export_tooltip": "Exporting a recording to a file",
"text.repeating-mod.import_tooltip": "Importing a recording from a file",
"text.repeating-mod.dev": "In development...",
"text.repeating-mod.nan_pos_delay": "No pos timer",
"text.repeating-mod.pos_delay": "Pos timer: %s ticks",
"text.repeating-mod.pos_delay_tooltip": "Timer after which the pos\nevent is added (20 ticks = 1 sec)",
"text.repeating-mod.unnamed": "Unnamed Record",
"text.repeating-mod.on_loop": "Enable repeat",
"text.repeating-mod.off_loop": "Disable repeat",
"text.repeating-mod.recorded_at": "Recorded at",
"text.repeating-mod.author": "Author",
"text.repeating-mod.delete": "Delete",
"text.repeating-mod.start": "Start",
"text.repeating-mod.stop": "Stop",
"text.repeating-mod.export": "Export",
"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"
{
"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.start_record": "Start record",
"text.repeating-mod.stop_record": "Stop record",
"text.repeating-mod.start_replay": "Start replay",
"text.repeating-mod.stop_replay": "Stop replay",
"text.repeating-mod.record_tooltip": "Start/stop recording all activities",
"text.repeating-mod.replay_tooltip": "Start/stop repeating recorded actions",
"text.repeating-mod.loop_tooltip": "Enable/disable repeating of recorded actions replay",
"text.repeating-mod.export_record": "Export record",
"text.repeating-mod.import": "Import record",
"text.repeating-mod.export_tooltip": "Exporting a recording to a file",
"text.repeating-mod.import_tooltip": "Importing a recording from a file",
"text.repeating-mod.dev": "In development...",
"text.repeating-mod.nan_pos_delay": "No pos timer",
"text.repeating-mod.pos_delay": "Pos timer: %s ticks",
"text.repeating-mod.pos_delay_tooltip": "Timer after which the pos\nevent is added (20 ticks = 1 sec)",
"text.repeating-mod.unnamed": "Unnamed Record",
"text.repeating-mod.on_loop": "Enable repeat",
"text.repeating-mod.off_loop": "Disable repeat",
"text.repeating-mod.recorded_at": "Recorded at",
"text.repeating-mod.author": "Author",
"text.repeating-mod.delete": "Delete",
"text.repeating-mod.start": "Start",
"text.repeating-mod.stop": "Stop",
"text.repeating-mod.export": "Export",
"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"
}

View file

@ -1,38 +1,38 @@
{
"key.repeating-mod.menu": "Меню репитинга",
"key.repeating-mod.toggle_replay": "Вкл/выкл повтор",
"key.repeating-mod.toggle_record": "Вкл/выкл запись",
"text.repeating-mod.name": "Репитинг Мод",
"text.repeating-mod.start_record": "Начать запись",
"text.repeating-mod.stop_record": "Остановить запись",
"text.repeating-mod.start_replay": "Начать повтор",
"text.repeating-mod.stop_replay": "Остановить повтор",
"text.repeating-mod.record_tooltip": "Начать/остановить запись всех действий",
"text.repeating-mod.replay_tooltip": "Начать/остановить повтор записанных действий",
"text.repeating-mod.loop_tooltip": "Вкл/выкл повтор записи",
"text.repeating-mod.import": "Импорт записи",
"text.repeating-mod.export_tooltip": "Экспорт записи в файл",
"text.repeating-mod.import_tooltip": "Импорт записи из файла",
"text.repeating-mod.dev": "В разработке...",
"text.repeating-mod.nan_pos_delay": "Таймера позиции нету",
"text.repeating-mod.pos_delay": "Таймер позиции: %s тиков",
"text.repeating-mod.pos_delay_tooltip": "Таймер, после которой добавляется\nивент позиции (20 тиков = 1 сек)",
"text.repeating-mod.unnamed": "Безымянная Запись",
"text.repeating-mod.on_loop": "Включить повторение",
"text.repeating-mod.off_loop": "Выключить повторение",
"text.repeating-mod.recorded_at": "Записано в",
"text.repeating-mod.author": "Автор",
"message.repeating-mod.replay_start": "Повтор начат",
"message.repeating-mod.replay_stop": "Повтор закончен",
"message.repeating-mod.record_start": "Запись начата",
"message.repeating-mod.record_stop": "Запись закончена",
"text.repeating-mod.export_record": "Экпорт записи",
"text.repeating-mod.export": "Экспорт",
"text.repeating-mod.delete": "Удалить",
"text.repeating-mod.start": "Старт",
"text.repeating-mod.stop": "Стоп"
}
{
"key.repeating-mod.menu": "Меню репитинга",
"key.repeating-mod.toggle_replay": "Вкл/выкл повтор",
"key.repeating-mod.toggle_record": "Вкл/выкл запись",
"text.repeating-mod.name": "Репитинг Мод",
"text.repeating-mod.start_record": "Начать запись",
"text.repeating-mod.stop_record": "Остановить запись",
"text.repeating-mod.start_replay": "Начать повтор",
"text.repeating-mod.stop_replay": "Остановить повтор",
"text.repeating-mod.record_tooltip": "Начать/остановить запись всех действий",
"text.repeating-mod.replay_tooltip": "Начать/остановить повтор записанных действий",
"text.repeating-mod.loop_tooltip": "Вкл/выкл повтор записи",
"text.repeating-mod.import": "Импорт записи",
"text.repeating-mod.export_tooltip": "Экспорт записи в файл",
"text.repeating-mod.import_tooltip": "Импорт записи из файла",
"text.repeating-mod.dev": "В разработке...",
"text.repeating-mod.nan_pos_delay": "Таймера позиции нету",
"text.repeating-mod.pos_delay": "Таймер позиции: %s тиков",
"text.repeating-mod.pos_delay_tooltip": "Таймер, после которой добавляется\nивент позиции (20 тиков = 1 сек)",
"text.repeating-mod.unnamed": "Безымянная Запись",
"text.repeating-mod.on_loop": "Включить повторение",
"text.repeating-mod.off_loop": "Выключить повторение",
"text.repeating-mod.recorded_at": "Записано в",
"text.repeating-mod.author": "Автор",
"message.repeating-mod.replay_start": "Повтор начат",
"message.repeating-mod.replay_stop": "Повтор закончен",
"message.repeating-mod.record_start": "Запись начата",
"message.repeating-mod.record_stop": "Запись закончена",
"text.repeating-mod.export_record": "Экпорт записи",
"text.repeating-mod.export": "Экспорт",
"text.repeating-mod.delete": "Удалить",
"text.repeating-mod.start": "Старт",
"text.repeating-mod.stop": "Стоп"
}

View file

@ -1,38 +1,38 @@
{
"schemaVersion": 1,
"id": "repeating-mod",
"version": "${version}",
"name": "Repeating Mod",
"description": "Mod that repeats your recorded actions. ",
"authors": [
"TheMixRay"
],
"contact": {
"homepage": "https://modrinth.com/mod/repeating-mod",
"sources": "https://github.com/MeexReay/repeating-mod"
},
"license": "CC0-1.0",
"icon": "icon.png",
"environment": "client",
"entrypoints": {
"client": [
"themixray.repeating.mod.Main"
]
},
"mixins": [
"repeating-mod.mixins.json"
],
"depends": {
"fabricloader": ">=0.14.14",
"fabric-api": "*",
"minecraft": ">=1.20",
"java": ">=17"
},
"suggests": {
"another-mod": "*"
}
}
{
"schemaVersion": 1,
"id": "repeating-mod",
"version": "${version}",
"name": "Repeating Mod",
"description": "Mod that repeats your recorded actions. ",
"authors": [
"TheMixRay"
],
"contact": {
"homepage": "https://modrinth.com/mod/repeating-mod",
"sources": "https://github.com/MeexReay/repeating-mod"
},
"license": "WTFPL",
"icon": "icon.png",
"environment": "client",
"entrypoints": {
"client": [
"ru.themixray.repeating_mod.Main"
]
},
"mixins": [
"repeating-mod.mixins.json"
],
"depends": {
"fabricloader": ">=0.14.14",
"fabric-api": "*",
"minecraft": ">=1.21.4",
"java": ">=17"
},
"suggests": {
"another-mod": "*"
}
}

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,18 +1,20 @@
{
"required": true,
"minVersion": "0.8",
"package": "themixray.repeating.mod.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"client": [
"MovementMixin",
"InputMixin",
"RendererMixin",
"EntityMixin",
"ClientMixin"
],
"injectors": {
"defaultRequire": 1
}
}
{
"required": true,
"minVersion": "0.8",
"package": "ru.themixray.repeating_mod.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"client": [
"MovementMixin",
"InputMixin",
"RendererMixin",
"EntityMixin",
"ClientMixin",
"ScreenMixin",
"PlayerMixin"
],
"injectors": {
"defaultRequire": 1
}
}