From 41706ade8010fa60982d9681839252bc3eb9c39a Mon Sep 17 00:00:00 2001 From: MeexReay <127148610+MeexReay@users.noreply.github.com> Date: Fri, 26 Apr 2024 20:08:14 +0300 Subject: [PATCH 01/29] Update README.md --- README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index e2be31c..f63c38a 100644 --- a/README.md +++ b/README.md @@ -23,14 +23,7 @@ How menu looks like ## Todo Releases dont have striked lines -- ~~fix "Space in record name deletes record 0_0"~~ -- ~~fix "Save record (edit name) on recording crashes the game"~~ -- ~~select record on click (you can see start and finish points when its selected)~~ -- ~~select record on import~~ -- ~~change icon in mod menu to new one~~ -- ~~fix "Crashes the game when leaving world while record is replaying"~~ -- ~~copy file to record list when import~~ -- record gui mouse clicks and key pressing +- record gui mouse clicks and key pressing (in dev) - create new preview.gif - practice mode like in geometry dash for parkours From cc12eab00619f6470b9c3f4914ef1274cb44cfe9 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sun, 8 Dec 2024 02:39:49 +0300 Subject: [PATCH 02/29] wh --- gradle.properties | 32 +- gradlew.bat | 184 ++--- .../themixray/repeating/mod/EasyConfig.java | 103 --- remappedSrc/themixray/repeating/mod/Main.java | 325 --------- .../themixray/repeating/mod/RecordList.java | 77 -- .../themixray/repeating/mod/RecordState.java | 169 ----- .../repeating/mod/RenderListener.java | 11 - .../repeating/mod/RepeatingScreen.java | 193 ----- .../themixray/repeating/mod/TickTask.java | 94 --- .../mod/event/RecordBlockBreakEvent.java | 32 - .../mod/event/RecordBlockInteractEvent.java | 46 -- .../repeating/mod/event/RecordDelayEvent.java | 29 - .../repeating/mod/event/RecordEvent.java | 28 - .../repeating/mod/event/RecordInputEvent.java | 147 ---- .../repeating/mod/event/RecordMoveEvent.java | 42 -- .../repeating/mod/mixin/ClientMixin.java | 24 - .../repeating/mod/mixin/EntityMixin.java | 31 - .../repeating/mod/mixin/InputMixin.java | 20 - .../repeating/mod/mixin/MovementMixin.java | 44 -- .../repeating/mod/mixin/NetworkMixin.java | 29 - .../repeating/mod/mixin/RendererMixin.java | 21 - .../repeating/mod/render/RenderHelper.java | 200 ------ .../repeating/mod/render/RenderSystem.java | 13 - .../mod/render/buffer/BufferManager.java | 48 -- .../repeating/mod/render/buffer/Vertex.java | 30 - .../mod/render/buffer/WorldBuffer.java | 82 --- .../repeating/mod/render/shader/Shader.java | 42 -- .../mod/render/shader/ShaderManager.java | 97 --- .../mod/widget/RecordListWidget.java | 150 ---- .../repeating/mod/widget/RecordWidget.java | 196 ----- .../themixray/repeating/mod/EasyConfig.java | 206 +++--- .../java/themixray/repeating/mod/Main.java | 680 +++++++++--------- .../themixray/repeating/mod/RecordList.java | 1 + .../themixray/repeating/mod/RecordState.java | 6 +- .../repeating/mod/RepeatingScreen.java | 374 +++++----- .../themixray/repeating/mod/TickTask.java | 190 ++--- .../mod/event/events/GuiMouseScrollEvent.java | 2 +- .../repeating/mod/mixin/ClientMixin.java | 48 +- .../repeating/mod/mixin/EntityMixin.java | 62 +- .../repeating/mod/mixin/InputMixin.java | 40 +- .../repeating/mod/mixin/MovementMixin.java | 88 +-- .../repeating/mod/mixin/NetworkMixin.java | 58 +- .../repeating/mod/mixin/RendererMixin.java | 42 +- .../repeating/mod/mixin/ScreenMixin.java | 14 +- .../repeating/mod/widget/RecordWidget.java | 5 +- .../assets/minecraft/font/default.json | 32 +- .../assets/repeating-mod/lang/en_us.json | 70 +- .../assets/repeating-mod/lang/ru_ru.json | 76 +- src/main/resources/fabric.mod.json | 76 +- src/main/resources/repeating-mod.mixins.json | 40 +- 50 files changed, 1166 insertions(+), 3483 deletions(-) delete mode 100644 remappedSrc/themixray/repeating/mod/EasyConfig.java delete mode 100644 remappedSrc/themixray/repeating/mod/Main.java delete mode 100644 remappedSrc/themixray/repeating/mod/RecordList.java delete mode 100644 remappedSrc/themixray/repeating/mod/RecordState.java delete mode 100644 remappedSrc/themixray/repeating/mod/RenderListener.java delete mode 100644 remappedSrc/themixray/repeating/mod/RepeatingScreen.java delete mode 100644 remappedSrc/themixray/repeating/mod/TickTask.java delete mode 100644 remappedSrc/themixray/repeating/mod/event/RecordBlockBreakEvent.java delete mode 100644 remappedSrc/themixray/repeating/mod/event/RecordBlockInteractEvent.java delete mode 100644 remappedSrc/themixray/repeating/mod/event/RecordDelayEvent.java delete mode 100644 remappedSrc/themixray/repeating/mod/event/RecordEvent.java delete mode 100644 remappedSrc/themixray/repeating/mod/event/RecordInputEvent.java delete mode 100644 remappedSrc/themixray/repeating/mod/event/RecordMoveEvent.java delete mode 100644 remappedSrc/themixray/repeating/mod/mixin/ClientMixin.java delete mode 100644 remappedSrc/themixray/repeating/mod/mixin/EntityMixin.java delete mode 100644 remappedSrc/themixray/repeating/mod/mixin/InputMixin.java delete mode 100644 remappedSrc/themixray/repeating/mod/mixin/MovementMixin.java delete mode 100644 remappedSrc/themixray/repeating/mod/mixin/NetworkMixin.java delete mode 100644 remappedSrc/themixray/repeating/mod/mixin/RendererMixin.java delete mode 100644 remappedSrc/themixray/repeating/mod/render/RenderHelper.java delete mode 100644 remappedSrc/themixray/repeating/mod/render/RenderSystem.java delete mode 100644 remappedSrc/themixray/repeating/mod/render/buffer/BufferManager.java delete mode 100644 remappedSrc/themixray/repeating/mod/render/buffer/Vertex.java delete mode 100644 remappedSrc/themixray/repeating/mod/render/buffer/WorldBuffer.java delete mode 100644 remappedSrc/themixray/repeating/mod/render/shader/Shader.java delete mode 100644 remappedSrc/themixray/repeating/mod/render/shader/ShaderManager.java delete mode 100644 remappedSrc/themixray/repeating/mod/widget/RecordListWidget.java delete mode 100644 remappedSrc/themixray/repeating/mod/widget/RecordWidget.java diff --git a/gradle.properties b/gradle.properties index 4fe0e23..be55ec6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,17 @@ -# 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 -yarn_mappings=1.20+build.1 -loader_version=0.15.10 - -#Fabric api -fabric_version=0.83.0+1.20 - -# Mod Properties -mod_version = 1.1.1+1.20 -maven_group = themixray.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.20.1 +yarn_mappings=1.20.1+build.3 +loader_version=0.15.10 + +#Fabric api +fabric_version=0.97.0+1.20.4 + +# Mod Properties +mod_version = 1.1.2+1.20.1 +maven_group = themixray.repeating.mod archives_base_name = repeating-mod \ No newline at end of file diff --git a/gradlew.bat b/gradlew.bat index 25da30d..7101f8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -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 - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -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 - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +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 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +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 + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/remappedSrc/themixray/repeating/mod/EasyConfig.java b/remappedSrc/themixray/repeating/mod/EasyConfig.java deleted file mode 100644 index 8836722..0000000 --- a/remappedSrc/themixray/repeating/mod/EasyConfig.java +++ /dev/null @@ -1,103 +0,0 @@ -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 data; - - public EasyConfig(File f, Map 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 m:def.entrySet()) - if (!data.containsKey(m.getKey())) - data.put(m.getKey(),m.getValue()); - - save(); - } - public EasyConfig(Path f, Map def) { - this(f.toFile(),def); - } - public EasyConfig(String parent,String child,Map def) { - this(new File(parent,child),def); - } - public EasyConfig(File parent,String child,Map def) { - this(new File(parent,child),def); - } - public EasyConfig(Path parent,String child,Map 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 p) { - StringBuilder t = new StringBuilder(); - for (Map.Entry e:p.entrySet()) - t.append(e.getKey()).append("=").append(e.getValue()).append("\n"); - return t.toString(); - } - private Map toMap(String j) { - Map m = new HashMap<>(); - for (String l:j.split("\n")) { - String s[] = l.split("="); - m.put(s[0],s[1]); - } - return m; - } - - private Map read() { - try { - return toMap(Files.readString(path)); - } catch (IOException e) { - e.printStackTrace(); - } - return new HashMap<>(); - } - private void write(Map p) { - try { - Files.write(path, toText(p).getBytes()); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/remappedSrc/themixray/repeating/mod/Main.java b/remappedSrc/themixray/repeating/mod/Main.java deleted file mode 100644 index 6a851ea..0000000 --- a/remappedSrc/themixray/repeating/mod/Main.java +++ /dev/null @@ -1,325 +0,0 @@ -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.*; - -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 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 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))); - } -} diff --git a/remappedSrc/themixray/repeating/mod/RecordList.java b/remappedSrc/themixray/repeating/mod/RecordList.java deleted file mode 100644 index e17a0e8..0000000 --- a/remappedSrc/themixray/repeating/mod/RecordList.java +++ /dev/null @@ -1,77 +0,0 @@ -package themixray.repeating.mod; - -import net.minecraft.text.Text; -import 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; - -public class RecordList { - private final File folder; - private List records; - private RecordListWidget widget; - - public RecordList(File folder) { - this.folder = folder; - this.records = new ArrayList<>(); - this.widget = new RecordListWidget(0, 0, 180, 200); - } - - public List getRecords() { - return records; - } - - public File getFolder() { - return folder; - } - - public RecordListWidget getWidget() { - return widget; - } - - public void loadRecords() { - for (File file : folder.listFiles()) { - try { - addRecord(file); - } catch (Exception e) {} - } - } - - public void addRecord(File file) throws Exception { - addRecord(RecordState.load(file)); - } - - public void addRecord(RecordState record) { - records.add(record); - widget.addWidget(record); - } - - public void removeRecord(RecordState record) { - records.remove(record); - widget.removeWidget(record); - } - - public RecordState newRecord() { - Date date = new Date(); - String name = "Unnamed"; - String author = Main.client.player.getName().getString(); - - File file = new File(Main.me.records_folder, - "record_" + RecordState.FILE_DATE_FORMAT.format(date) + - "_" + Main.rand.nextInt(10) + ".rrm"); - - RecordState state = new RecordState( - file, name, date, author, - new ArrayList<>(), - null, - null); - - addRecord(state); - - return state; - } -} diff --git a/remappedSrc/themixray/repeating/mod/RecordState.java b/remappedSrc/themixray/repeating/mod/RecordState.java deleted file mode 100644 index 239194a..0000000 --- a/remappedSrc/themixray/repeating/mod/RecordState.java +++ /dev/null @@ -1,169 +0,0 @@ -package themixray.repeating.mod; - -import com.google.common.collect.Lists; -import net.minecraft.util.math.Vec3d; -import themixray.repeating.mod.event.RecordEvent; - -import java.awt.*; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -public class RecordState { - public static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); - public static SimpleDateFormat FILE_DATE_FORMAT = new SimpleDateFormat("MM-dd-yyyy_HH-mm-ss"); - - private final File file; - private String name; - private Date date; - private String author; - - private List events; - private Vec3d start_record_pos; - private Vec3d finish_record_pos; - - public RecordState(File file, - String name, - Date date, - String author, - List events, - Vec3d start_record_pos, - Vec3d finish_record_pos) { - this.file = file; - this.name = name; - this.date = date; - this.author = author; - - this.events = events; - this.start_record_pos = start_record_pos; - this.finish_record_pos = finish_record_pos; - } - - public File getFile() { - return file; - } - - public String getName() { - return name; - } - - public String getAuthor() { - return author; - } - - public Date getDate() { - return date; - } - - public List getEvents() { - return events; - } - - public Vec3d getFinishRecordPos() { - return finish_record_pos; - } - - public Vec3d getStartRecordPos() { - return start_record_pos; - } - - public void setAuthor(String author) { - this.author = author; - } - - public void setDate(Date date) { - this.date = date; - } - - public void setName(String name) { - this.name = name; - } - - public void setEvents(List events) { - this.events = events; - } - - public void setFinishRecordPos(Vec3d finish_record_pos) { - this.finish_record_pos = finish_record_pos; - } - - public void setStartRecordPos(Vec3d start_record_pos) { - this.start_record_pos = start_record_pos; - } - - public void addEvent(RecordEvent event) { - events.add(event); - } - - public RecordEvent getLastEvent(String type) { - for (RecordEvent r: Lists.reverse(new ArrayList<>(events))) { - if (r.getType().equals(type)) { - return r; - } - } - return null; - } - - public void save() throws IOException { - StringBuilder text = new StringBuilder(); - - text.append(name).append("\n") - .append(DATE_FORMAT.format(date)).append("\n") - .append(author).append("\n"); - - text.append(start_record_pos.getX()).append("n") - .append(start_record_pos.getY()).append("n") - .append(start_record_pos.getZ()).append("x") - .append(finish_record_pos.getX()).append("n") - .append(finish_record_pos.getY()).append("n") - .append(finish_record_pos.getZ()); - - for (int i = 0; i < events.size(); i++) { - text.append("\n"); - text.append(events.get(i).serialize()); - } - - Files.write(file.toPath(), text.toString().getBytes()); - } - - public static RecordState load(File file) throws Exception { - String text = Files.readString(file.toPath()); - List lines = List.of(text.split("\n")); - - List signature = lines.subList(0,4); - - String name = signature.get(0); - Date date = DATE_FORMAT.parse(signature.get(1)); - String author = signature.get(2); - - String record_pos = signature.get(3); - - String[] lss0 = record_pos.split("x"); - String[] lss1 = lss0[0].split("n"); - String[] lss2 = lss0[1].split("n"); - - Vec3d start_record_pos = new Vec3d( - Float.parseFloat(lss1[0]), - Float.parseFloat(lss1[1]), - Float.parseFloat(lss1[2])); - Vec3d finish_record_pos = new Vec3d( - Float.parseFloat(lss2[0]), - Float.parseFloat(lss2[1]), - Float.parseFloat(lss2[2])); - - List event_lines = lines.subList(4,lines.size()); - List events = event_lines.stream().map(RecordEvent::deserialize).toList(); - - return new RecordState(file, name, date, author, events, start_record_pos, finish_record_pos); - } - - public void remove() { - file.delete(); - Main.me.record_list.removeRecord(this); - Main.me.record_list.getWidget().removeWidget(this); - } -} diff --git a/remappedSrc/themixray/repeating/mod/RenderListener.java b/remappedSrc/themixray/repeating/mod/RenderListener.java deleted file mode 100644 index 9992e48..0000000 --- a/remappedSrc/themixray/repeating/mod/RenderListener.java +++ /dev/null @@ -1,11 +0,0 @@ -package themixray.repeating.mod; - -import net.minecraft.client.gui.DrawContext; - -public interface RenderListener { - default boolean beforeRender() { - return true; - } - - void render(DrawContext context, int mouseX, int mouseY, float delta); -} diff --git a/remappedSrc/themixray/repeating/mod/RepeatingScreen.java b/remappedSrc/themixray/repeating/mod/RepeatingScreen.java deleted file mode 100644 index 19609e4..0000000 --- a/remappedSrc/themixray/repeating/mod/RepeatingScreen.java +++ /dev/null @@ -1,193 +0,0 @@ -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 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.method_46421(width / 2 + 2); - list_widget.method_46419(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 addDrawableChild(T drawableElement) { - return super.addDrawableChild(drawableElement); - } - - public T addDrawable(T drawable) { - return super.addDrawable(drawable); - } - - public T addSelectableChild(T child) { - return super.addSelectableChild(child); - } - - public void remove(Element child) { - super.remove(child); - } -} diff --git a/remappedSrc/themixray/repeating/mod/TickTask.java b/remappedSrc/themixray/repeating/mod/TickTask.java deleted file mode 100644 index f3beed1..0000000 --- a/remappedSrc/themixray/repeating/mod/TickTask.java +++ /dev/null @@ -1,94 +0,0 @@ -package themixray.repeating.mod; - -import java.util.ArrayList; -import java.util.List; - -public abstract class TickTask implements Runnable { - public static List 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++; - } -} diff --git a/remappedSrc/themixray/repeating/mod/event/RecordBlockBreakEvent.java b/remappedSrc/themixray/repeating/mod/event/RecordBlockBreakEvent.java deleted file mode 100644 index a39380c..0000000 --- a/remappedSrc/themixray/repeating/mod/event/RecordBlockBreakEvent.java +++ /dev/null @@ -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"; - } -} diff --git a/remappedSrc/themixray/repeating/mod/event/RecordBlockInteractEvent.java b/remappedSrc/themixray/repeating/mod/event/RecordBlockInteractEvent.java deleted file mode 100644 index 59d0b76..0000000 --- a/remappedSrc/themixray/repeating/mod/event/RecordBlockInteractEvent.java +++ /dev/null @@ -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"; - } -} diff --git a/remappedSrc/themixray/repeating/mod/event/RecordDelayEvent.java b/remappedSrc/themixray/repeating/mod/event/RecordDelayEvent.java deleted file mode 100644 index 7e4bcca..0000000 --- a/remappedSrc/themixray/repeating/mod/event/RecordDelayEvent.java +++ /dev/null @@ -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"; - } -} diff --git a/remappedSrc/themixray/repeating/mod/event/RecordEvent.java b/remappedSrc/themixray/repeating/mod/event/RecordEvent.java deleted file mode 100644 index e7c2ffe..0000000 --- a/remappedSrc/themixray/repeating/mod/event/RecordEvent.java +++ /dev/null @@ -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; - } -} diff --git a/remappedSrc/themixray/repeating/mod/event/RecordInputEvent.java b/remappedSrc/themixray/repeating/mod/event/RecordInputEvent.java deleted file mode 100644 index a760440..0000000 --- a/remappedSrc/themixray/repeating/mod/event/RecordInputEvent.java +++ /dev/null @@ -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"; - } -} diff --git a/remappedSrc/themixray/repeating/mod/event/RecordMoveEvent.java b/remappedSrc/themixray/repeating/mod/event/RecordMoveEvent.java deleted file mode 100644 index 7b964de..0000000 --- a/remappedSrc/themixray/repeating/mod/event/RecordMoveEvent.java +++ /dev/null @@ -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"; - } -} diff --git a/remappedSrc/themixray/repeating/mod/mixin/ClientMixin.java b/remappedSrc/themixray/repeating/mod/mixin/ClientMixin.java deleted file mode 100644 index 60e9e64..0000000 --- a/remappedSrc/themixray/repeating/mod/mixin/ClientMixin.java +++ /dev/null @@ -1,24 +0,0 @@ -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); - } -} diff --git a/remappedSrc/themixray/repeating/mod/mixin/EntityMixin.java b/remappedSrc/themixray/repeating/mod/mixin/EntityMixin.java deleted file mode 100644 index eed7b58..0000000 --- a/remappedSrc/themixray/repeating/mod/mixin/EntityMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -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 (Main.client.player != null) { - if (getUuid().equals(Main.client.player.getUuid())) { - if (Main.me.is_replaying) { - if (Main.input_replay != null && - Main.input_replay.sprinting != null && - Main.input_replay.sprinting != sprinting) { - ci.cancel(); - } - } - } - } - } -} diff --git a/remappedSrc/themixray/repeating/mod/mixin/InputMixin.java b/remappedSrc/themixray/repeating/mod/mixin/InputMixin.java deleted file mode 100644 index 800e147..0000000 --- a/remappedSrc/themixray/repeating/mod/mixin/InputMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -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(); - } - } - } -} diff --git a/remappedSrc/themixray/repeating/mod/mixin/MovementMixin.java b/remappedSrc/themixray/repeating/mod/mixin/MovementMixin.java deleted file mode 100644 index 45190ba..0000000 --- a/remappedSrc/themixray/repeating/mod/mixin/MovementMixin.java +++ /dev/null @@ -1,44 +0,0 @@ -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); - } -} diff --git a/remappedSrc/themixray/repeating/mod/mixin/NetworkMixin.java b/remappedSrc/themixray/repeating/mod/mixin/NetworkMixin.java deleted file mode 100644 index 4f85878..0000000 --- a/remappedSrc/themixray/repeating/mod/mixin/NetworkMixin.java +++ /dev/null @@ -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 packet, -// BooleanSupplier sendCondition, -// Duration expirationTime, -// CallbackInfo ci) { -// -// } -} diff --git a/remappedSrc/themixray/repeating/mod/mixin/RendererMixin.java b/remappedSrc/themixray/repeating/mod/mixin/RendererMixin.java deleted file mode 100644 index edb363d..0000000 --- a/remappedSrc/themixray/repeating/mod/mixin/RendererMixin.java +++ /dev/null @@ -1,21 +0,0 @@ -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); - } -} diff --git a/remappedSrc/themixray/repeating/mod/render/RenderHelper.java b/remappedSrc/themixray/repeating/mod/render/RenderHelper.java deleted file mode 100644 index 4f80464..0000000 --- a/remappedSrc/themixray/repeating/mod/render/RenderHelper.java +++ /dev/null @@ -1,200 +0,0 @@ -package 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 java.awt.*; - -import static org.lwjgl.opengl.GL33.*; - -@UtilityClass -public class RenderHelper { - public WorldBuffer startLines(WorldRenderContext context) { - glEnable(GL_LINE_SMOOTH); - return new WorldBuffer(GL_LINES, ShaderManager.getPositionColorShader(), context); - } - - public void endLines(WorldBuffer buffer) { - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(false); - buffer.draw(); - glDepthMask(true); - glDisable(GL_BLEND); - } - - 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); - } - - public static WorldBuffer startTri(WorldRenderContext context) { - return new WorldBuffer(GL_TRIANGLES, ShaderManager.getPositionColorShader(), context); - } - - public static void endTri(WorldBuffer buffer) { - //glDepthRange(0, 0.7); - glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDepthMask(false); - buffer.draw(); - glDepthMask(true); - glEnable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthRange(0, 1); - } - - 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); - } - - public static void drawRectFromTri(WorldBuffer buffer, - float x1, float y1, float z1, - float x2, float y2, float z2, - float x3, float y3, float z3, - float x4, float y4, float z4, - Color color) { - drawTri(buffer, - x1, y1, z1, - x2, y2, z2, - x3, y3, z3, - color); - drawTri(buffer, - x3, y3, z3, - x4, y4, z4, - x1, y1, z1, - color); - } - - public void drawRectFromLines(WorldBuffer buffer, - float x1, float y1, float z1, - float x2, float y2, float z2, - float x3, float y3, float z3, - float x4, float y4, float z4, - Color color) { - drawLine(buffer, - x1, y1, z1, - x2, y2, z2, - color); - drawLine(buffer, - x2, y2, z2, - x3, y3, z3, - color); - drawLine(buffer, - x3, y3, z3, - x4, y4, z4, - color); - drawLine(buffer, - x4, y4, z4, - x1, y1, z1, - color); - } - - public void drawBoxFromTri(WorldBuffer buffer, - float x1, float y1, float z1, - float x2, float y2, float z2, - Color color) { - float[][] v = new float[][]{ - new float[]{Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2)}, - new float[]{Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2)}}; - - drawRectFromTri(buffer, - v[0][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[0][2], - v[1][0], v[1][1], v[0][2], - v[0][0], v[1][1], v[0][2], - color); - - drawRectFromTri(buffer, - v[0][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[1][2], - v[0][0], v[0][1], v[1][2], - color); - - drawRectFromTri(buffer, - v[0][0], v[0][1], v[0][2], - v[0][0], v[0][1], v[1][2], - v[0][0], v[1][1], v[1][2], - v[0][0], v[1][1], v[0][2], - color); - - drawRectFromTri(buffer, - v[0][0], v[0][1], v[1][2], - v[1][0], v[0][1], v[1][2], - v[1][0], v[1][1], v[1][2], - v[0][0], v[1][1], v[1][2], - color); - - drawRectFromTri(buffer, - v[0][0], v[1][1], v[0][2], - v[1][0], v[1][1], v[0][2], - v[1][0], v[1][1], v[1][2], - v[0][0], v[1][1], v[1][2], - color); - - drawRectFromTri(buffer, - v[1][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[1][2], - v[1][0], v[1][1], v[1][2], - v[1][0], v[1][1], v[0][2], - color); - } - - public void drawBoxFromLines(WorldBuffer buffer, - float x1, float y1, float z1, - float x2, float y2, float z2, - Color color) { - float[][] v = new float[][]{ - new float[]{Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2)}, - new float[]{Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2)}}; - - drawRectFromLines(buffer, - v[0][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[0][2], - v[1][0], v[1][1], v[0][2], - v[0][0], v[1][1], v[0][2], - color); - - drawRectFromLines(buffer, - v[0][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[1][2], - v[0][0], v[0][1], v[1][2], - color); - - drawRectFromLines(buffer, - v[0][0], v[0][1], v[0][2], - v[0][0], v[0][1], v[1][2], - v[0][0], v[1][1], v[1][2], - v[0][0], v[1][1], v[0][2], - color); - - drawRectFromLines(buffer, - v[0][0], v[0][1], v[1][2], - v[1][0], v[0][1], v[1][2], - v[1][0], v[1][1], v[1][2], - v[0][0], v[1][1], v[1][2], - color); - - drawRectFromLines(buffer, - v[0][0], v[1][1], v[0][2], - v[1][0], v[1][1], v[0][2], - v[1][0], v[1][1], v[1][2], - v[0][0], v[1][1], v[1][2], - color); - - drawRectFromLines(buffer, - v[1][0], v[0][1], v[0][2], - v[1][0], v[0][1], v[1][2], - v[1][0], v[1][1], v[1][2], - v[1][0], v[1][1], v[0][2], - color); - } -} diff --git a/remappedSrc/themixray/repeating/mod/render/RenderSystem.java b/remappedSrc/themixray/repeating/mod/render/RenderSystem.java deleted file mode 100644 index a5fa15c..0000000 --- a/remappedSrc/themixray/repeating/mod/render/RenderSystem.java +++ /dev/null @@ -1,13 +0,0 @@ -package themixray.repeating.mod.render; - -import lombok.experimental.UtilityClass; -import themixray.repeating.mod.render.buffer.BufferManager; -import themixray.repeating.mod.render.shader.ShaderManager; - -@UtilityClass -public class RenderSystem { - public static void init() { - BufferManager.init(); - ShaderManager.init(); - } -} diff --git a/remappedSrc/themixray/repeating/mod/render/buffer/BufferManager.java b/remappedSrc/themixray/repeating/mod/render/buffer/BufferManager.java deleted file mode 100644 index 76d2853..0000000 --- a/remappedSrc/themixray/repeating/mod/render/buffer/BufferManager.java +++ /dev/null @@ -1,48 +0,0 @@ -package themixray.repeating.mod.render.buffer; - -import lombok.experimental.UtilityClass; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; - -import java.nio.FloatBuffer; - -import static org.lwjgl.opengl.GL33.*; - -@UtilityClass -public class BufferManager { - private int vao; - private int vbo; - - private int prevVao; - - public void init() { - ClientLifecycleEvents.CLIENT_STARTED.register(client -> { - vao = glGenVertexArrays(); - vbo = glGenBuffers(); - }); - } - - public static void bindBuffer() { - glBindBuffer(GL_ARRAY_BUFFER, vbo); - } - - public static void unbindBuffer() { - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - public static void writeBuffer(FloatBuffer buffer) { - glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW); - } - - public static void draw(int drawMode, int verts) { - glDrawArrays(drawMode, 0, verts); - } - - public static void bind() { - prevVao = glGetInteger(GL_VERTEX_ARRAY_BINDING); - glBindVertexArray(vao); - } - - public static void unbind() { - glBindVertexArray(prevVao); - } -} diff --git a/remappedSrc/themixray/repeating/mod/render/buffer/Vertex.java b/remappedSrc/themixray/repeating/mod/render/buffer/Vertex.java deleted file mode 100644 index 5aaa113..0000000 --- a/remappedSrc/themixray/repeating/mod/render/buffer/Vertex.java +++ /dev/null @@ -1,30 +0,0 @@ -package themixray.repeating.mod.render.buffer; - -import lombok.Getter; - -public class Vertex { - @Getter - private float x; - @Getter - private float y; - @Getter - private float z; - @Getter - private float r; - @Getter - private float g; - @Getter - private float b; - @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; - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } -} \ No newline at end of file diff --git a/remappedSrc/themixray/repeating/mod/render/buffer/WorldBuffer.java b/remappedSrc/themixray/repeating/mod/render/buffer/WorldBuffer.java deleted file mode 100644 index 390f97d..0000000 --- a/remappedSrc/themixray/repeating/mod/render/buffer/WorldBuffer.java +++ /dev/null @@ -1,82 +0,0 @@ -package 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.lwjgl.BufferUtils; -import themixray.repeating.mod.render.shader.Shader; - -import java.nio.FloatBuffer; -import java.util.ArrayList; -import java.util.List; - -import static org.lwjgl.opengl.GL33.*; - -public class WorldBuffer { - private final List vertices = new ArrayList<>(); - private final int drawMode; - private final Shader shader; - private FloatBuffer projectionMatrix; - private final Vec3d cameraPos; - - 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()); - } - - 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 draw() { - BufferManager.bind(); - BufferManager.bindBuffer(); - - BufferManager.writeBuffer(getBuffer()); - applyProjectionMatrix(); - - glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, vertices.size() * 3 * 4L); - glEnableVertexAttribArray(1); - - BufferManager.unbindBuffer(); - - shader.bind(); - BufferManager.draw(drawMode, this.vertices.size()); - shader.unbind(); - - BufferManager.unbind(); - } - - private FloatBuffer getBuffer() { - FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(vertices.size() * 7); - ArrayList floats = new ArrayList<>(); - for (Vertex vertex : vertices) { - floats.add(vertex.getX()); - floats.add(vertex.getY()); - floats.add(vertex.getZ()); - } - for (Vertex vertex : vertices) { - floats.add(vertex.getR()); - floats.add(vertex.getG()); - floats.add(vertex.getB()); - floats.add(vertex.getA()); - } - Float[] floatArray = new Float[floats.size()]; - floats.toArray(floatArray); - 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); - } -} diff --git a/remappedSrc/themixray/repeating/mod/render/shader/Shader.java b/remappedSrc/themixray/repeating/mod/render/shader/Shader.java deleted file mode 100644 index e11dd9a..0000000 --- a/remappedSrc/themixray/repeating/mod/render/shader/Shader.java +++ /dev/null @@ -1,42 +0,0 @@ -package themixray.repeating.mod.render.shader; - -import lombok.Getter; - -import java.nio.FloatBuffer; - -import static org.lwjgl.opengl.GL33.*; - -public class Shader { - @Getter - private final int id; - - - public Shader(String name) { - int v = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.VERTEX); - int f = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.FRAGMENT); - this.id = glCreateProgram(); - glAttachShader(id, v); - glAttachShader(id, f); - glLinkProgram(id); - } - - public void bind() { - glUseProgram(id); - } - - public void unbind() { - glUseProgram(0); - } - - public void uniformMatrix4f(String name, FloatBuffer matrix) { - bind(); - glUniformMatrix4fv(glGetUniformLocation(id, name), false, matrix); - unbind(); - } - - public void uniformValue2f(String name, float value1, float value2) { - bind(); - glUniform2f(glGetUniformLocation(id, name), value1, value2); - unbind(); - } -} diff --git a/remappedSrc/themixray/repeating/mod/render/shader/ShaderManager.java b/remappedSrc/themixray/repeating/mod/render/shader/ShaderManager.java deleted file mode 100644 index f11c98b..0000000 --- a/remappedSrc/themixray/repeating/mod/render/shader/ShaderManager.java +++ /dev/null @@ -1,97 +0,0 @@ -package themixray.repeating.mod.render.shader; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.platform.TextureUtil; -import lombok.Getter; -import lombok.SneakyThrows; -import lombok.experimental.UtilityClass; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.GlImportProcessor; -import net.minecraft.resource.Resource; -import net.minecraft.resource.ResourceFactory; -import net.minecraft.util.Identifier; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.Nullable; -import org.lwjgl.system.MemoryUtil; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Optional; - -import static org.lwjgl.opengl.GL33.*; - -@UtilityClass -public class ShaderManager { - @Getter - private Shader positionColorShader; - - public void init() { - ClientLifecycleEvents.CLIENT_STARTED.register(client -> loadShaders()); - } - - private void loadShaders() { - positionColorShader = new Shader("position_color"); - } - - public int loadShaderProgram(String name, ShaderType type) { - try { - boolean file_present = true; - ResourceFactory resourceFactory = MinecraftClient.getInstance().getResourceManager(); - Optional resource = resourceFactory.getResource(new Identifier("renderer", "shader/" + name + type.fileExtension)); - int i = glCreateShader(type.glType); - if (resource.isPresent()) { - GlStateManager.glShaderSource(i, new GlImportProcessor() { - @SneakyThrows - @Nullable - @Override - public String loadImport(boolean inline, String name) { - return IOUtils.toString(resource.get().getInputStream(), StandardCharsets.UTF_8); - } - }.readSource(readResourceAsString(resource.get().getInputStream()))); - } else file_present = false; - glCompileShader(i); - if (glGetShaderi(i, GL_COMPILE_STATUS) == 0 || !file_present) { - String shaderInfo = StringUtils.trim(glGetShaderInfoLog(i, 32768)); - throw new IOException("Couldn't compile " + type.name + " program (" + name + ") : " + shaderInfo); - } - return i; - } catch (IOException e) { - e.printStackTrace(); - } - return 0; - } - - private String readResourceAsString(InputStream inputStream) { - ByteBuffer byteBuffer = null; - try { - byteBuffer = TextureUtil.readResource(inputStream); - int i = byteBuffer.position(); - byteBuffer.rewind(); - return MemoryUtil.memASCII(byteBuffer, i); - } catch (IOException ignored) { - } finally { - if (byteBuffer != null) { - MemoryUtil.memFree(byteBuffer); - } - } - return null; - } - - public enum ShaderType { - VERTEX("vertex", ".vsh", GL_VERTEX_SHADER), - FRAGMENT("fragment", ".fsh", GL_FRAGMENT_SHADER); - private final String name; - private final String fileExtension; - private final int glType; - - ShaderType(String name, String fileExtension, int glType) { - this.name = name; - this.fileExtension = fileExtension; - this.glType = glType; - } - } -} diff --git a/remappedSrc/themixray/repeating/mod/widget/RecordListWidget.java b/remappedSrc/themixray/repeating/mod/widget/RecordListWidget.java deleted file mode 100644 index 1ac42b2..0000000 --- a/remappedSrc/themixray/repeating/mod/widget/RecordListWidget.java +++ /dev/null @@ -1,150 +0,0 @@ -package 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 java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; - -public class RecordListWidget extends ScrollableWidget { - private List widgets = new ArrayList<>(); - private boolean focused = false; - - public RecordListWidget(int x, int y, int width, int height) { - super(x,y,width,height,Text.empty()); - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { - focused = true; - boolean res = super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); - focused = false; - return res; - } - - @Override - protected double getDeltaYPerScroll() { - return 10; - } - - @Override - protected void renderContents(DrawContext ctx, int mouseX, int mouseY, float delta) { - int y = 0; - for (RecordWidget wid: widgets) { - wid.method_46419(y); - wid.render(ctx, mouseX, (int) (mouseY + this.getScrollY()), delta); - - y += wid.getHeight(); - y += 2; - } - } - - public void addWidget(RecordState record) { - RecordWidget widget = new RecordWidget(0, 0, width, 55, record, this); - widget.init(null); - widgets.add(0, widget); - } - - public void removeWidget(RecordState record) { - widgets.removeIf(i -> i.getRecord().equals(record)); - } - - @Override - public void setFocused(boolean focused) { - - } - - @Override - public boolean isFocused() { - 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); - } - - screen.addDrawableChild(this); - } - - @Override - protected void appendClickableNarrations(NarrationMessageBuilder builder) { - - } - - public RecordWidget getWidget(RecordState record) { - for (RecordWidget widget : widgets) { - if (widget.getRecord().equals(record)) { - return widget; - } - } - return null; - } - - public interface transport { - boolean check(ClickableWidget ch); - } - - public boolean checkTransport(transport tr) { - for (RecordWidget wid : widgets) { - for (ClickableWidget child : wid.getChildren()) { - if (tr.check(child)) { - return true; - } - } - } - return false; - } - - public boolean checkTransportNF(transport tr) { - for (RecordWidget wid : widgets) { - for (ClickableWidget child : wid.getChildren()) { - boolean res = tr.check(child); - - if (res) { - child.setFocused(true); - return true; - } else { - child.setFocused(false); - } - } - } - return false; - } - - @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); - } - - @Override - public boolean charTyped(char chr, int modifiers) { - return checkTransport((c) -> c.charTyped(chr, modifiers)) || super.charTyped(chr, modifiers); - } - - @Override - public boolean keyPressed(int keyCode, int scanCode, int modifiers) { - return checkTransport((c) -> c.keyPressed(keyCode, scanCode, modifiers)) || super.keyPressed(keyCode, scanCode, modifiers); - } - - @Override - public boolean keyReleased(int keyCode, int scanCode, int modifiers) { - return checkTransport((c) -> c.keyReleased(keyCode, scanCode, modifiers)) || super.keyReleased(keyCode, scanCode, modifiers); - } -} diff --git a/remappedSrc/themixray/repeating/mod/widget/RecordWidget.java b/remappedSrc/themixray/repeating/mod/widget/RecordWidget.java deleted file mode 100644 index bef439a..0000000 --- a/remappedSrc/themixray/repeating/mod/widget/RecordWidget.java +++ /dev/null @@ -1,196 +0,0 @@ -package themixray.repeating.mod.widget; - -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 java.awt.*; -import java.io.IOException; -import java.util.ArrayList; - -import java.util.List; -import java.util.function.Consumer; - -public class RecordWidget implements Drawable, Widget { - private RecordState record; - - private List children; - - private RecordListWidget parent; - - private int x; - private int y; - private int width; - private int height; - - public RecordWidget(int x, int y, int width, int height, RecordState record, RecordListWidget parent) { - this.parent = parent; - this.record = record; - - this.x = x; - this.y = y; - this.width = width; - this.height = height; - - this.children = new ArrayList<>(); - } - - public void method_46421(int x) { - this.x = x; - } - public void method_46419(int y) { - this.y = y; - } - public int getX() { - return x; - } - public int getY() { - return y; - } - public int getWidth() { - return width; - } - public int getHeight() { - return height; - } - - public List getChildren() { - return children; - } - - @Override - public void forEachChild(Consumer consumer) { - children.forEach(consumer); - } - - public void init(RepeatingScreen screen) { - this.children = new ArrayList<>(); - - TextFieldWidget name_widget = new TextFieldWidget( - Main.client.textRenderer, - parent.getX() + getX() + 5, - parent.getY() + getY() + 5, - 102, - 10, - Text.empty()); - - name_widget.setText(record.getName()); - - name_widget.setChangedListener((s) -> { - record.setName(s); - try { - record.save(); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - - children.add(name_widget); - - ButtonWidget delete_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.delete"), (i) -> { - record.remove(); - }).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4, 65, 13).build(); - - children.add(delete_button); - - ButtonWidget export_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.export"), (i) -> { - if (Desktop.isDesktopSupported()) { - Desktop desk = Desktop.getDesktop(); - try { - desk.browseFileDirectory(record.getFile()); - } catch (Exception e) { - try { - desk.browse(record.getFile().toURI()); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - } - }).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) -> { - if (Main.me.is_replaying) { - Main.me.stopReplay(); - } - - i.setMessage(Text.translatable("text.repeating-mod.stop")); - Main.me.now_record = record; - Main.me.startReplay(); - }).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 lines, float size, int line_height, boolean shadow) { - ctx.getMatrices().push(); - ctx.getMatrices().scale(size, size, size); - - 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); - now_y += line_height; - } - - ctx.getMatrices().pop(); - } - - @Override - public void render(DrawContext ctx, int mouseX, int mouseY, float delta) { - int color = record.equals(Main.me.now_record) ? 0xFF555555 : 0xFF333333; - - ctx.fill(parent.getX() + getX(), - parent.getY() + getY(), - parent.getX() + getX() + getWidth(), - parent.getY() + getY() + getHeight(), - color); - - drawText( - parent.getX() + getX() + 5, - parent.getY() + getY() + 5 + 12, - ctx, List.of( - Text.translatable("text.repeating-mod.recorded_at") - .append(": ") - .styled((s) -> s.withColor(0xbbbbbb)), - Text.literal(RecordState.DATE_FORMAT.format(record.getDate())).styled((s) -> s.withColor(0xffffff)), - Text.translatable("text.repeating-mod.author") - .append(": ") - .styled((s) -> s.withColor(0xbbbbbb)), - Text.literal(record.getAuthor()).styled((s) -> s.withColor(0xffffff)) - ), 1, - 9, - false); - - if (!children.isEmpty()) { - ClickableWidget name_widget = children.get(0); - name_widget.setPosition(parent.getX() + getX() + 5, parent.getY() + getY() + 5); - - ClickableWidget delete_button = children.get(1); - delete_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4); - - ClickableWidget export_button = children.get(2); - export_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 14); - - ClickableWidget replay_button = children.get(3); - replay_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 28); - } - - for (ClickableWidget child : children) { - child.render(ctx, mouseX, mouseY, delta); - } - } -} diff --git a/src/main/java/themixray/repeating/mod/EasyConfig.java b/src/main/java/themixray/repeating/mod/EasyConfig.java index 8836722..0ee871c 100644 --- a/src/main/java/themixray/repeating/mod/EasyConfig.java +++ b/src/main/java/themixray/repeating/mod/EasyConfig.java @@ -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 data; - - public EasyConfig(File f, Map 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 m:def.entrySet()) - if (!data.containsKey(m.getKey())) - data.put(m.getKey(),m.getValue()); - - save(); - } - public EasyConfig(Path f, Map def) { - this(f.toFile(),def); - } - public EasyConfig(String parent,String child,Map def) { - this(new File(parent,child),def); - } - public EasyConfig(File parent,String child,Map def) { - this(new File(parent,child),def); - } - public EasyConfig(Path parent,String child,Map 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 p) { - StringBuilder t = new StringBuilder(); - for (Map.Entry e:p.entrySet()) - t.append(e.getKey()).append("=").append(e.getValue()).append("\n"); - return t.toString(); - } - private Map toMap(String j) { - Map m = new HashMap<>(); - for (String l:j.split("\n")) { - String s[] = l.split("="); - m.put(s[0],s[1]); - } - return m; - } - - private Map read() { - try { - return toMap(Files.readString(path)); - } catch (IOException e) { - e.printStackTrace(); - } - return new HashMap<>(); - } - private void write(Map p) { - try { - Files.write(path, toText(p).getBytes()); - } catch (IOException e) { - e.printStackTrace(); - } - } -} +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 data; + + public EasyConfig(File f, Map 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 m:def.entrySet()) + if (!data.containsKey(m.getKey())) + data.put(m.getKey(),m.getValue()); + + save(); + } + public EasyConfig(Path f, Map def) { + this(f.toFile(),def); + } + public EasyConfig(String parent,String child,Map def) { + this(new File(parent,child),def); + } + public EasyConfig(File parent,String child,Map def) { + this(new File(parent,child),def); + } + public EasyConfig(Path parent,String child,Map 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 p) { + StringBuilder t = new StringBuilder(); + for (Map.Entry e:p.entrySet()) + t.append(e.getKey()).append("=").append(e.getValue()).append("\n"); + return t.toString(); + } + private Map toMap(String j) { + Map m = new HashMap<>(); + for (String l:j.split("\n")) { + String s[] = l.split("="); + m.put(s[0],s[1]); + } + return m; + } + + private Map read() { + try { + return toMap(Files.readString(path)); + } catch (IOException e) { + e.printStackTrace(); + } + return new HashMap<>(); + } + private void write(Map p) { + try { + Files.write(path, toText(p).getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/themixray/repeating/mod/Main.java b/src/main/java/themixray/repeating/mod/Main.java index c2b8645..f213ee2 100644 --- a/src/main/java/themixray/repeating/mod/Main.java +++ b/src/main/java/themixray/repeating/mod/Main.java @@ -1,339 +1,341 @@ -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.events.DelayEvent; -import themixray.repeating.mod.event.RecordEvent; -import themixray.repeating.mod.event.events.InputEvent; -import themixray.repeating.mod.event.events.MoveEvent; -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 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 = 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); - }); - - ClientTickEvents.END_CLIENT_TICK.register(client -> { - TickTask.tickTasks(TickTask.TickAt.CLIENT_EVENT); - }); - - Map 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 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() { - now_record.addEvent(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 l = ((InputEvent) now_record.getLastEvent("input")); - if (l == null) { - InputEvent e = new InputEvent( - 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 { - InputEvent e = new InputEvent( - ((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 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 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))); - } - - public static void sendDebug(String s) { - client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s))); - } -} +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.events.DelayEvent; +import themixray.repeating.mod.event.RecordEvent; +import themixray.repeating.mod.event.events.InputEvent; +import themixray.repeating.mod.event.events.MoveEvent; +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 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 = 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); + }); + + ClientTickEvents.END_CLIENT_TICK.register(client -> { + TickTask.tickTasks(TickTask.TickAt.CLIENT_EVENT); + }); + + Map 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 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() { + now_record.addEvent(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 l = ((InputEvent) now_record.getLastEvent("input")); + if (l == null) { + InputEvent e = new InputEvent( + 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 { + InputEvent e = new InputEvent( + ((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 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))); + } + + public static void sendDebug(String s) { + client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s))); + } +} diff --git a/src/main/java/themixray/repeating/mod/RecordList.java b/src/main/java/themixray/repeating/mod/RecordList.java index 99fffe7..431a7be 100644 --- a/src/main/java/themixray/repeating/mod/RecordList.java +++ b/src/main/java/themixray/repeating/mod/RecordList.java @@ -51,6 +51,7 @@ public class RecordList { } public void addRecord(RecordState record) { + if (record == null) return; records.add(record); widget.addWidget(record); } diff --git a/src/main/java/themixray/repeating/mod/RecordState.java b/src/main/java/themixray/repeating/mod/RecordState.java index 21d782b..782c494 100644 --- a/src/main/java/themixray/repeating/mod/RecordState.java +++ b/src/main/java/themixray/repeating/mod/RecordState.java @@ -96,6 +96,7 @@ public class RecordState { } public void addEvent(RecordEvent event) { + if (event == null) return; events.add(event); } @@ -124,9 +125,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()); diff --git a/src/main/java/themixray/repeating/mod/RepeatingScreen.java b/src/main/java/themixray/repeating/mod/RepeatingScreen.java index 0fcd5ec..015feaf 100644 --- a/src/main/java/themixray/repeating/mod/RepeatingScreen.java +++ b/src/main/java/themixray/repeating/mod/RepeatingScreen.java @@ -1,187 +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 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(); - } - }; - 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 addDrawableChild(T drawableElement) { - return super.addDrawableChild(drawableElement); - } - - public T addDrawable(T drawable) { - return super.addDrawable(drawable); - } - - public T addSelectableChild(T child) { - return super.addSelectableChild(child); - } - - public void remove(Element child) { - super.remove(child); - } -} +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 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(); + } + }; + 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 addDrawableChild(T drawableElement) { + return super.addDrawableChild(drawableElement); + } + + public T addDrawable(T drawable) { + return super.addDrawable(drawable); + } + + public T addSelectableChild(T child) { + return super.addSelectableChild(child); + } + + public void remove(Element child) { + super.remove(child); + } +} diff --git a/src/main/java/themixray/repeating/mod/TickTask.java b/src/main/java/themixray/repeating/mod/TickTask.java index e014511..c1ff672 100644 --- a/src/main/java/themixray/repeating/mod/TickTask.java +++ b/src/main/java/themixray/repeating/mod/TickTask.java @@ -1,95 +1,95 @@ -package themixray.repeating.mod; - -import java.util.ArrayList; -import java.util.List; - -public abstract class TickTask implements Runnable { - public static List 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++; - } -} +package themixray.repeating.mod; + +import java.util.ArrayList; +import java.util.List; + +public abstract class TickTask implements Runnable { + public static List 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++; + } +} diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiMouseScrollEvent.java b/src/main/java/themixray/repeating/mod/event/events/GuiMouseScrollEvent.java index 470c29c..720e027 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiMouseScrollEvent.java +++ b/src/main/java/themixray/repeating/mod/event/events/GuiMouseScrollEvent.java @@ -16,7 +16,7 @@ public class GuiMouseScrollEvent extends RecordEvent { public void replay() { if (Main.client.currentScreen != null) { - Main.client.currentScreen.mouseScrolled(mouseX, mouseY, amount); +// Main.client.currentScreen.mouseScrolled(mouseX, mouseY, amount); } } diff --git a/src/main/java/themixray/repeating/mod/mixin/ClientMixin.java b/src/main/java/themixray/repeating/mod/mixin/ClientMixin.java index 60e9e64..b3adac0 100644 --- a/src/main/java/themixray/repeating/mod/mixin/ClientMixin.java +++ b/src/main/java/themixray/repeating/mod/mixin/ClientMixin.java @@ -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 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); + } +} diff --git a/src/main/java/themixray/repeating/mod/mixin/EntityMixin.java b/src/main/java/themixray/repeating/mod/mixin/EntityMixin.java index eed7b58..185de64 100644 --- a/src/main/java/themixray/repeating/mod/mixin/EntityMixin.java +++ b/src/main/java/themixray/repeating/mod/mixin/EntityMixin.java @@ -1,31 +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 (Main.client.player != null) { - if (getUuid().equals(Main.client.player.getUuid())) { - if (Main.me.is_replaying) { - if (Main.input_replay != null && - Main.input_replay.sprinting != null && - Main.input_replay.sprinting != sprinting) { - ci.cancel(); - } - } - } - } - } -} +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 (Main.client.player != null) { + if (getUuid().equals(Main.client.player.getUuid())) { + if (Main.me.is_replaying) { + if (Main.input_replay != null && + Main.input_replay.sprinting != null && + Main.input_replay.sprinting != sprinting) { + ci.cancel(); + } + } + } + } + } +} diff --git a/src/main/java/themixray/repeating/mod/mixin/InputMixin.java b/src/main/java/themixray/repeating/mod/mixin/InputMixin.java index 800e147..c58f53c 100644 --- a/src/main/java/themixray/repeating/mod/mixin/InputMixin.java +++ b/src/main/java/themixray/repeating/mod/mixin/InputMixin.java @@ -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 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(); + } + } + } +} diff --git a/src/main/java/themixray/repeating/mod/mixin/MovementMixin.java b/src/main/java/themixray/repeating/mod/mixin/MovementMixin.java index b850676..f9084e7 100644 --- a/src/main/java/themixray/repeating/mod/mixin/MovementMixin.java +++ b/src/main/java/themixray/repeating/mod/mixin/MovementMixin.java @@ -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.events.BlockBreakEvent; -import themixray.repeating.mod.event.events.BlockInteractEvent; -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 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); - } -} +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.events.BlockBreakEvent; +import themixray.repeating.mod.event.events.BlockInteractEvent; +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 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); + } +} diff --git a/src/main/java/themixray/repeating/mod/mixin/NetworkMixin.java b/src/main/java/themixray/repeating/mod/mixin/NetworkMixin.java index 4f85878..396b6c2 100644 --- a/src/main/java/themixray/repeating/mod/mixin/NetworkMixin.java +++ b/src/main/java/themixray/repeating/mod/mixin/NetworkMixin.java @@ -1,29 +1,29 @@ -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 packet, -// BooleanSupplier sendCondition, -// Duration expirationTime, -// CallbackInfo ci) { -// -// } -} +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 packet, +// BooleanSupplier sendCondition, +// Duration expirationTime, +// CallbackInfo ci) { +// +// } +} diff --git a/src/main/java/themixray/repeating/mod/mixin/RendererMixin.java b/src/main/java/themixray/repeating/mod/mixin/RendererMixin.java index edb363d..22ca225 100644 --- a/src/main/java/themixray/repeating/mod/mixin/RendererMixin.java +++ b/src/main/java/themixray/repeating/mod/mixin/RendererMixin.java @@ -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 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); + } +} diff --git a/src/main/java/themixray/repeating/mod/mixin/ScreenMixin.java b/src/main/java/themixray/repeating/mod/mixin/ScreenMixin.java index bfa46c8..63d5fc5 100644 --- a/src/main/java/themixray/repeating/mod/mixin/ScreenMixin.java +++ b/src/main/java/themixray/repeating/mod/mixin/ScreenMixin.java @@ -80,11 +80,11 @@ public abstract class ScreenMixin extends AbstractParentElement implements Drawa 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); - } +// @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); +// } } diff --git a/src/main/java/themixray/repeating/mod/widget/RecordWidget.java b/src/main/java/themixray/repeating/mod/widget/RecordWidget.java index 3838168..719a606 100644 --- a/src/main/java/themixray/repeating/mod/widget/RecordWidget.java +++ b/src/main/java/themixray/repeating/mod/widget/RecordWidget.java @@ -134,7 +134,8 @@ public class RecordWidget implements Drawable, Widget { 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)) { @@ -143,7 +144,7 @@ public class RecordWidget implements Drawable, Widget { } 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) diff --git a/src/main/resources/assets/minecraft/font/default.json b/src/main/resources/assets/minecraft/font/default.json index 6501fb4..ef1f683 100644 --- a/src/main/resources/assets/minecraft/font/default.json +++ b/src/main/resources/assets/minecraft/font/default.json @@ -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" + } + ] } \ No newline at end of file diff --git a/src/main/resources/assets/repeating-mod/lang/en_us.json b/src/main/resources/assets/repeating-mod/lang/en_us.json index 774b7d8..d2f69be 100644 --- a/src/main/resources/assets/repeating-mod/lang/en_us.json +++ b/src/main/resources/assets/repeating-mod/lang/en_us.json @@ -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" } \ No newline at end of file diff --git a/src/main/resources/assets/repeating-mod/lang/ru_ru.json b/src/main/resources/assets/repeating-mod/lang/ru_ru.json index 2cf3521..84bf569 100644 --- a/src/main/resources/assets/repeating-mod/lang/ru_ru.json +++ b/src/main/resources/assets/repeating-mod/lang/ru_ru.json @@ -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": "Стоп" +} + diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 7a2119f..2e09cc1 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -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": "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": "*" + } +} diff --git a/src/main/resources/repeating-mod.mixins.json b/src/main/resources/repeating-mod.mixins.json index 6156b8f..4196f7e 100644 --- a/src/main/resources/repeating-mod.mixins.json +++ b/src/main/resources/repeating-mod.mixins.json @@ -1,20 +1,20 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "themixray.repeating.mod.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - ], - "client": [ - "MovementMixin", - "InputMixin", - "RendererMixin", - "EntityMixin", - "ClientMixin", - "ScreenMixin", - "PlayerMixin" - ], - "injectors": { - "defaultRequire": 1 - } -} +{ + "required": true, + "minVersion": "0.8", + "package": "themixray.repeating.mod.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + ], + "client": [ + "MovementMixin", + "InputMixin", + "RendererMixin", + "EntityMixin", + "ClientMixin", + "ScreenMixin", + "PlayerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} From 61c755aabc2e63119f389c21881f03311f3afdf5 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 03:02:04 +0300 Subject: [PATCH 03/29] move to 1.21 and fix for nixos --- .gitignore | 42 ++++++++++++++++++ build.gradle | 12 ++--- gradle.properties | 13 +++--- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- shell.nix | 6 +++ .../repeating/mod/RepeatingScreen.java | 2 +- .../mod/render/shader/ShaderManager.java | 2 +- 8 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 .gitignore create mode 100644 shell.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34d600a --- /dev/null +++ b/.gitignore @@ -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/ diff --git a/build.gradle b/build.gradle index 84a69d1..383e374 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.6-SNAPSHOT' + id 'fabric-loom' version "${loom_version}" id 'maven-publish' } @@ -19,8 +19,8 @@ repositories { } 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' @@ -45,7 +45,7 @@ processResources { } tasks.withType(JavaCompile).configureEach { - it.options.release = 17 + it.options.release = 21 } java { @@ -54,8 +54,8 @@ 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 { diff --git a/gradle.properties b/gradle.properties index be55ec6..8feaa20 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,14 +4,15 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.20.1 -yarn_mappings=1.20.1+build.3 -loader_version=0.15.10 +minecraft_version=1.21 +yarn_mappings=1.21+build.9 +loader_version=0.16.14 +loom_version=1.10-SNAPSHOT -#Fabric api -fabric_version=0.97.0+1.20.4 +# Fabric API +fabric_version=0.102.0+1.21 # Mod Properties -mod_version = 1.1.2+1.20.1 +mod_version = 1.1.2+1.21 maven_group = themixray.repeating.mod archives_base_name = repeating-mod \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 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 BT1x-` delta 12460 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 T`Z7J93TASz(qo%C2V^+_d67$> diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23..e18bc25 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..27efeb0 --- /dev/null +++ b/shell.nix @@ -0,0 +1,6 @@ +{ pkgs ? import {} }: +pkgs.mkShell { + shellHook = '' + export LD_LIBRARY_PATH="''${LD_LIBRARY_PATH}''${LD_LIBRARY_PATH:+:}${pkgs.libglvnd}/lib" + ''; +} \ No newline at end of file diff --git a/src/main/java/themixray/repeating/mod/RepeatingScreen.java b/src/main/java/themixray/repeating/mod/RepeatingScreen.java index 015feaf..78f2121 100644 --- a/src/main/java/themixray/repeating/mod/RepeatingScreen.java +++ b/src/main/java/themixray/repeating/mod/RepeatingScreen.java @@ -51,7 +51,7 @@ public class RepeatingScreen extends Screen { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - renderBackground(context); + renderBackground(context, mouseX, mouseY, delta); for (RenderListener l : render_listeners) { if (l.beforeRender()) { diff --git a/src/main/java/themixray/repeating/mod/render/shader/ShaderManager.java b/src/main/java/themixray/repeating/mod/render/shader/ShaderManager.java index f11c98b..08d6a9b 100644 --- a/src/main/java/themixray/repeating/mod/render/shader/ShaderManager.java +++ b/src/main/java/themixray/repeating/mod/render/shader/ShaderManager.java @@ -41,7 +41,7 @@ public class ShaderManager { try { boolean file_present = true; ResourceFactory resourceFactory = MinecraftClient.getInstance().getResourceManager(); - Optional resource = resourceFactory.getResource(new Identifier("renderer", "shader/" + name + type.fileExtension)); + Optional resource = resourceFactory.getResource(Identifier.of("renderer", "shader/" + name + type.fileExtension)); int i = glCreateShader(type.glType); if (resource.isPresent()) { GlStateManager.glShaderSource(i, new GlImportProcessor() { From e7abf3e15b688756938614d2b3f3375f33a20e46 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 03:04:16 +0300 Subject: [PATCH 04/29] open source! --- LICENSE | 433 ++------------------------------------------------- build.gradle | 1 - 2 files changed, 9 insertions(+), 425 deletions(-) diff --git a/LICENSE b/LICENSE index 2d58298..07b7a81 100644 --- a/LICENSE +++ b/LICENSE @@ -1,428 +1,13 @@ -Attribution-ShareAlike 4.0 International + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 -======================================================================= +Copyright (C) 2004 Sam Hocevar -Creative Commons Corporation ("Creative Commons") is not a law firm and -does not provide legal services or legal advice. Distribution of -Creative Commons public licenses does not create a lawyer-client or -other relationship. Creative Commons makes its licenses and related -information available on an "as-is" basis. Creative Commons gives no -warranties regarding its licenses, any material licensed under their -terms and conditions, or any related information. Creative Commons -disclaims all liability for damages resulting from their use to the -fullest extent possible. +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. -Using Creative Commons Public Licenses - -Creative Commons public licenses provide a standard set of terms and -conditions that creators and other rights holders may use to share -original works of authorship and other material subject to copyright -and certain other rights specified in the public license below. The -following considerations are for informational purposes only, are not -exhaustive, and do not form part of our licenses. - - Considerations for licensors: Our public licenses are - intended for use by those authorized to give the public - permission to use material in ways otherwise restricted by - copyright and certain other rights. Our licenses are - irrevocable. Licensors should read and understand the terms - and conditions of the license they choose before applying it. - Licensors should also secure all rights necessary before - applying our licenses so that the public can reuse the - material as expected. Licensors should clearly mark any - material not subject to the license. This includes other CC- - licensed material, or material used under an exception or - limitation to copyright. More considerations for licensors: - wiki.creativecommons.org/Considerations_for_licensors - - Considerations for the public: By using one of our public - licenses, a licensor grants the public permission to use the - licensed material under specified terms and conditions. If - the licensor's permission is not necessary for any reason--for - example, because of any applicable exception or limitation to - copyright--then that use is not regulated by the license. Our - licenses grant only permissions under copyright and certain - other rights that a licensor has authority to grant. Use of - the licensed material may still be restricted for other - reasons, including because others have copyright or other - rights in the material. A licensor may make special requests, - such as asking that all changes be marked or described. - Although not required by our licenses, you are encouraged to - respect those requests where reasonable. More considerations - for the public: - wiki.creativecommons.org/Considerations_for_licensees - -======================================================================= - -Creative Commons Attribution-ShareAlike 4.0 International Public -License - -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-ShareAlike 4.0 International Public License ("Public -License"). To the extent this Public License may be interpreted as a -contract, You are granted the Licensed Rights in consideration of Your -acceptance of these terms and conditions, and the Licensor grants You -such rights in consideration of benefits the Licensor receives from -making the Licensed Material available under these terms and -conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - l. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - m. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part; and - - b. produce, reproduce, and Share Adapted Material. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - including for purposes of Section 3(b); and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. - - -======================================================================= - -Creative Commons is not a party to its public -licenses. Notwithstanding, Creative Commons may elect to apply one of -its public licenses to material it publishes and in those instances -will be considered the “Licensor.” The text of the Creative Commons -public licenses is dedicated to the public domain under the CC0 Public -Domain Dedication. Except for the limited purpose of indicating that -material is shared under a Creative Commons public license or as -otherwise permitted by the Creative Commons policies published at -creativecommons.org/policies, Creative Commons does not authorize the -use of the trademark "Creative Commons" or any other trademark or logo -of Creative Commons without its prior written consent including, -without limitation, in connection with any unauthorized modifications -to any of its public licenses or any other arrangements, -understandings, or agreements concerning use of licensed material. For -the avoidance of doubt, this paragraph does not form part of the -public licenses. - -Creative Commons may be contacted at creativecommons.org. + 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. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 383e374..ffbc124 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +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}" - } processResources { From 8242b2c60191773b975ad9a2efb50fa4cf649c33 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 03:13:26 +0300 Subject: [PATCH 05/29] readme update --- README.md | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f63c38a..43b4faa 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ This mod can record your movements and play them back. +## How to use + +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](preview.gif) ## Controls @@ -10,29 +16,18 @@ 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 -How menu looks like +This is how menu looks like: ![repeating mod menu](https://github.com/MeexReay/repeating-mod/assets/127148610/4123068f-b150-45ae-8ae3-fcaa0e6bb9f8) -## Todo -Releases dont have striked lines +## Roadmap -- record gui mouse clicks and key pressing (in dev) -- create new preview.gif -- practice mode like in geometry dash for parkours - -## How to build - -How to build mod from source - -``` -gradlew build -``` - -Compiled .jar file you can find in `build/libs` +- [ ] relative mode for repeating actions (like mining) +- [ ] record mouse and keyboard in gui +- [ ] practice mode (like in geometry dash but for parkours) From 45998bbe2e741689795fbfc3a2ee7863f80aa187 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 05:02:06 +0300 Subject: [PATCH 06/29] rename group-id and artifact-id, fix recording points render --- gradle.properties | 2 +- .../themixray/repeating_mod}/EasyConfig.java | 2 +- .../themixray/repeating_mod}/Main.java | 46 +++++++++---------- .../themixray/repeating_mod}/RecordList.java | 7 +-- .../themixray/repeating_mod}/RecordState.java | 5 +- .../repeating_mod}/RenderListener.java | 2 +- .../repeating_mod}/RepeatingScreen.java | 44 +++++++++--------- .../themixray/repeating_mod}/TickTask.java | 2 +- .../repeating_mod}/event/RecordEvent.java | 4 +- .../repeating_mod}/event/RecordEventType.java | 4 +- .../event/events/BlockBreakEvent.java | 6 +-- .../event/events/BlockInteractEvent.java | 6 +-- .../event/events/DelayEvent.java | 4 +- .../event/events/GuiCharTypeEvent.java | 6 +-- .../event/events/GuiCloseEvent.java | 6 +-- .../event/events/GuiKeyPressEvent.java | 6 +-- .../event/events/GuiKeyReleaseEvent.java | 6 +-- .../event/events/GuiMouseClickEvent.java | 6 +-- .../event/events/GuiMouseDragEvent.java | 6 +-- .../event/events/GuiMouseMoveEvent.java | 6 +-- .../event/events/GuiMouseReleaseEvent.java | 6 +-- .../event/events/GuiMouseScrollEvent.java | 6 +-- .../event/events/InputEvent.java | 6 +-- .../event/events/MoveEvent.java | 6 +-- .../repeating_mod}/mixin/ClientMixin.java | 6 +-- .../repeating_mod}/mixin/EntityMixin.java | 4 +- .../repeating_mod}/mixin/InputMixin.java | 4 +- .../repeating_mod}/mixin/MovementMixin.java | 10 ++-- .../repeating_mod}/mixin/NetworkMixin.java | 2 +- .../repeating_mod}/mixin/PlayerMixin.java | 10 +--- .../repeating_mod}/mixin/RendererMixin.java | 4 +- .../repeating_mod}/mixin/ScreenMixin.java | 11 ++--- .../repeating_mod}/render/RenderHelper.java | 18 ++++---- .../repeating_mod}/render/RenderSystem.java | 6 +-- .../render/buffer/BufferManager.java | 2 +- .../repeating_mod}/render/buffer/Vertex.java | 15 ++---- .../render/buffer/WorldBuffer.java | 39 +++++++--------- .../repeating_mod}/render/shader/Shader.java | 6 +-- .../render/shader/ShaderManager.java | 6 +-- .../widget/RecordListWidget.java | 16 ++----- .../repeating_mod}/widget/RecordWidget.java | 11 ++--- src/main/resources/fabric.mod.json | 2 +- src/main/resources/repeating-mod.mixins.json | 2 +- 43 files changed, 169 insertions(+), 205 deletions(-) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/EasyConfig.java (95%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/Main.java (83%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/RecordList.java (92%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/RecordState.java (98%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/RenderListener.java (86%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/RepeatingScreen.java (72%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/TickTask.java (94%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/RecordEvent.java (87%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/RecordEventType.java (95%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/BlockBreakEvent.java (85%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/BlockInteractEvent.java (92%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/DelayEvent.java (84%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiCharTypeEvent.java (84%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiCloseEvent.java (73%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiKeyPressEvent.java (86%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiKeyReleaseEvent.java (86%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiMouseClickEvent.java (86%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiMouseDragEvent.java (89%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiMouseMoveEvent.java (84%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiMouseReleaseEvent.java (86%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/GuiMouseScrollEvent.java (86%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/InputEvent.java (98%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/event/events/MoveEvent.java (90%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/ClientMixin.java (82%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/EntityMixin.java (88%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/InputMixin.java (84%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/MovementMixin.java (82%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/NetworkMixin.java (94%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/PlayerMixin.java (64%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/RendererMixin.java (85%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/mixin/ScreenMixin.java (90%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/render/RenderHelper.java (87%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/render/RenderSystem.java (52%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/render/buffer/BufferManager.java (95%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/render/buffer/Vertex.java (50%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/render/buffer/WorldBuffer.java (63%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/render/shader/Shader.java (67%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/render/shader/ShaderManager.java (93%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/widget/RecordListWidget.java (89%) rename src/main/java/{themixray/repeating/mod => ru/themixray/repeating_mod}/widget/RecordWidget.java (96%) diff --git a/gradle.properties b/gradle.properties index 8feaa20..489444b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,5 +14,5 @@ fabric_version=0.102.0+1.21 # Mod Properties mod_version = 1.1.2+1.21 -maven_group = themixray.repeating.mod +maven_group = ru.themixray archives_base_name = repeating-mod \ No newline at end of file diff --git a/src/main/java/themixray/repeating/mod/EasyConfig.java b/src/main/java/ru/themixray/repeating_mod/EasyConfig.java similarity index 95% rename from src/main/java/themixray/repeating/mod/EasyConfig.java rename to src/main/java/ru/themixray/repeating_mod/EasyConfig.java index 0ee871c..b592deb 100644 --- a/src/main/java/themixray/repeating/mod/EasyConfig.java +++ b/src/main/java/ru/themixray/repeating_mod/EasyConfig.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod; +package ru.themixray.repeating_mod; import java.io.IOException; import java.nio.file.Files; diff --git a/src/main/java/themixray/repeating/mod/Main.java b/src/main/java/ru/themixray/repeating_mod/Main.java similarity index 83% rename from src/main/java/themixray/repeating/mod/Main.java rename to src/main/java/ru/themixray/repeating_mod/Main.java index f213ee2..e5ac5a9 100644 --- a/src/main/java/themixray/repeating/mod/Main.java +++ b/src/main/java/ru/themixray/repeating_mod/Main.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod; +package ru.themixray.repeating_mod; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; @@ -15,13 +15,13 @@ import net.minecraft.util.math.Vec3d; import org.lwjgl.glfw.GLFW; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import themixray.repeating.mod.event.events.DelayEvent; -import themixray.repeating.mod.event.RecordEvent; -import themixray.repeating.mod.event.events.InputEvent; -import themixray.repeating.mod.event.events.MoveEvent; -import themixray.repeating.mod.render.RenderHelper; -import themixray.repeating.mod.render.RenderSystem; -import themixray.repeating.mod.render.buffer.WorldBuffer; +import ru.themixray.repeating_mod.event.events.DelayEvent; +import ru.themixray.repeating_mod.event.RecordEvent; +import ru.themixray.repeating_mod.event.events.InputEvent; +import ru.themixray.repeating_mod.event.events.MoveEvent; +import ru.themixray.repeating_mod.render.RenderHelper; +import ru.themixray.repeating_mod.render.RenderSystem; +import ru.themixray.repeating_mod.render.buffer.WorldBuffer; import java.awt.*; import java.io.File; @@ -35,21 +35,21 @@ public class Main implements ClientModInitializer { public static final FabricLoader loader = FabricLoader.getInstance(); public static Main me; - public RecordList record_list; - public RecordState now_record; + public ru.themixray.repeating_mod.RecordList record_list; + public ru.themixray.repeating_mod.RecordState now_record; public boolean is_recording = false; public long last_record = -1; - public TickTask move_tick = null; + public ru.themixray.repeating_mod.TickTask move_tick = null; - public TickTask replay_tick = null; + public ru.themixray.repeating_mod.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; + public static ru.themixray.repeating_mod.RepeatingScreen menu; private static KeyBinding menu_key; private static KeyBinding toggle_replay_key; private static KeyBinding toggle_record_key; @@ -58,7 +58,7 @@ public class Main implements ClientModInitializer { public static Random rand = new Random(); - public EasyConfig conf; + public ru.themixray.repeating_mod.EasyConfig conf; public File records_folder; @Override @@ -71,11 +71,11 @@ public class Main implements ClientModInitializer { 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 = new ru.themixray.repeating_mod.RecordList(records_folder); record_list.loadRecords(); RenderSystem.init(); - WorldRenderEvents.LAST.register(context -> { + WorldRenderEvents.AFTER_ENTITIES.register(context -> { WorldBuffer buffer = RenderHelper.startTri(context); if (now_record != null) { Vec3d start_pos = now_record.getStartRecordPos(); @@ -88,13 +88,13 @@ public class Main implements ClientModInitializer { }); ClientTickEvents.END_CLIENT_TICK.register(client -> { - TickTask.tickTasks(TickTask.TickAt.CLIENT_EVENT); + ru.themixray.repeating_mod.TickTask.tickTasks(ru.themixray.repeating_mod.TickTask.TickAt.CLIENT_EVENT); }); Map def = new HashMap<>(); def.put("record_pos_delay", String.valueOf(record_pos_delay)); - conf = new EasyConfig(loader.getConfigDir(),"repeating-mod",def); + conf = new ru.themixray.repeating_mod.EasyConfig(loader.getConfigDir(),"repeating-mod",def); record_pos_delay = Long.parseLong(conf.data.get("record_pos_delay")); @@ -108,7 +108,7 @@ public class Main implements ClientModInitializer { "key.repeating-mod.toggle_record",InputUtil.Type.KEYSYM, -1,"text.repeating-mod.name")); - menu = new RepeatingScreen(); + menu = new ru.themixray.repeating_mod.RepeatingScreen(); ClientTickEvents.END_CLIENT_TICK.register(client -> { if (menu_key.wasPressed()) client.setScreen(menu); @@ -132,7 +132,7 @@ public class Main implements ClientModInitializer { } }); - new TickTask(0,0) { + new ru.themixray.repeating_mod.TickTask(0,0) { @Override public void run() { living_ticks++; @@ -142,7 +142,7 @@ public class Main implements ClientModInitializer { System.setProperty("java.awt.headless", "false"); } - public void setNowRecord(RecordState record) { + public void setNowRecord(ru.themixray.repeating_mod.RecordState record) { now_record = record; } @@ -177,7 +177,7 @@ public class Main implements ClientModInitializer { now_record.setStartRecordPos(start_pos); if (record_pos_delay > 0) { - move_tick = new TickTask( + move_tick = new ru.themixray.repeating_mod.TickTask( record_pos_delay, record_pos_delay) { @Override @@ -277,7 +277,7 @@ public class Main implements ClientModInitializer { List events = now_record.getEvents(); - replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_EVENT) { + replay_tick = new ru.themixray.repeating_mod.TickTask(0,0, ru.themixray.repeating_mod.TickTask.TickAt.CLIENT_EVENT) { public int replay_index = 0; @Override diff --git a/src/main/java/themixray/repeating/mod/RecordList.java b/src/main/java/ru/themixray/repeating_mod/RecordList.java similarity index 92% rename from src/main/java/themixray/repeating/mod/RecordList.java rename to src/main/java/ru/themixray/repeating_mod/RecordList.java index 431a7be..cebbc45 100644 --- a/src/main/java/themixray/repeating/mod/RecordList.java +++ b/src/main/java/ru/themixray/repeating_mod/RecordList.java @@ -1,12 +1,9 @@ -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.nio.file.Files; -import java.text.SimpleDateFormat; import java.util.*; public class RecordList { diff --git a/src/main/java/themixray/repeating/mod/RecordState.java b/src/main/java/ru/themixray/repeating_mod/RecordState.java similarity index 98% rename from src/main/java/themixray/repeating/mod/RecordState.java rename to src/main/java/ru/themixray/repeating_mod/RecordState.java index 782c494..3a684f5 100644 --- a/src/main/java/themixray/repeating/mod/RecordState.java +++ b/src/main/java/ru/themixray/repeating_mod/RecordState.java @@ -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; diff --git a/src/main/java/themixray/repeating/mod/RenderListener.java b/src/main/java/ru/themixray/repeating_mod/RenderListener.java similarity index 86% rename from src/main/java/themixray/repeating/mod/RenderListener.java rename to src/main/java/ru/themixray/repeating_mod/RenderListener.java index 9992e48..80558be 100644 --- a/src/main/java/themixray/repeating/mod/RenderListener.java +++ b/src/main/java/ru/themixray/repeating_mod/RenderListener.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod; +package ru.themixray.repeating_mod; import net.minecraft.client.gui.DrawContext; diff --git a/src/main/java/themixray/repeating/mod/RepeatingScreen.java b/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java similarity index 72% rename from src/main/java/themixray/repeating/mod/RepeatingScreen.java rename to src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java index 78f2121..6f4df2c 100644 --- a/src/main/java/themixray/repeating/mod/RepeatingScreen.java +++ b/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod; +package ru.themixray.repeating_mod; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -11,7 +11,7 @@ import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.SliderWidget; import net.minecraft.text.Text; -import themixray.repeating.mod.widget.RecordListWidget; +import ru.themixray.repeating_mod.widget.RecordListWidget; import java.awt.*; import java.io.File; @@ -20,7 +20,7 @@ import java.util.List; @Environment(EnvType.CLIENT) public class RepeatingScreen extends Screen { - private static List render_listeners = new ArrayList<>(); + private static List render_listeners = new ArrayList<>(); public ButtonWidget record_btn; public ButtonWidget loop_btn; @@ -34,18 +34,18 @@ public class RepeatingScreen extends Screen { super(Text.empty()); } - public static void addRenderListener(RenderListener render) { + public static void addRenderListener(ru.themixray.repeating_mod.RenderListener render) { render_listeners.add(render); } - public static void removeRenderListener(RenderListener render) { + public static void removeRenderListener(ru.themixray.repeating_mod.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"))); + record_btn.setMessage(Text.translatable("text.repeating-mod." + ((ru.themixray.repeating_mod.Main.me.is_recording) ? "stop_record" : "start_record"))); + loop_btn.setMessage(Text.translatable("text.repeating-mod." + ((ru.themixray.repeating_mod.Main.me.loop_replay) ? "off_loop" : "on_loop"))); } } @@ -53,7 +53,7 @@ public class RepeatingScreen extends Screen { public void render(DrawContext context, int mouseX, int mouseY, float delta) { renderBackground(context, mouseX, mouseY, delta); - for (RenderListener l : render_listeners) { + for (ru.themixray.repeating_mod.RenderListener l : render_listeners) { if (l.beforeRender()) { l.render(context, mouseX, mouseY, delta); } @@ -61,7 +61,7 @@ public class RepeatingScreen extends Screen { super.render(context, mouseX, mouseY, delta); - for (RenderListener l : render_listeners) { + for (ru.themixray.repeating_mod.RenderListener l : render_listeners) { if (!l.beforeRender()) { l.render(context, mouseX, mouseY, delta); } @@ -70,7 +70,7 @@ public class RepeatingScreen extends Screen { @Override protected void init() { - RecordListWidget list_widget = Main.me.record_list.getWidget(); + RecordListWidget list_widget = ru.themixray.repeating_mod.Main.me.record_list.getWidget(); list_widget.setX(width / 2 + 2); list_widget.setY(height / 2 - list_widget.getHeight() / 2); @@ -79,10 +79,10 @@ public class RepeatingScreen extends Screen { 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(); + if (!ru.themixray.repeating_mod.Main.me.is_replaying) { + if (ru.themixray.repeating_mod.Main.me.is_recording) + ru.themixray.repeating_mod.Main.me.stopRecording(); + else ru.themixray.repeating_mod.Main.me.startRecording(); updateButtons(); } }) @@ -91,7 +91,7 @@ public class RepeatingScreen extends Screen { .build(); loop_btn = ButtonWidget.builder(Text.empty(), button -> { - Main.me.loop_replay = !Main.me.loop_replay; + ru.themixray.repeating_mod.Main.me.loop_replay = !ru.themixray.repeating_mod.Main.me.loop_replay; updateButtons(); }) .dimensions(width / 2 - 120, height / 2 - 10, 120, 20) @@ -100,9 +100,9 @@ public class RepeatingScreen extends Screen { 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) { + (ru.themixray.repeating_mod.Main.me.record_pos_delay < 0) ? Text.translatable("text.repeating-mod.nan_pos_delay") : + Text.translatable("text.repeating-mod.pos_delay", String.valueOf(ru.themixray.repeating_mod.Main.me.record_pos_delay)), + (ru.themixray.repeating_mod.Main.me.record_pos_delay+1d)/101d) { @Override protected void updateMessage() { @@ -116,9 +116,9 @@ public class RepeatingScreen extends Screen { 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(); + ru.themixray.repeating_mod.Main.me.record_pos_delay = (long) v; + ru.themixray.repeating_mod.Main.me.conf.data.put("record_pos_delay",String.valueOf(ru.themixray.repeating_mod.Main.me.record_pos_delay)); + ru.themixray.repeating_mod.Main.me.conf.save(); } @Override @@ -148,7 +148,7 @@ public class RepeatingScreen extends Screen { if (files != null) { for (File file : files) { try { - Main.me.setNowRecord(Main.me.record_list.cloneRecord(file)); + ru.themixray.repeating_mod.Main.me.setNowRecord(ru.themixray.repeating_mod.Main.me.record_list.cloneRecord(file)); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/src/main/java/themixray/repeating/mod/TickTask.java b/src/main/java/ru/themixray/repeating_mod/TickTask.java similarity index 94% rename from src/main/java/themixray/repeating/mod/TickTask.java rename to src/main/java/ru/themixray/repeating_mod/TickTask.java index c1ff672..d8adbef 100644 --- a/src/main/java/themixray/repeating/mod/TickTask.java +++ b/src/main/java/ru/themixray/repeating_mod/TickTask.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod; +package ru.themixray.repeating_mod; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/themixray/repeating/mod/event/RecordEvent.java b/src/main/java/ru/themixray/repeating_mod/event/RecordEvent.java similarity index 87% rename from src/main/java/themixray/repeating/mod/event/RecordEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/RecordEvent.java index 0c2cb64..c55db10 100644 --- a/src/main/java/themixray/repeating/mod/event/RecordEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/RecordEvent.java @@ -1,6 +1,6 @@ -package themixray.repeating.mod.event; +package ru.themixray.repeating_mod.event; -import themixray.repeating.mod.event.events.*; +import ru.themixray.repeating_mod.event.events.*; public abstract class RecordEvent { public abstract void replay(); diff --git a/src/main/java/themixray/repeating/mod/event/RecordEventType.java b/src/main/java/ru/themixray/repeating_mod/event/RecordEventType.java similarity index 95% rename from src/main/java/themixray/repeating/mod/event/RecordEventType.java rename to src/main/java/ru/themixray/repeating_mod/event/RecordEventType.java index 957159f..853f002 100644 --- a/src/main/java/themixray/repeating/mod/event/RecordEventType.java +++ b/src/main/java/ru/themixray/repeating_mod/event/RecordEventType.java @@ -1,6 +1,6 @@ -package themixray.repeating.mod.event; +package ru.themixray.repeating_mod.event; -import themixray.repeating.mod.event.events.*; +import ru.themixray.repeating_mod.event.events.*; public enum RecordEventType { BLOCK_BREAK('b',"block_break",BlockBreakEvent.class), diff --git a/src/main/java/themixray/repeating/mod/event/events/BlockBreakEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/BlockBreakEvent.java similarity index 85% rename from src/main/java/themixray/repeating/mod/event/events/BlockBreakEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/BlockBreakEvent.java index 0e34fba..dd8a656 100644 --- a/src/main/java/themixray/repeating/mod/event/events/BlockBreakEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/BlockBreakEvent.java @@ -1,8 +1,8 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; import net.minecraft.util.math.BlockPos; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class BlockBreakEvent extends RecordEvent { public BlockPos pos; diff --git a/src/main/java/themixray/repeating/mod/event/events/BlockInteractEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/BlockInteractEvent.java similarity index 92% rename from src/main/java/themixray/repeating/mod/event/events/BlockInteractEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/BlockInteractEvent.java index bdae075..789ea8f 100644 --- a/src/main/java/themixray/repeating/mod/event/events/BlockInteractEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/BlockInteractEvent.java @@ -1,12 +1,12 @@ -package themixray.repeating.mod.event.events; +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 themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class BlockInteractEvent extends RecordEvent { public Hand hand; diff --git a/src/main/java/themixray/repeating/mod/event/events/DelayEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/DelayEvent.java similarity index 84% rename from src/main/java/themixray/repeating/mod/event/events/DelayEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/DelayEvent.java index 1978702..25dcbac 100644 --- a/src/main/java/themixray/repeating/mod/event/events/DelayEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/DelayEvent.java @@ -1,6 +1,6 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.event.RecordEvent; public class DelayEvent extends RecordEvent { public long delay; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiCharTypeEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiCharTypeEvent.java similarity index 84% rename from src/main/java/themixray/repeating/mod/event/events/GuiCharTypeEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiCharTypeEvent.java index 4428984..7c8dae9 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiCharTypeEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiCharTypeEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiCharTypeEvent extends RecordEvent { private char chr; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiCloseEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiCloseEvent.java similarity index 73% rename from src/main/java/themixray/repeating/mod/event/events/GuiCloseEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiCloseEvent.java index f2c3024..38908fb 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiCloseEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiCloseEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiCloseEvent extends RecordEvent { public GuiCloseEvent() {} diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiKeyPressEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiKeyPressEvent.java similarity index 86% rename from src/main/java/themixray/repeating/mod/event/events/GuiKeyPressEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiKeyPressEvent.java index cf5221f..0e83969 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiKeyPressEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiKeyPressEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiKeyPressEvent extends RecordEvent { private int keyCode; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiKeyReleaseEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiKeyReleaseEvent.java similarity index 86% rename from src/main/java/themixray/repeating/mod/event/events/GuiKeyReleaseEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiKeyReleaseEvent.java index 8134c73..253f8bf 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiKeyReleaseEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiKeyReleaseEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiKeyReleaseEvent extends RecordEvent { private int keyCode; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiMouseClickEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseClickEvent.java similarity index 86% rename from src/main/java/themixray/repeating/mod/event/events/GuiMouseClickEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseClickEvent.java index 1c47776..6cc2393 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiMouseClickEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseClickEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiMouseClickEvent extends RecordEvent { private double mouseX; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiMouseDragEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseDragEvent.java similarity index 89% rename from src/main/java/themixray/repeating/mod/event/events/GuiMouseDragEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseDragEvent.java index f351482..eba566f 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiMouseDragEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseDragEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiMouseDragEvent extends RecordEvent { private double mouseX; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiMouseMoveEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseMoveEvent.java similarity index 84% rename from src/main/java/themixray/repeating/mod/event/events/GuiMouseMoveEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseMoveEvent.java index 7da1c82..94480f2 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiMouseMoveEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseMoveEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiMouseMoveEvent extends RecordEvent { private double mouseX; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiMouseReleaseEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseReleaseEvent.java similarity index 86% rename from src/main/java/themixray/repeating/mod/event/events/GuiMouseReleaseEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseReleaseEvent.java index 63b8b6b..3e8c1b4 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiMouseReleaseEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseReleaseEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiMouseReleaseEvent extends RecordEvent { private double mouseX; diff --git a/src/main/java/themixray/repeating/mod/event/events/GuiMouseScrollEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseScrollEvent.java similarity index 86% rename from src/main/java/themixray/repeating/mod/event/events/GuiMouseScrollEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseScrollEvent.java index 720e027..8df7061 100644 --- a/src/main/java/themixray/repeating/mod/event/events/GuiMouseScrollEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/GuiMouseScrollEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class GuiMouseScrollEvent extends RecordEvent { private double mouseX; diff --git a/src/main/java/themixray/repeating/mod/event/events/InputEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java similarity index 98% rename from src/main/java/themixray/repeating/mod/event/events/InputEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java index 9ca3128..74be7c5 100644 --- a/src/main/java/themixray/repeating/mod/event/events/InputEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java @@ -1,7 +1,7 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class InputEvent extends RecordEvent { public Boolean sneaking; diff --git a/src/main/java/themixray/repeating/mod/event/events/MoveEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/MoveEvent.java similarity index 90% rename from src/main/java/themixray/repeating/mod/event/events/MoveEvent.java rename to src/main/java/ru/themixray/repeating_mod/event/events/MoveEvent.java index c8b8bf1..97054ca 100644 --- a/src/main/java/themixray/repeating/mod/event/events/MoveEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/MoveEvent.java @@ -1,9 +1,9 @@ -package themixray.repeating.mod.event.events; +package ru.themixray.repeating_mod.event.events; import net.minecraft.entity.MovementType; import net.minecraft.util.math.Vec3d; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.RecordEvent; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.RecordEvent; public class MoveEvent extends RecordEvent { public Vec3d vec; diff --git a/src/main/java/themixray/repeating/mod/mixin/ClientMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/ClientMixin.java similarity index 82% rename from src/main/java/themixray/repeating/mod/mixin/ClientMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/ClientMixin.java index b3adac0..10b1a8e 100644 --- a/src/main/java/themixray/repeating/mod/mixin/ClientMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/ClientMixin.java @@ -1,12 +1,12 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; import net.minecraft.client.MinecraftClient; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.TickTask; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.TickTask; @Mixin(MinecraftClient.class) public abstract class ClientMixin { diff --git a/src/main/java/themixray/repeating/mod/mixin/EntityMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/EntityMixin.java similarity index 88% rename from src/main/java/themixray/repeating/mod/mixin/EntityMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/EntityMixin.java index 185de64..9bf8341 100644 --- a/src/main/java/themixray/repeating/mod/mixin/EntityMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/EntityMixin.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; @@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import themixray.repeating.mod.Main; +import ru.themixray.repeating_mod.Main; import java.util.UUID; diff --git a/src/main/java/themixray/repeating/mod/mixin/InputMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/InputMixin.java similarity index 84% rename from src/main/java/themixray/repeating/mod/mixin/InputMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/InputMixin.java index c58f53c..33acbf1 100644 --- a/src/main/java/themixray/repeating/mod/mixin/InputMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/InputMixin.java @@ -1,11 +1,11 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; import net.minecraft.client.input.KeyboardInput; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import themixray.repeating.mod.Main; +import ru.themixray.repeating_mod.Main; @Mixin(KeyboardInput.class) public abstract class InputMixin { diff --git a/src/main/java/themixray/repeating/mod/mixin/MovementMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/MovementMixin.java similarity index 82% rename from src/main/java/themixray/repeating/mod/mixin/MovementMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/MovementMixin.java index f9084e7..73f970b 100644 --- a/src/main/java/themixray/repeating/mod/mixin/MovementMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/MovementMixin.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; @@ -9,10 +9,10 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.event.events.BlockBreakEvent; -import themixray.repeating.mod.event.events.BlockInteractEvent; -import themixray.repeating.mod.TickTask; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.events.BlockBreakEvent; +import ru.themixray.repeating_mod.event.events.BlockInteractEvent; +import ru.themixray.repeating_mod.TickTask; @Mixin(ClientPlayerEntity.class) public abstract class MovementMixin { diff --git a/src/main/java/themixray/repeating/mod/mixin/NetworkMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/NetworkMixin.java similarity index 94% rename from src/main/java/themixray/repeating/mod/mixin/NetworkMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/NetworkMixin.java index 396b6c2..58f7570 100644 --- a/src/main/java/themixray/repeating/mod/mixin/NetworkMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/NetworkMixin.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.listener.ServerPlayPacketListener; diff --git a/src/main/java/themixray/repeating/mod/mixin/PlayerMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/PlayerMixin.java similarity index 64% rename from src/main/java/themixray/repeating/mod/mixin/PlayerMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/PlayerMixin.java index 67735f9..c5627c8 100644 --- a/src/main/java/themixray/repeating/mod/mixin/PlayerMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/PlayerMixin.java @@ -1,18 +1,12 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.entity.Entity; import net.minecraft.network.ClientConnection; import net.minecraft.text.Text; 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; +import ru.themixray.repeating_mod.Main; @Mixin(ClientConnection.class) public abstract class PlayerMixin { diff --git a/src/main/java/themixray/repeating/mod/mixin/RendererMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/RendererMixin.java similarity index 85% rename from src/main/java/themixray/repeating/mod/mixin/RendererMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/RendererMixin.java index 22ca225..c035167 100644 --- a/src/main/java/themixray/repeating/mod/mixin/RendererMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/RendererMixin.java @@ -1,11 +1,11 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; import net.minecraft.client.render.*; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import themixray.repeating.mod.TickTask; +import ru.themixray.repeating_mod.TickTask; @Mixin(GameRenderer.class) public abstract class RendererMixin { diff --git a/src/main/java/themixray/repeating/mod/mixin/ScreenMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/ScreenMixin.java similarity index 90% rename from src/main/java/themixray/repeating/mod/mixin/ScreenMixin.java rename to src/main/java/ru/themixray/repeating_mod/mixin/ScreenMixin.java index 63d5fc5..3d74704 100644 --- a/src/main/java/themixray/repeating/mod/mixin/ScreenMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/ScreenMixin.java @@ -1,20 +1,15 @@ -package themixray.repeating.mod.mixin; +package ru.themixray.repeating_mod.mixin; import net.minecraft.client.gui.AbstractParentElement; import net.minecraft.client.gui.Drawable; -import net.minecraft.client.gui.Element; -import net.minecraft.client.gui.ParentElement; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.render.GameRenderer; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; 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 themixray.repeating.mod.Main; -import themixray.repeating.mod.TickTask; -import themixray.repeating.mod.event.events.*; +import ru.themixray.repeating_mod.Main; +import ru.themixray.repeating_mod.event.events.*; @Mixin(Screen.class) public abstract class ScreenMixin extends AbstractParentElement implements Drawable { diff --git a/src/main/java/themixray/repeating/mod/render/RenderHelper.java b/src/main/java/ru/themixray/repeating_mod/render/RenderHelper.java similarity index 87% rename from src/main/java/themixray/repeating/mod/render/RenderHelper.java rename to src/main/java/ru/themixray/repeating_mod/render/RenderHelper.java index 4f80464..c67abd4 100644 --- a/src/main/java/themixray/repeating/mod/render/RenderHelper.java +++ b/src/main/java/ru/themixray/repeating_mod/render/RenderHelper.java @@ -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, diff --git a/src/main/java/themixray/repeating/mod/render/RenderSystem.java b/src/main/java/ru/themixray/repeating_mod/render/RenderSystem.java similarity index 52% rename from src/main/java/themixray/repeating/mod/render/RenderSystem.java rename to src/main/java/ru/themixray/repeating_mod/render/RenderSystem.java index a5fa15c..90f12e9 100644 --- a/src/main/java/themixray/repeating/mod/render/RenderSystem.java +++ b/src/main/java/ru/themixray/repeating_mod/render/RenderSystem.java @@ -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 { diff --git a/src/main/java/themixray/repeating/mod/render/buffer/BufferManager.java b/src/main/java/ru/themixray/repeating_mod/render/buffer/BufferManager.java similarity index 95% rename from src/main/java/themixray/repeating/mod/render/buffer/BufferManager.java rename to src/main/java/ru/themixray/repeating_mod/render/buffer/BufferManager.java index 76d2853..9fb32ff 100644 --- a/src/main/java/themixray/repeating/mod/render/buffer/BufferManager.java +++ b/src/main/java/ru/themixray/repeating_mod/render/buffer/BufferManager.java @@ -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; diff --git a/src/main/java/themixray/repeating/mod/render/buffer/Vertex.java b/src/main/java/ru/themixray/repeating_mod/render/buffer/Vertex.java similarity index 50% rename from src/main/java/themixray/repeating/mod/render/buffer/Vertex.java rename to src/main/java/ru/themixray/repeating_mod/render/buffer/Vertex.java index 5aaa113..a87e2e6 100644 --- a/src/main/java/themixray/repeating/mod/render/buffer/Vertex.java +++ b/src/main/java/ru/themixray/repeating_mod/render/buffer/Vertex.java @@ -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; diff --git a/src/main/java/themixray/repeating/mod/render/buffer/WorldBuffer.java b/src/main/java/ru/themixray/repeating_mod/render/buffer/WorldBuffer.java similarity index 63% rename from src/main/java/themixray/repeating/mod/render/buffer/WorldBuffer.java rename to src/main/java/ru/themixray/repeating_mod/render/buffer/WorldBuffer.java index 390f97d..fa27670 100644 --- a/src/main/java/themixray/repeating/mod/render/buffer/WorldBuffer.java +++ b/src/main/java/ru/themixray/repeating_mod/render/buffer/WorldBuffer.java @@ -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 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); - } } diff --git a/src/main/java/themixray/repeating/mod/render/shader/Shader.java b/src/main/java/ru/themixray/repeating_mod/render/shader/Shader.java similarity index 67% rename from src/main/java/themixray/repeating/mod/render/shader/Shader.java rename to src/main/java/ru/themixray/repeating_mod/render/shader/Shader.java index e11dd9a..efe5550 100644 --- a/src/main/java/themixray/repeating/mod/render/shader/Shader.java +++ b/src/main/java/ru/themixray/repeating_mod/render/shader/Shader.java @@ -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); diff --git a/src/main/java/themixray/repeating/mod/render/shader/ShaderManager.java b/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java similarity index 93% rename from src/main/java/themixray/repeating/mod/render/shader/ShaderManager.java rename to src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java index 08d6a9b..34c0d25 100644 --- a/src/main/java/themixray/repeating/mod/render/shader/ShaderManager.java +++ b/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java @@ -1,4 +1,4 @@ -package themixray.repeating.mod.render.shader; +package ru.themixray.repeating_mod.render.shader; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.TextureUtil; @@ -27,14 +27,14 @@ 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) { diff --git a/src/main/java/themixray/repeating/mod/widget/RecordListWidget.java b/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java similarity index 89% rename from src/main/java/themixray/repeating/mod/widget/RecordListWidget.java rename to src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java index d038f91..5b7a7e3 100644 --- a/src/main/java/themixray/repeating/mod/widget/RecordListWidget.java +++ b/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java @@ -1,22 +1,14 @@ -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.LinkedList; -import java.util.List; -import java.util.function.Consumer; public class RecordListWidget extends ScrollableWidget { private LinkedList widgets = new LinkedList<>(); diff --git a/src/main/java/themixray/repeating/mod/widget/RecordWidget.java b/src/main/java/ru/themixray/repeating_mod/widget/RecordWidget.java similarity index 96% rename from src/main/java/themixray/repeating/mod/widget/RecordWidget.java rename to src/main/java/ru/themixray/repeating_mod/widget/RecordWidget.java index 719a606..7d53358 100644 --- a/src/main/java/themixray/repeating/mod/widget/RecordWidget.java +++ b/src/main/java/ru/themixray/repeating_mod/widget/RecordWidget.java @@ -1,17 +1,14 @@ -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.tooltip.Tooltip; import net.minecraft.client.gui.widget.*; -import net.minecraft.text.Style; import net.minecraft.text.Text; -import net.minecraft.text.TextColor; import net.minecraft.util.Formatting; -import themixray.repeating.mod.Main; -import themixray.repeating.mod.RecordState; -import themixray.repeating.mod.RenderListener; -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.awt.*; import java.io.IOException; diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 2e09cc1..9bbbbe2 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -19,7 +19,7 @@ "environment": "client", "entrypoints": { "client": [ - "themixray.repeating.mod.Main" + "ru.themixray.repeating_mod.Main" ] }, "mixins": [ diff --git a/src/main/resources/repeating-mod.mixins.json b/src/main/resources/repeating-mod.mixins.json index 4196f7e..7bfbaa8 100644 --- a/src/main/resources/repeating-mod.mixins.json +++ b/src/main/resources/repeating-mod.mixins.json @@ -1,7 +1,7 @@ { "required": true, "minVersion": "0.8", - "package": "themixray.repeating.mod.mixin", + "package": "ru.themixray.repeating_mod.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ ], From 2944395e54a21aecfad847b59cf67f1c30b6baa9 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 05:09:39 +0300 Subject: [PATCH 07/29] remove some crap --- .../java/ru/themixray/repeating_mod/Main.java | 28 ++++++------- .../repeating_mod/RepeatingScreen.java | 40 +++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/main/java/ru/themixray/repeating_mod/Main.java b/src/main/java/ru/themixray/repeating_mod/Main.java index e5ac5a9..3079d38 100644 --- a/src/main/java/ru/themixray/repeating_mod/Main.java +++ b/src/main/java/ru/themixray/repeating_mod/Main.java @@ -35,21 +35,21 @@ public class Main implements ClientModInitializer { public static final FabricLoader loader = FabricLoader.getInstance(); public static Main me; - public ru.themixray.repeating_mod.RecordList record_list; - public ru.themixray.repeating_mod.RecordState now_record; + public RecordList record_list; + public RecordState now_record; public boolean is_recording = false; public long last_record = -1; - public ru.themixray.repeating_mod.TickTask move_tick = null; + public TickTask move_tick = null; - public ru.themixray.repeating_mod.TickTask replay_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 ru.themixray.repeating_mod.RepeatingScreen menu; + public static RepeatingScreen menu; private static KeyBinding menu_key; private static KeyBinding toggle_replay_key; private static KeyBinding toggle_record_key; @@ -58,7 +58,7 @@ public class Main implements ClientModInitializer { public static Random rand = new Random(); - public ru.themixray.repeating_mod.EasyConfig conf; + public EasyConfig conf; public File records_folder; @Override @@ -71,7 +71,7 @@ public class Main implements ClientModInitializer { records_folder = new File(FabricLoader.getInstance().getGameDir().toFile(),"repeating_mod_records"); if (!records_folder.exists()) records_folder.mkdir(); - record_list = new ru.themixray.repeating_mod.RecordList(records_folder); + record_list = new RecordList(records_folder); record_list.loadRecords(); RenderSystem.init(); @@ -88,13 +88,13 @@ public class Main implements ClientModInitializer { }); ClientTickEvents.END_CLIENT_TICK.register(client -> { - ru.themixray.repeating_mod.TickTask.tickTasks(ru.themixray.repeating_mod.TickTask.TickAt.CLIENT_EVENT); + TickTask.tickTasks(TickTask.TickAt.CLIENT_EVENT); }); Map def = new HashMap<>(); def.put("record_pos_delay", String.valueOf(record_pos_delay)); - conf = new ru.themixray.repeating_mod.EasyConfig(loader.getConfigDir(),"repeating-mod",def); + conf = new EasyConfig(loader.getConfigDir(),"repeating-mod",def); record_pos_delay = Long.parseLong(conf.data.get("record_pos_delay")); @@ -108,7 +108,7 @@ public class Main implements ClientModInitializer { "key.repeating-mod.toggle_record",InputUtil.Type.KEYSYM, -1,"text.repeating-mod.name")); - menu = new ru.themixray.repeating_mod.RepeatingScreen(); + menu = new RepeatingScreen(); ClientTickEvents.END_CLIENT_TICK.register(client -> { if (menu_key.wasPressed()) client.setScreen(menu); @@ -132,7 +132,7 @@ public class Main implements ClientModInitializer { } }); - new ru.themixray.repeating_mod.TickTask(0,0) { + new TickTask(0,0) { @Override public void run() { living_ticks++; @@ -142,7 +142,7 @@ public class Main implements ClientModInitializer { System.setProperty("java.awt.headless", "false"); } - public void setNowRecord(ru.themixray.repeating_mod.RecordState record) { + public void setNowRecord(RecordState record) { now_record = record; } @@ -177,7 +177,7 @@ public class Main implements ClientModInitializer { now_record.setStartRecordPos(start_pos); if (record_pos_delay > 0) { - move_tick = new ru.themixray.repeating_mod.TickTask( + move_tick = new TickTask( record_pos_delay, record_pos_delay) { @Override @@ -277,7 +277,7 @@ public class Main implements ClientModInitializer { List events = now_record.getEvents(); - replay_tick = new ru.themixray.repeating_mod.TickTask(0,0, ru.themixray.repeating_mod.TickTask.TickAt.CLIENT_EVENT) { + replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_EVENT) { public int replay_index = 0; @Override diff --git a/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java b/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java index 6f4df2c..8d95918 100644 --- a/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java +++ b/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java @@ -20,7 +20,7 @@ import java.util.List; @Environment(EnvType.CLIENT) public class RepeatingScreen extends Screen { - private static List render_listeners = new ArrayList<>(); + private static List render_listeners = new ArrayList<>(); public ButtonWidget record_btn; public ButtonWidget loop_btn; @@ -34,18 +34,18 @@ public class RepeatingScreen extends Screen { super(Text.empty()); } - public static void addRenderListener(ru.themixray.repeating_mod.RenderListener render) { + public static void addRenderListener(RenderListener render) { render_listeners.add(render); } - public static void removeRenderListener(ru.themixray.repeating_mod.RenderListener 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." + ((ru.themixray.repeating_mod.Main.me.is_recording) ? "stop_record" : "start_record"))); - loop_btn.setMessage(Text.translatable("text.repeating-mod." + ((ru.themixray.repeating_mod.Main.me.loop_replay) ? "off_loop" : "on_loop"))); + 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"))); } } @@ -53,7 +53,7 @@ public class RepeatingScreen extends Screen { public void render(DrawContext context, int mouseX, int mouseY, float delta) { renderBackground(context, mouseX, mouseY, delta); - for (ru.themixray.repeating_mod.RenderListener l : render_listeners) { + for (RenderListener l : render_listeners) { if (l.beforeRender()) { l.render(context, mouseX, mouseY, delta); } @@ -61,7 +61,7 @@ public class RepeatingScreen extends Screen { super.render(context, mouseX, mouseY, delta); - for (ru.themixray.repeating_mod.RenderListener l : render_listeners) { + for (RenderListener l : render_listeners) { if (!l.beforeRender()) { l.render(context, mouseX, mouseY, delta); } @@ -70,7 +70,7 @@ public class RepeatingScreen extends Screen { @Override protected void init() { - RecordListWidget list_widget = ru.themixray.repeating_mod.Main.me.record_list.getWidget(); + RecordListWidget list_widget = Main.me.record_list.getWidget(); list_widget.setX(width / 2 + 2); list_widget.setY(height / 2 - list_widget.getHeight() / 2); @@ -79,10 +79,10 @@ public class RepeatingScreen extends Screen { record_btn = ButtonWidget.builder( Text.translatable("text.repeating-mod.start_record"), button -> { - if (!ru.themixray.repeating_mod.Main.me.is_replaying) { - if (ru.themixray.repeating_mod.Main.me.is_recording) - ru.themixray.repeating_mod.Main.me.stopRecording(); - else ru.themixray.repeating_mod.Main.me.startRecording(); + if (!Main.me.is_replaying) { + if (Main.me.is_recording) + Main.me.stopRecording(); + else Main.me.startRecording(); updateButtons(); } }) @@ -91,7 +91,7 @@ public class RepeatingScreen extends Screen { .build(); loop_btn = ButtonWidget.builder(Text.empty(), button -> { - ru.themixray.repeating_mod.Main.me.loop_replay = !ru.themixray.repeating_mod.Main.me.loop_replay; + Main.me.loop_replay = !Main.me.loop_replay; updateButtons(); }) .dimensions(width / 2 - 120, height / 2 - 10, 120, 20) @@ -100,9 +100,9 @@ public class RepeatingScreen extends Screen { pos_delay_slider = new SliderWidget( width / 2 - 120, height / 2 + 12, 120, 20, - (ru.themixray.repeating_mod.Main.me.record_pos_delay < 0) ? Text.translatable("text.repeating-mod.nan_pos_delay") : - Text.translatable("text.repeating-mod.pos_delay", String.valueOf(ru.themixray.repeating_mod.Main.me.record_pos_delay)), - (ru.themixray.repeating_mod.Main.me.record_pos_delay+1d)/101d) { + (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() { @@ -116,9 +116,9 @@ public class RepeatingScreen extends Screen { 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))); - ru.themixray.repeating_mod.Main.me.record_pos_delay = (long) v; - ru.themixray.repeating_mod.Main.me.conf.data.put("record_pos_delay",String.valueOf(ru.themixray.repeating_mod.Main.me.record_pos_delay)); - ru.themixray.repeating_mod.Main.me.conf.save(); + 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 @@ -148,7 +148,7 @@ public class RepeatingScreen extends Screen { if (files != null) { for (File file : files) { try { - ru.themixray.repeating_mod.Main.me.setNowRecord(ru.themixray.repeating_mod.Main.me.record_list.cloneRecord(file)); + Main.me.setNowRecord(Main.me.record_list.cloneRecord(file)); } catch (Exception e) { throw new RuntimeException(e); } From 759b6cb05ec6309c6eaa61bd449e9a9c2999e335 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 05:17:53 +0300 Subject: [PATCH 08/29] gitea action --- .gitea/workflows/java.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .gitea/workflows/java.yml diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml new file mode 100644 index 0000000..77f293a --- /dev/null +++ b/.gitea/workflows/java.yml @@ -0,0 +1,35 @@ +name: Build fabric mod + +on: + push: + branches: [ '*' ] + pull_request: + branches: [ '*' ] + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + + 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@v4 + with: + gradle-version: '8.12.1' + + - name: Build with Gradle Wrapper + run: ./gradlew build + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: build + path: build/libs \ No newline at end of file From f49b1e21a314226fa4b7475135ccc15d309e74ea Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 05:23:49 +0300 Subject: [PATCH 09/29] maybefix gitea actions --- .gitea/workflows/java.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index 77f293a..df59382 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -21,7 +21,7 @@ jobs: distribution: 'temurin' - name: Setup Gradle 8.12.1 - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 with: gradle-version: '8.12.1' From 1e4f4fdaeb3368379d6c0386f0314171139d6251 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 06:00:20 +0300 Subject: [PATCH 10/29] gitea actions fix x3 --- .gitea/workflows/java.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index df59382..377de88 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -9,9 +9,6 @@ on: jobs: build: runs-on: ubuntu-latest - permissions: - contents: read - steps: - uses: actions/checkout@v4 - name: Set up JDK 21 From b6084063a1efcd6d231052a7c6b21a0e32abb66c Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 06:23:35 +0300 Subject: [PATCH 11/29] make gradlew exec --- .gitea/workflows/java.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index 377de88..1862a70 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -22,6 +22,9 @@ jobs: with: gradle-version: '8.12.1' + - name: Make gradlew executable + run: chmod +x ./gradlew + - name: Build with Gradle Wrapper run: ./gradlew build From 62dcb75960345a3ee1119a078e0b7749682984b7 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 06:48:00 +0300 Subject: [PATCH 12/29] fix upload artifact --- .gitea/workflows/java.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index 1862a70..b3d122f 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -32,4 +32,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: build - path: build/libs \ No newline at end of file + path: build/libs/* \ No newline at end of file From 2e62b69a218db43bd756b19fdd7f5aa6932c6ea1 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 07:45:08 +0300 Subject: [PATCH 13/29] action refactor --- .gitea/workflows/java.yml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index b3d122f..d0cc80b 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -1,16 +1,13 @@ -name: Build fabric mod +on: [push, pull_request] -on: - push: - branches: [ '*' ] - pull_request: - branches: [ '*' ] +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: @@ -22,14 +19,10 @@ jobs: with: gradle-version: '8.12.1' - - name: Make gradlew executable - run: chmod +x ./gradlew - - name: Build with Gradle Wrapper - run: ./gradlew build + run: chmod +x ./gradlew; ./gradlew build - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: build path: build/libs/* \ No newline at end of file From d4abb39c8012984db9c640bc15b9642468582357 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 08:01:57 +0300 Subject: [PATCH 14/29] downgrade upload-artifact --- .gitea/workflows/java.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index d0cc80b..8fc764a 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -23,6 +23,6 @@ jobs: run: chmod +x ./gradlew; ./gradlew build - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: path: build/libs/* \ No newline at end of file From 63132684cd2ed70d355282f49ba45e64a8dee64e Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 19:28:24 +0300 Subject: [PATCH 15/29] Update README.md --- README.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 43b4faa..e0fa54f 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,16 @@ This mod can record your movements and play them back. Simply start recording, perform any actions, stop the recording, return to the starting point, and then you can replay everything you did. -## Showcase +### Showcase ![Preview gif](preview.gif) -## Controls +This is how menu looks like: + +![repeating mod menu](https://github.com/MeexReay/repeating-mod/assets/127148610/4123068f-b150-45ae-8ae3-fcaa0e6bb9f8) + + +### Controls Default Repeating Mod keys @@ -20,14 +25,15 @@ Toggle recording | not specified by default Toggle replay | not specified by default ``` -## Menu - -This is how menu looks like: - -![repeating mod menu](https://github.com/MeexReay/repeating-mod/assets/127148610/4123068f-b150-45ae-8ae3-fcaa0e6bb9f8) - ## 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 From 666377e5ee261669fc68724e6913118388641a3d Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 20:04:53 +0300 Subject: [PATCH 16/29] fix pos event --- .gitea/workflows/java.yml | 1 + src/main/java/ru/themixray/repeating_mod/Main.java | 6 +++--- .../repeating_mod/event/events/MoveEvent.java | 12 +++++++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index 8fc764a..2dd136f 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -25,4 +25,5 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v3 with: + name: build path: build/libs/* \ No newline at end of file diff --git a/src/main/java/ru/themixray/repeating_mod/Main.java b/src/main/java/ru/themixray/repeating_mod/Main.java index 3079d38..17cf367 100644 --- a/src/main/java/ru/themixray/repeating_mod/Main.java +++ b/src/main/java/ru/themixray/repeating_mod/Main.java @@ -54,7 +54,7 @@ public class Main implements ClientModInitializer { private static KeyBinding toggle_replay_key; private static KeyBinding toggle_record_key; - public long record_pos_delay = 20; + public long record_pos_delay = -1; public static Random rand = new Random(); @@ -173,7 +173,7 @@ public class Main implements ClientModInitializer { now_record = record_list.newRecord(); Vec3d start_pos = client.player.getPos(); - now_record.addEvent(new MoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch())); + recordTick(new MoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch())); now_record.setStartRecordPos(start_pos); if (record_pos_delay > 0) { @@ -182,7 +182,7 @@ public class Main implements ClientModInitializer { record_pos_delay) { @Override public void run() { - now_record.addEvent(new MoveEvent(client.player.getPos(), + recordTick(new MoveEvent(client.player.getPos(), client.player.getHeadYaw(), client.player.getPitch())); } }; diff --git a/src/main/java/ru/themixray/repeating_mod/event/events/MoveEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/MoveEvent.java index 97054ca..9506eae 100644 --- a/src/main/java/ru/themixray/repeating_mod/event/events/MoveEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/MoveEvent.java @@ -10,6 +10,8 @@ public class MoveEvent extends RecordEvent { 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]), @@ -29,9 +31,13 @@ public class MoveEvent extends RecordEvent { 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()); - Main.client.player.move(MovementType.SELF, v); - Main.client.player.setYaw(yaw); - Main.client.player.setPitch(pitch); + 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); } } From 5d5e628cdf41ae0532ffac25a44fea7b787386d7 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 20:18:04 +0300 Subject: [PATCH 17/29] add dev artifacts --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index e0fa54f..c0a9513 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,16 @@ Toggle recording | not specified by default Toggle replay | not specified by default ``` +## Where to download + +### 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) + +### Developement artifacts + +Artifacts are automatically built with [Gitea Actions](https://git.meex.lol/MeexReay/repeating_mod/actions) on each commit + ## Roadmap - [ ] relative mode for repeating actions (like mining) From 38127eb69f2ff81b3ba84791f28837e835e7f130 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 20:35:23 +0300 Subject: [PATCH 18/29] make img folder for readme images --- README.md | 4 ++-- img/menu.png | Bin 0 -> 135226 bytes preview.gif => img/preview.gif | Bin 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 img/menu.png rename preview.gif => img/preview.gif (100%) diff --git a/README.md b/README.md index c0a9513..d8959df 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ Simply start recording, perform any actions, stop the recording, return to the s ### Showcase -![Preview gif](preview.gif) +![Preview gif](img/preview.gif) This is how menu looks like: -![repeating mod menu](https://github.com/MeexReay/repeating-mod/assets/127148610/4123068f-b150-45ae-8ae3-fcaa0e6bb9f8) +![repeating mod menu](img/menu.png) ### Controls diff --git a/img/menu.png b/img/menu.png new file mode 100644 index 0000000000000000000000000000000000000000..5cf79282973bd1efb06d669db04a221864266cee GIT binary patch literal 135226 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 HP6 Date: Sat, 14 Jun 2025 21:38:30 +0300 Subject: [PATCH 19/29] fix gitea actions --- .gitea/workflows/java.yml | 2 +- README.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/java.yml b/.gitea/workflows/java.yml index 2dd136f..5c47e28 100644 --- a/.gitea/workflows/java.yml +++ b/.gitea/workflows/java.yml @@ -1,4 +1,4 @@ -on: [push, pull_request] +on: [ push ] name: Build fabric mod diff --git a/README.md b/README.md index d8959df..ca695e9 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,10 @@ Toggle replay | not specified by default 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) -### Developement artifacts +### Development artifacts -Artifacts are automatically built with [Gitea Actions](https://git.meex.lol/MeexReay/repeating_mod/actions) on each commit +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 From 4714b1dbfbe09f03ed064970ba5cf596e83b5687 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 22:22:27 +0300 Subject: [PATCH 20/29] add compatible with comment --- gradle.properties | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 489444b..49aab6b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,6 @@ fabric_version=0.102.0+1.21 # Mod Properties mod_version = 1.1.2+1.21 maven_group = ru.themixray -archives_base_name = repeating-mod \ No newline at end of file +archives_base_name = repeating-mod + +# Compatible with: 1.21, 1.21.1 \ No newline at end of file From 412c3f47ab3fa025d0750d6e5f3075c5fa8c2688 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sat, 14 Jun 2025 23:46:18 +0300 Subject: [PATCH 21/29] port to 1.21.2, MOVEMENTS ARE BROKEN --- gradle.properties | 8 +- .../java/ru/themixray/repeating_mod/Main.java | 54 +---- .../event/events/InputEvent.java | 208 ++++++++++-------- .../repeating_mod/mixin/EntityMixin.java | 4 +- .../render/shader/ShaderManager.java | 2 +- 5 files changed, 131 insertions(+), 145 deletions(-) diff --git a/gradle.properties b/gradle.properties index 49aab6b..bcf329b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,16 +4,16 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21 -yarn_mappings=1.21+build.9 +minecraft_version=1.21.2 +yarn_mappings=1.21.2+build.1 loader_version=0.16.14 loom_version=1.10-SNAPSHOT # Fabric API -fabric_version=0.102.0+1.21 +fabric_version=0.106.1+1.21.2 # Mod Properties -mod_version = 1.1.2+1.21 +mod_version = 1.1.2+1.21.2 maven_group = ru.themixray archives_base_name = repeating-mod diff --git a/src/main/java/ru/themixray/repeating_mod/Main.java b/src/main/java/ru/themixray/repeating_mod/Main.java index 17cf367..296904c 100644 --- a/src/main/java/ru/themixray/repeating_mod/Main.java +++ b/src/main/java/ru/themixray/repeating_mod/Main.java @@ -209,46 +209,14 @@ public class Main implements ClientModInitializer { return; } - InputEvent l = ((InputEvent) now_record.getLastEvent("input")); - if (l == null) { - InputEvent e = new InputEvent( - 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 { - InputEvent e = new InputEvent( - ((Boolean) client.player.input.sneaking == l.sneaking) ? null : client.player.input.sneaking, - ((Boolean) client.player.input.jumping == l.jumping) ? null : client.player.input.jumping, - (((Float) client.player.input.movementSideways).equals(l.movementSideways)) ? null : client.player.input.movementSideways, - (((Float) client.player.input.movementForward).equals(l.movementForward)) ? null : client.player.input.movementForward, - ((Boolean) client.player.input.pressingForward == l.pressingForward) ? null : client.player.input.pressingForward, - ((Boolean) client.player.input.pressingBack == l.pressingBack) ? null : client.player.input.pressingBack, - ((Boolean) client.player.input.pressingLeft == l.pressingLeft) ? null : client.player.input.pressingLeft, - ((Boolean) client.player.input.pressingRight == l.pressingRight) ? null : client.player.input.pressingRight, - client.player.getHeadYaw(), Main.client.player.getBodyYaw(),client.player.getPitch(), - ((Boolean) client.player.isSprinting() == l.sprinting) ? null : client.player.isSprinting(), - client.player.getYaw(),client.player.getMovementSpeed()); + InputEvent curr = InputEvent.current(); + if (curr == null) return; - if (!(e.isEmpty() && - e.yaw == l.yaw && - e.head_yaw == l.head_yaw && - e.pitch == l.pitch && - e.body_yaw == l.body_yaw)) { - e.fillEmpty(l); - recordTick(e); - } + InputEvent last = ((InputEvent) now_record.getLastEvent("input")); + if (last == null) { + recordTick(curr); + } else if (!curr.equals(last)) { + recordTick(curr.differs(last)); } } @@ -332,10 +300,10 @@ public class Main implements ClientModInitializer { client.player.sendMessage(Text.literal("[") .append(Text.translatable("text.repeating-mod.name")) .append("] ").formatted(Formatting.BOLD,Formatting.DARK_GRAY) - .append(text.formatted(Formatting.RESET).formatted(Formatting.GRAY))); + .append(text.formatted(Formatting.RESET).formatted(Formatting.GRAY)), false); } - public static void sendDebug(String s) { - client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s))); - } +// public static void sendDebug(String s) { +// client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s)), false); +// } } diff --git a/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java index 74be7c5..e0ce865 100644 --- a/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java @@ -1,19 +1,17 @@ package ru.themixray.repeating_mod.event.events; +import net.minecraft.util.PlayerInput; import ru.themixray.repeating_mod.Main; import ru.themixray.repeating_mod.event.RecordEvent; public class InputEvent 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 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; @@ -21,94 +19,118 @@ public class InputEvent extends RecordEvent { public float pitch; public float speed; - public InputEvent(Boolean sneaking, - Boolean jumping, - Float movementSideways, - Float movementForward, - Boolean pressingForward, - Boolean pressingBack, - Boolean pressingLeft, - Boolean pressingRight, + 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() + ); + } + + 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, - 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.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.sprinting = sprinting; this.yaw = yaw; this.speed = speed; } + /** + * 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 + ); + } + 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 : 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])); + (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]) + ); } protected String[] serializeArgs() { return new String[] { - ((sneaking == null) ? "n" : (sneaking ? "1" : "0")), // sneaking - ((jumping == null) ? "n" : (jumping ? "1" : "0")), // jumping - ((movementSideways == null) ? "n" : String.valueOf(movementSideways)), // movement sideways - ((movementForward == null) ? "n" : String.valueOf(movementForward)), // movement forward - ((pressingForward == null) ? "n" : (pressingForward ? "1" : "0")), // pressing forward - ((pressingBack == null) ? "n" : (pressingBack ? "1" : "0")), // pressing back - ((pressingLeft == null) ? "n" : (pressingLeft ? "1" : "0")), // pressing left - ((pressingRight == null) ? "n" : (pressingRight ? "1" : "0")), // pressing right - String.valueOf(head_yaw), // head yaw - String.valueOf(body_yaw), // body yaw - String.valueOf(pitch), // pitch - ((sprinting == null) ? "n" : (sprinting ? "1" : "0")), // sprinting - String.valueOf(yaw), // yaw - String.valueOf(speed) // speed + ((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), }; } - public void fillEmpty(InputEvent 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 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; } public void replay() { @@ -117,8 +139,8 @@ public class InputEvent extends RecordEvent { public void inputCallback() { if (Main.client.player != null) { - if (sprinting != null && Main.client.player.isSprinting() != sprinting) - Main.client.player.setSprinting(sprinting); + 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) @@ -129,22 +151,18 @@ public class InputEvent extends RecordEvent { 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; + + 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 + ); } } } diff --git a/src/main/java/ru/themixray/repeating_mod/mixin/EntityMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/EntityMixin.java index 9bf8341..93257cc 100644 --- a/src/main/java/ru/themixray/repeating_mod/mixin/EntityMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/EntityMixin.java @@ -20,8 +20,8 @@ public abstract class EntityMixin { if (getUuid().equals(Main.client.player.getUuid())) { if (Main.me.is_replaying) { if (Main.input_replay != null && - Main.input_replay.sprinting != null && - Main.input_replay.sprinting != sprinting) { + Main.input_replay.sprint != null && + Main.input_replay.sprint != sprinting) { ci.cancel(); } } diff --git a/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java b/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java index 34c0d25..0879153 100644 --- a/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java +++ b/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java @@ -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) { From d101b11c36c0232b3a1cac9da4d8f570f3ce423a Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sun, 15 Jun 2025 16:23:04 +0300 Subject: [PATCH 22/29] fix movements 1.21.2 --- gradle.properties | 2 +- .../event/events/InputEvent.java | 54 ++++++++++++------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/gradle.properties b/gradle.properties index bcf329b..1c01598 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,4 +17,4 @@ mod_version = 1.1.2+1.21.2 maven_group = ru.themixray archives_base_name = repeating-mod -# Compatible with: 1.21, 1.21.1 \ No newline at end of file +# Compatible with: 1.21.2, ? \ No newline at end of file diff --git a/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java index e0ce865..ac79afe 100644 --- a/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java @@ -18,6 +18,8 @@ public class InputEvent extends RecordEvent { 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; @@ -33,7 +35,9 @@ public class InputEvent extends RecordEvent { Main.client.player.getBodyYaw(), Main.client.player.getPitch(), Main.client.player.getYaw(), - Main.client.player.getMovementSpeed() + Main.client.player.getMovementSpeed(), + Main.client.player.input.movementForward, + Main.client.player.input.movementSideways ); } @@ -48,7 +52,9 @@ public class InputEvent extends RecordEvent { float body_yaw, float head_pitch, float yaw, - float speed) { + float speed, + float movementForward, + float movementSideways) { this.forward = forward; this.backward = backward; this.left = left; @@ -62,6 +68,8 @@ public class InputEvent extends RecordEvent { this.pitch = head_pitch; this.yaw = yaw; this.speed = speed; + this.movementForward = movementForward; + this.movementSideways = movementSideways; } /** @@ -80,7 +88,9 @@ public class InputEvent extends RecordEvent { body_yaw, pitch, yaw, - speed + speed, + movementForward, + movementSideways ); } @@ -97,24 +107,28 @@ public class InputEvent extends RecordEvent { Float.parseFloat(a[8]), Float.parseFloat(a[9]), Float.parseFloat(a[10]), - Float.parseFloat(a[11]) + 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), + ((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) }; } @@ -130,7 +144,9 @@ public class InputEvent extends RecordEvent { event.head_yaw == head_yaw && event.body_yaw == body_yaw && event.yaw == yaw && - event.pitch == pitch; + event.pitch == pitch && + event.movementForward == movementForward && + event.movementSideways == movementSideways; } public void replay() { @@ -152,8 +168,10 @@ public class InputEvent extends RecordEvent { if (Main.client.player.getMovementSpeed() != speed) Main.client.player.setMovementSpeed(speed); - PlayerInput input = Main.client.player.input.playerInput; + Main.client.player.input.movementSideways = movementSideways; + Main.client.player.input.movementForward = movementForward; + 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, From 06634a8704ab69a6531cc0ce43648a4eed528d2e Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sun, 15 Jun 2025 19:59:29 +0300 Subject: [PATCH 23/29] set license wtfpl in mod --- src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 9bbbbe2..4d3612f 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -13,7 +13,7 @@ "sources": "https://github.com/MeexReay/repeating-mod" }, - "license": "CC0-1.0", + "license": "WTFPL", "icon": "icon.png", "environment": "client", From f0827884065dfafe4e2737ef01bafdc3b7e7684e Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sun, 15 Jun 2025 20:06:31 +0300 Subject: [PATCH 24/29] set fabric mod json 1.21. --- src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 4d3612f..88e2fff 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -29,7 +29,7 @@ "depends": { "fabricloader": ">=0.14.14", "fabric-api": "*", - "minecraft": ">=1.20", + "minecraft": ">=1.21.2", "java": ">=17" }, "suggests": { From c65e9065006e9a04da8b176c05a6e79ace667b90 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Sun, 15 Jun 2025 20:36:55 +0300 Subject: [PATCH 25/29] port to 1.21.4, RECORDS LIST IS BROKEN --- gradle.properties | 10 +++++----- .../ru/themixray/repeating_mod/mixin/InputMixin.java | 2 +- .../repeating_mod/widget/RecordListWidget.java | 12 ++++++------ src/main/resources/fabric.mod.json | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/gradle.properties b/gradle.properties index 1c01598..63462f5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,17 +4,17 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.2 -yarn_mappings=1.21.2+build.1 +minecraft_version=1.21.4 +yarn_mappings=1.21.4+build.8 loader_version=0.16.14 loom_version=1.10-SNAPSHOT # Fabric API -fabric_version=0.106.1+1.21.2 +fabric_version=0.119.3+1.21.4 # Mod Properties -mod_version = 1.1.2+1.21.2 +mod_version = 1.1.2+1.21.4 maven_group = ru.themixray archives_base_name = repeating-mod -# Compatible with: 1.21.2, ? \ No newline at end of file +# Compatible with: 1.21.4, ? \ No newline at end of file diff --git a/src/main/java/ru/themixray/repeating_mod/mixin/InputMixin.java b/src/main/java/ru/themixray/repeating_mod/mixin/InputMixin.java index 33acbf1..261c59c 100644 --- a/src/main/java/ru/themixray/repeating_mod/mixin/InputMixin.java +++ b/src/main/java/ru/themixray/repeating_mod/mixin/InputMixin.java @@ -10,7 +10,7 @@ import ru.themixray.repeating_mod.Main; @Mixin(KeyboardInput.class) public abstract class InputMixin { @Inject(at = @At(value = "TAIL"), method = "tick") - private void onTickTail(boolean slowDown, float f, CallbackInfo ci) { + private void onTickTail(CallbackInfo ci) { if (Main.me.is_replaying) { if (Main.input_replay != null) { Main.input_replay.inputCallback(); diff --git a/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java b/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java index 5b7a7e3..6ab167d 100644 --- a/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java +++ b/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java @@ -26,13 +26,18 @@ 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) { + protected void renderWidget(DrawContext ctx, int mouseX, int mouseY, float delta) { int y = 0; for (RecordWidget wid: widgets) { wid.setY(y); @@ -63,11 +68,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); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 88e2fff..4a40393 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -29,7 +29,7 @@ "depends": { "fabricloader": ">=0.14.14", "fabric-api": "*", - "minecraft": ">=1.21.2", + "minecraft": ">=1.21.4", "java": ">=17" }, "suggests": { From ac1ee8ec6da34e9cbc11d8f05b3875b339c4724c Mon Sep 17 00:00:00 2001 From: MeexReay Date: Wed, 18 Jun 2025 15:57:29 +0300 Subject: [PATCH 26/29] fix record list widget --- .../repeating_mod/widget/RecordListWidget.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java b/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java index 6ab167d..b17af92 100644 --- a/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java +++ b/src/main/java/ru/themixray/repeating_mod/widget/RecordListWidget.java @@ -38,20 +38,28 @@ public class RecordListWidget extends ScrollableWidget { @Override protected void renderWidget(DrawContext ctx, int mouseX, int mouseY, float delta) { - int y = 0; + 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) { @@ -125,7 +133,7 @@ public class RecordListWidget extends ScrollableWidget { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - return checkTransportNF(mouseX, mouseY + getScrollY(), button) || super.mouseClicked(mouseX, mouseY, button); + return checkTransportNF(mouseX, mouseY, button) || super.checkScrollbarDragged(mouseX, mouseY, button); } @Override From 59a2175fb2e70b25ac67bb53e8a5c7312abe104f Mon Sep 17 00:00:00 2001 From: MeexReay Date: Wed, 18 Jun 2025 16:18:48 +0300 Subject: [PATCH 27/29] port to 1.21.5 --- gradle.properties | 10 +++++----- .../event/events/BlockInteractEvent.java | 4 ++-- .../repeating_mod/event/events/InputEvent.java | 17 +++++++++++++---- .../render/shader/ShaderManager.java | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/gradle.properties b/gradle.properties index 63462f5..68634eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,17 +4,17 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.4 -yarn_mappings=1.21.4+build.8 +minecraft_version=1.21.5 +yarn_mappings=1.21.5+build.1 loader_version=0.16.14 loom_version=1.10-SNAPSHOT # Fabric API -fabric_version=0.119.3+1.21.4 +fabric_version=0.127.0+1.21.5 # Mod Properties -mod_version = 1.1.2+1.21.4 +mod_version = 1.1.2+1.21.5 maven_group = ru.themixray archives_base_name = repeating-mod -# Compatible with: 1.21.4, ? \ No newline at end of file +# Compatible with: 1.21.5 \ No newline at end of file diff --git a/src/main/java/ru/themixray/repeating_mod/event/events/BlockInteractEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/BlockInteractEvent.java index 789ea8f..16a8425 100644 --- a/src/main/java/ru/themixray/repeating_mod/event/events/BlockInteractEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/BlockInteractEvent.java @@ -19,7 +19,7 @@ public class BlockInteractEvent extends RecordEvent { Double.parseDouble(a[0]), Double.parseDouble(a[1]), Double.parseDouble(a[2])), - Direction.byId(Integer.parseInt(a[4])), + Direction.byIndex(Integer.parseInt(a[4])), new BlockPos( Integer.parseInt(a[0]), Integer.parseInt(a[1]), @@ -44,7 +44,7 @@ public class BlockInteractEvent extends RecordEvent { String.valueOf(hitResult.getBlockPos().getY()), String.valueOf(hitResult.getBlockPos().getZ()), (hitResult.isInsideBlock() ? "1" : "0"), - String.valueOf(hitResult.getSide().getId()), + String.valueOf(hitResult.getSide().getIndex()), hand.name() }; } diff --git a/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java index ac79afe..01d1f39 100644 --- a/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java +++ b/src/main/java/ru/themixray/repeating_mod/event/events/InputEvent.java @@ -1,9 +1,13 @@ 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; @@ -36,8 +40,8 @@ public class InputEvent extends RecordEvent { Main.client.player.getPitch(), Main.client.player.getYaw(), Main.client.player.getMovementSpeed(), - Main.client.player.input.movementForward, - Main.client.player.input.movementSideways + Main.client.player.input.getMovementInput().y, + Main.client.player.input.getMovementInput().x ); } @@ -168,8 +172,13 @@ public class InputEvent extends RecordEvent { if (Main.client.player.getMovementSpeed() != speed) Main.client.player.setMovementSpeed(speed); - Main.client.player.input.movementSideways = movementSideways; - Main.client.player.input.movementForward = movementForward; + 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( diff --git a/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java b/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java index 0879153..f5e26a6 100644 --- a/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java +++ b/src/main/java/ru/themixray/repeating_mod/render/shader/ShaderManager.java @@ -1,6 +1,6 @@ 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; From 0b3bac264f036b5b4166b72f6c8b8c0cb11053bb Mon Sep 17 00:00:00 2001 From: MeexReay Date: Wed, 18 Jun 2025 18:17:57 +0300 Subject: [PATCH 28/29] port to 1.21.6 --- gradle.properties | 6 +++--- .../repeating_mod/RepeatingScreen.java | 2 +- .../repeating_mod/widget/RecordWidget.java | 17 +++++------------ 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/gradle.properties b/gradle.properties index 68634eb..a363b27 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,13 +4,13 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.5 -yarn_mappings=1.21.5+build.1 +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.5 +fabric_version=0.127.0+1.21.6 # Mod Properties mod_version = 1.1.2+1.21.5 diff --git a/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java b/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java index 8d95918..0783386 100644 --- a/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java +++ b/src/main/java/ru/themixray/repeating_mod/RepeatingScreen.java @@ -51,7 +51,7 @@ public class RepeatingScreen extends Screen { @Override public void render(DrawContext context, int mouseX, int mouseY, float delta) { - renderBackground(context, mouseX, mouseY, delta); +// renderBackground(context, mouseX, mouseY, delta); for (RenderListener l : render_listeners) { if (l.beforeRender()) { diff --git a/src/main/java/ru/themixray/repeating_mod/widget/RecordWidget.java b/src/main/java/ru/themixray/repeating_mod/widget/RecordWidget.java index 7d53358..5b9954e 100644 --- a/src/main/java/ru/themixray/repeating_mod/widget/RecordWidget.java +++ b/src/main/java/ru/themixray/repeating_mod/widget/RecordWidget.java @@ -1,5 +1,6 @@ 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; @@ -18,6 +19,7 @@ import java.util.List; import java.util.function.Consumer; public class RecordWidget implements Drawable, Widget { + @Getter private RecordState record; private List children; @@ -150,22 +152,13 @@ public class RecordWidget implements Drawable, Widget { children.add(replay_button); } - public RecordState getRecord() { - return record; - } - - public void drawText(int x, int y, DrawContext ctx, List 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 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 @@ -190,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); From 654589355d73c910bbe987f9e22f986cb924b367 Mon Sep 17 00:00:00 2001 From: MeexReay Date: Wed, 18 Jun 2025 18:18:55 +0300 Subject: [PATCH 29/29] fix version name --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index a363b27..780fbef 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,8 +13,8 @@ loom_version=1.10-SNAPSHOT fabric_version=0.127.0+1.21.6 # Mod Properties -mod_version = 1.1.2+1.21.5 +mod_version = 1.1.2+1.21.6 maven_group = ru.themixray archives_base_name = repeating-mod -# Compatible with: 1.21.5 \ No newline at end of file +# Compatible with: 1.21.6 \ No newline at end of file