diff --git a/build.gradle.kts b/build.gradle.kts index 6bf4968c..18117a97 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -54,7 +54,7 @@ tasks { allprojects { val mc = "1.21" - val pr = "0.3.0" + val pr = "0.3.1" project.ext["minecraft_version"] = mc project.ext["project_version"] = pr @@ -73,6 +73,7 @@ allprojects { project.ext["license"] = "GPL-3.0" project.ext["github"] = "https://github.com/gmitch215/SocketMC" + project.ext["similar_versions"] = listOf("1.21.1") project.ext["version_type"] = when { version.toString().contains("SNAPSHOT") -> "alpha" version.toString().split("-")[1].startsWith("0") -> "beta" diff --git a/core/src/main/java/xyz/gmitch215/socketmc/instruction/Instruction.java b/core/src/main/java/xyz/gmitch215/socketmc/instruction/Instruction.java index 15b04c33..c52232ba 100644 --- a/core/src/main/java/xyz/gmitch215/socketmc/instruction/Instruction.java +++ b/core/src/main/java/xyz/gmitch215/socketmc/instruction/Instruction.java @@ -33,7 +33,7 @@ *
  • Instructions are immutable and cannot be modified after creation.
  • *
  • Instructions are serializable and can be sent over the network as byte arrays.
  • *
  • All X, Y, Height, Width, and other measurements used in drawing instructions are in pixels.
  • - *
  • Players render things on the screen based on their own FPS (Frames Per Second), hence the provision of timed renderings in milliseconds.
  • + *
  • Players render things on the screen based on their own FPS (Frames Per Second), hence the provision of timed renderings in milliseconds. In addition, you can specify {@code -1} for an infinite duration.
  • *
  • SocketMC v0.1.3 introduced a permission system that allows or disallows specific types of Instructions. If permission is not given, the Instruction will silently fail.
  • * */ diff --git a/core/src/main/java/xyz/gmitch215/socketmc/retriever/RetrieverType.java b/core/src/main/java/xyz/gmitch215/socketmc/retriever/RetrieverType.java index f9499471..855e7dec 100644 --- a/core/src/main/java/xyz/gmitch215/socketmc/retriever/RetrieverType.java +++ b/core/src/main/java/xyz/gmitch215/socketmc/retriever/RetrieverType.java @@ -2,7 +2,9 @@ import org.jetbrains.annotations.NotNull; import xyz.gmitch215.socketmc.config.ModPermission; +import xyz.gmitch215.socketmc.instruction.Instruction; import xyz.gmitch215.socketmc.spigot.SocketPlugin; +import xyz.gmitch215.socketmc.util.Identifier; import xyz.gmitch215.socketmc.util.InputType; import java.io.*; @@ -128,6 +130,21 @@ public final class RetrieverType implements Serializable { @RetrieverPermission(ModPermission.READ_GAME_PROPERTIES) public static final RetrieverType HIDDEN_PLAYERS = new RetrieverType<>("hidden_players", UUID[].class); + /** + *

    A retriever for all of the drawn contents on the client's screen made through SocketMC Instructions.

    + *

    This currently includes the following instructions:

    + * + */ + @RetrieverPermission(ModPermission.READ_GUI_PROPERTIES) + public static final RetrieverType DRAWN_CONTENTS = new RetrieverType<>("drawn_contents", Identifier[].class); + // private final String id; diff --git a/core/src/main/java/xyz/gmitch215/socketmc/screen/CustomScreen.java b/core/src/main/java/xyz/gmitch215/socketmc/screen/CustomScreen.java index 212e9111..86c8c25f 100644 --- a/core/src/main/java/xyz/gmitch215/socketmc/screen/CustomScreen.java +++ b/core/src/main/java/xyz/gmitch215/socketmc/screen/CustomScreen.java @@ -1,13 +1,16 @@ package xyz.gmitch215.socketmc.screen; -import xyz.gmitch215.socketmc.screen.layout.Layout; -import xyz.gmitch215.socketmc.util.render.text.Text; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; +import xyz.gmitch215.socketmc.screen.layout.Layout; +import xyz.gmitch215.socketmc.util.render.text.Text; import java.io.Serial; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Represents a custom screen to be displayed on the client's screen. @@ -23,6 +26,7 @@ public final class CustomScreen extends AbstractScreen { private boolean closeableOnEscape = true; private final List children = new ArrayList<>(); + private final Map attributes = new HashMap<>(); /** * Constructs a new screen with the given title. @@ -174,7 +178,86 @@ public void setCloseableOnEscape(boolean closeableOnEscape) { this.closeableOnEscape = closeableOnEscape; } + /** + * Gets an immutable copy of the attributes of this screen. + * @return Map of Attributes + */ + @Unmodifiable + @NotNull + public Map getAttributes() { + return Map.copyOf(attributes); + } + + /** + * Gets an attribute from this screen. + * @param key the key of the attribute + * @return the attribute value, or null if the attribute does not exist + * @throws IllegalArgumentException if the key is null + */ + @Nullable + public Object getAttribute(@NotNull String key) throws IllegalArgumentException { + if (key == null) throw new IllegalArgumentException("Key cannot be null"); + return attributes.get(key); + } + + /** + * Gets an attribute from this screen. + * @param key the key of the attribute + * @param def the default value if the attribute does not exist + * @return the attribute value, or the default value if the attribute does not exist + * @throws IllegalArgumentException if the key is null + */ + public Object getAttribute(@NotNull String key, @Nullable Object def) throws IllegalArgumentException { + if (key == null) throw new IllegalArgumentException("Key cannot be null"); + return attributes.getOrDefault(key, def); + } + + /** + * Gets an attribute from this screen. + * @param key the key of the attribute + * @param type the type of the attribute + * @return the attribute value, or null if the attribute does not exist + * @param the type of the attribute + */ + @Nullable + public T getAttribute(@NotNull String key, @NotNull Class type) { + if (key == null) throw new IllegalArgumentException("Key cannot be null"); + if (type == null) throw new IllegalArgumentException("Type cannot be null"); + + return type.cast(attributes.get(key)); + } + + /** + * Gets an attribute from this screen. + * @param key the key of the attribute + * @param type the type of the attribute + * @param def the default value if the attribute does not exist + * @return the attribute value, or the default value if the attribute does not exist + * @param the type of the attribute + */ + @Nullable + public T getAttribute(@NotNull String key, @NotNull Class type, @Nullable T def) { + if (key == null) throw new IllegalArgumentException("Key cannot be null"); + if (type == null) throw new IllegalArgumentException("Type cannot be null"); + + return type.cast(attributes.getOrDefault(key, def)); + } + + /** + * Sets an attribute for this screen. + * @param key the key of the attribute + * @param value the value of the attribute + * @throws IllegalArgumentException if the key is null + */ + public void setAttribute(@NotNull String key, @Nullable Object value) throws IllegalArgumentException { + if (key == null) throw new IllegalArgumentException("Key cannot be null"); + + if (value == null) attributes.remove(key); + else attributes.put(key, value); + } + @Override + @NotNull public String toString() { return "CustomScreen{" + "title='" + titleJSON + '\'' + @@ -182,6 +265,8 @@ public String toString() { ", children=" + children + ", background=" + background + ", layout=" + layout + + ", closeableOnEscape=" + closeableOnEscape + + ", attributes=" + attributes + '}'; } } diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/Arm.java b/core/src/main/java/xyz/gmitch215/socketmc/util/Arm.java new file mode 100644 index 00000000..c4c0e896 --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/Arm.java @@ -0,0 +1,41 @@ +package xyz.gmitch215.socketmc.util; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents a player's arm. + */ +public enum Arm { + + /** + * Represents the left arm. + */ + LEFT, + + /** + * Represents the right arm. + */ + RIGHT; + + /** + * Returns the opposite arm. + * @return the opposite arm + */ + @NotNull + public Arm opposite() { + return this == LEFT ? RIGHT : LEFT; + } + + /** + * Gets the Arm by its ordinal. + * @param ordinal + * @return Arm by ordinal + */ + @NotNull + public static Arm byOrdinal(int ordinal) { + return values()[ordinal]; + } + + + +} diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/Identifier.java b/core/src/main/java/xyz/gmitch215/socketmc/util/Identifier.java index 4a2a115c..1568b3e8 100644 --- a/core/src/main/java/xyz/gmitch215/socketmc/util/Identifier.java +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/Identifier.java @@ -5,6 +5,7 @@ import java.io.Serial; import java.io.Serializable; import java.util.Objects; +import java.util.UUID; /** *

    Represents a Namespaced Identifier.

    @@ -73,4 +74,24 @@ public static Identifier minecraft(@NotNull String path) { return new Identifier("minecraft", path); } + /** + * Creates a new Identifier with the namespace "socketmc". + * @param path The path of the Identifier. + * @return The new Identifier. + */ + @NotNull + public static Identifier socketmc(@NotNull String path) { + return new Identifier("socketmc", path); + } + + /** + * Creates a new random Identifier with the namespace "socketmc" and a random UUID as its path. + * @return The new random Identifier. + */ + @NotNull + public static Identifier random() { + UUID uuid = UUID.randomUUID(); + return Identifier.socketmc(uuid.toString()); + } + } diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/LifecycleMap.java b/core/src/main/java/xyz/gmitch215/socketmc/util/LifecycleMap.java index a770596c..b77a2ff7 100644 --- a/core/src/main/java/xyz/gmitch215/socketmc/util/LifecycleMap.java +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/LifecycleMap.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -15,6 +16,7 @@ */ public class LifecycleMap implements Iterable { + private final Map identifiers = new HashMap<>(); private final Map origin = new HashMap<>(); private final Map duration = new HashMap<>(); @@ -38,9 +40,11 @@ public LifecycleMap(@Nullable LifecycleMap map) { * Runs the map, removing any expired values. */ public void run() { - for (T key : origin.keySet()) { + Iterator it = origin.keySet().iterator(); + while (it.hasNext()) { + T key = it.next(); if (getRemainingTime(key) <= 0) { - origin.remove(key); + it.remove(); duration.remove(key); } } @@ -48,54 +52,160 @@ public void run() { /** * Associates the specified value with the specified key in this map. + * @param id The identifier for the key * @param key The key with which the specified value is to be associated * @param startMillis The start time of the value, in milliseconds - * @param durationMillis The duration of the value, in milliseconds + * @param durationMillis The duration of the value, in milliseconds (use {@code -1} for infinite) + * @return The identifier of the key */ - public void put(@NotNull T key, long startMillis, long durationMillis) { + @NotNull + public Identifier put(@NotNull Identifier id, @NotNull T key, long startMillis, long durationMillis) { + if (id == null) throw new IllegalArgumentException("Identifier cannot be null"); + if (key == null) throw new IllegalArgumentException("Key cannot be null"); + if (startMillis < 0) throw new IllegalArgumentException("Start time cannot be negative"); + if (durationMillis < -1) throw new IllegalArgumentException("Duration cannot be less than -1"); + + identifiers.put(key, id); origin.put(key, startMillis); duration.put(key, durationMillis); + + return id; + } + + /** + * Associates the specified value with the specified key in this map. + * @param key The key with which the specified value is to be associated + * @param startMillis The start time of the value, in milliseconds + * @param durationMillis The duration of the value, in milliseconds (use {@code -1} for infinite) + * @return The identifier of the key + */ + @NotNull + public Identifier put(@NotNull T key, long startMillis, long durationMillis) { + return put(Identifier.random(), key, startMillis, durationMillis); } /** * Stores the specified key in this map for the specified duration. + * @param id The identifier for the key * @param key The key to store - * @param millis The duration to store the key for, in milliseconds + * @param millis The duration to store the key for, in milliseconds (use {@code -1} for infinite) + * @return The identifier of the key */ - public void store(@NotNull T key, long millis) { - put(key, System.currentTimeMillis(), millis); + @NotNull + public Identifier store(@NotNull Identifier id, @NotNull T key, long millis) { + return put(id, key, System.currentTimeMillis(), millis); } /** - * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. + * Stores the specified key in this map for the specified duration. + * @param key The key to store + * @param millis The duration to store the key for, in milliseconds (use {@code -1} for infinite) + * @return The identifier of the key + */ + @NotNull + public Identifier store(@NotNull T key, long millis) { + return store(Identifier.random(), key, millis); + } + + /** + * Stores the specified key in this map for the specified duration. + * @param id The identifier for the key * @param key The key whose associated value is to be returned * @param time The current time, in milliseconds * @param unit The time unit of the duration + * @return The identifier for the key */ - public void store(@NotNull T key, long time, @NotNull TimeUnit unit) { + @NotNull + public Identifier store(@NotNull Identifier id, @NotNull T key, long time, @NotNull TimeUnit unit) { if (unit == null) throw new IllegalArgumentException("TimeUnit cannot be null"); - put(key, System.currentTimeMillis(), unit.toMillis(time)); + return put(id, key, System.currentTimeMillis(), unit.toMillis(time)); + } + + /** + * Stores the specified key in this map for the specified duration. + * @param key The key whose associated value is to be returned + * @param time The current time, in milliseconds + * @param unit The time unit of the duration + * @return The identifier for the key + */ + @NotNull + public Identifier store(@NotNull T key, long time, @NotNull TimeUnit unit) { + return store(Identifier.random(), key, time, unit); } /** - * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. + * Stores the specified key in this map for the specified duration. + * @param id The identifier for the key * @param key The key whose associated value is to be returned * @param duration The duration to store the key for + * @return The identifier for the key */ - public void store(@NotNull T key, @NotNull Duration duration) { + @NotNull + public Identifier store(@NotNull Identifier id, @NotNull T key, @NotNull Duration duration) { if (duration == null) throw new IllegalArgumentException("TimeUnit cannot be null"); - put(key, System.currentTimeMillis(), duration.toMillis()); + return put(id, key, System.currentTimeMillis(), duration.toMillis()); + } + + /** + * Stores the specified key in this map for the specified duration. + * @param key The key whose associated value is to be returned + * @param duration The duration to store the key for + * @return The identifier for the key + */ + @NotNull + public Identifier store(@NotNull T key, @NotNull Duration duration) { + return store(Identifier.random(), key, duration); + } + + /** + * Stores the specified key in this map for an infinite duration. + * @param id The identifier for the key + * @param key The key whose associated value is to be returned + * @return The identifier for the key + */ + @NotNull + public Identifier storeInfinite(@NotNull Identifier id, @NotNull T key) { + return store(id, key, -1); } /** - * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. + * Stores the specified key in this map for an infinite duration. + * @param key The key whose associated value is to be returned + * @return The identifier for the key + */ + @NotNull + public Identifier storeInfinite(@NotNull T key) { + return store(key, -1); + } + + /** + * Removes the mapping for the specified key from this map if present. * @param key The key whose associated value is to be returned */ public void remove(@NotNull T key) { + identifiers.remove(key); origin.remove(key); duration.remove(key); } + /** + * Removes the mapping for the specified identifier from this map if present. + * @param id The identifier whose associated value is to be removed + * @return The key that was removed, or null if the identifier was not present + */ + @Nullable + public T remove(@NotNull Identifier id) { + if (id == null) throw new IllegalArgumentException("Identifier cannot be null"); + T key = getContents().get(id); + + if (key != null) { + remove(key); + return key; + } + + return null; + } + /** * Returns the start time of the specified key. * @param key The key whose start time is to be returned @@ -117,13 +227,57 @@ public long getDuration(@NotNull T key) { /** * Returns the remaining time of the specified key. * @param key The key whose remaining time is to be returned - * @return The remaining time of the key, in milliseconds, or -1 if the key is not present + * @return The remaining time of the key (in milliseconds), {@code -1} if the key is not present, or {@link Long#MAX_VALUE} if the key is infinite */ public long getRemainingTime(@NotNull T key) { if (!origin.containsKey(key)) return -1; + if (duration.get(key) == -1) return Long.MAX_VALUE; + return (origin.get(key) + duration.get(key)) - System.currentTimeMillis(); } + /** + * Returns true if the specified key has an infinite duration. + * @param key The key whose duration is to be checked + * @return True if the key has an infinite duration + */ + public boolean isInfinite(@NotNull T key) { + return getDuration(key) == -1; + } + + /** + * Returns the identifier of the specified key. + * @param key The key whose identifier is to be returned + * @return The identifier of the key + */ + @NotNull + public Identifier getIdentifier(@NotNull T key) { + return identifiers.get(key); + } + + /** + * Gets an immutable copy of the contents of the LifecycleMap as a map of identifiers to keys. + * @return The contents of the LifecycleMap + */ + @NotNull + public Map getContents() { + Map contents = new HashMap<>(); + + for (T key : origin.keySet()) + contents.put(identifiers.get(key), key); + + return Map.copyOf(contents); + } + + /** + * Fetches an immutable set of the identifiers in the map. + * @return Set of identifiers for their keys + */ + @NotNull + public Set getIdentifiers() { + return Set.copyOf(identifiers.values()); + } + /** * Gets the size of the map. * @return The size of the map @@ -141,9 +295,34 @@ public boolean containsKey(@NotNull T key) { return origin.containsKey(key); } + /** + * Returns true if this map contains a mapping for the specified identifier. + * @param id The identifier whose presence in this map is to be tested + * @return True if this map contains a mapping for the specified identifier + */ + public boolean containsIdentifier(@NotNull Identifier id) { + return identifiers.containsValue(id); + } + @NotNull @Override public Iterator iterator() { return origin.keySet().iterator(); } + + /** + * Removes a specific key from multiple LifecycleMaps. + * @param id The identifier of the key to remove + * @param maps The LifecycleMaps to remove the key from + * @throws IllegalArgumentException if the maps are null + */ + public static void removeIn(@NotNull Identifier id, @NotNull LifecycleMap... maps) { + if (id == null) throw new IllegalArgumentException("Identifier cannot be null"); + if (maps == null) throw new IllegalArgumentException("Maps cannot be null"); + + for (LifecycleMap map : maps) { + if (map.remove(id) != null) + return; + } + } } diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/option/AttackIndicator.java b/core/src/main/java/xyz/gmitch215/socketmc/util/option/AttackIndicator.java new file mode 100644 index 00000000..276ab8cb --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/option/AttackIndicator.java @@ -0,0 +1,37 @@ +package xyz.gmitch215.socketmc.util.option; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents the status of the attack indicator. + */ +public enum AttackIndicator { + + /** + * The attack indicator is disabled. + */ + OFF, + + /** + * The attack indicator is displayed in the crosshair. + */ + CROSSHAIR, + + /** + * The attack indicator is displayed in the hotbar. + */ + HOTBAR + + ; + + /** + * Gets the AttackIndicator by its ordinal. + * @param ordinal + * @return AttackIndicator by ordinal + */ + @NotNull + public static AttackIndicator byOrdinal(int ordinal) { + return values()[ordinal]; + } + +} diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/option/ChatVisibility.java b/core/src/main/java/xyz/gmitch215/socketmc/util/option/ChatVisibility.java new file mode 100644 index 00000000..38564585 --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/option/ChatVisibility.java @@ -0,0 +1,37 @@ +package xyz.gmitch215.socketmc.util.option; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents the visibility of chat messages. + */ +public enum ChatVisibility { + + /** + * All chat messages are visible. + */ + FULL, + + /** + * Only chat messages from players that are in the same team are visible. + */ + SYSTEM, + + /** + * No chat messages are visible. + */ + HIDDEN + + ; + + /** + * Gets the ChatVisibility by its ordinal. + * @param ordinal + * @return ChatVisibility by ordinal + */ + @NotNull + public static ChatVisibility byOrdinal(int ordinal) { + return values()[ordinal]; + } + +} diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/option/ChunkUpdatePriority.java b/core/src/main/java/xyz/gmitch215/socketmc/util/option/ChunkUpdatePriority.java new file mode 100644 index 00000000..0d4ae946 --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/option/ChunkUpdatePriority.java @@ -0,0 +1,37 @@ +package xyz.gmitch215.socketmc.util.option; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents the priority for chunk updates. + */ +public enum ChunkUpdatePriority { + + /** + * Chunk updates are not prioritized. + */ + NONE, + + /** + * Chunk updates are prioritized if a player is nearby. + */ + PLAYER_AFFECTED, + + /** + * Chunk updates are prioritized if the client is rendering the chunk. + */ + NEARBY + + ; + + /** + * Gets the ChunkUpdatePriority by its ordinal. + * @param ordinal The ordinal + * @return ChunkUpdatePriority by ordinal + */ + @NotNull + public static ChunkUpdatePriority byOrdinal(int ordinal) { + return values()[ordinal]; + } + +} diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/option/CloudRendering.java b/core/src/main/java/xyz/gmitch215/socketmc/util/option/CloudRendering.java new file mode 100644 index 00000000..bbb56318 --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/option/CloudRendering.java @@ -0,0 +1,37 @@ +package xyz.gmitch215.socketmc.util.option; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents the status of cloud rendering. + */ +public enum CloudRendering { + + /** + * Clouds are not rendered. + */ + OFF, + + /** + * Clouds are rendered in performance mode. + */ + FAST, + + /** + * Clouds are rendered in quality mode. + */ + FANCY + + ; + + /** + * Gets the CloudRendering by its ordinal. + * @param ordinal + * @return CloudRendering by ordinal + */ + @NotNull + public static CloudRendering byOrdinal(int ordinal) { + return values()[ordinal]; + } + +} diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/option/GraphicsQuality.java b/core/src/main/java/xyz/gmitch215/socketmc/util/option/GraphicsQuality.java new file mode 100644 index 00000000..44751f21 --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/option/GraphicsQuality.java @@ -0,0 +1,37 @@ +package xyz.gmitch215.socketmc.util.option; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents the different graphics rendering options. + */ +public enum GraphicsQuality { + + /** + * Graphics are rendered in the fastest way possible. + */ + FAST, + + /** + * Graphics are rendered in a medium quality way. + */ + FANCY, + + /** + * Graphics are rendered in the highest quality possible. + */ + FABULOUS + + ; + + /** + * Gets the GraphicsRendering by its ordinal. + * @param ordinal + * @return GraphicsRendering by ordinal + */ + @NotNull + public static GraphicsQuality byOrdinal(int ordinal) { + return values()[ordinal]; + } + +} diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/option/NarratorStatus.java b/core/src/main/java/xyz/gmitch215/socketmc/util/option/NarratorStatus.java new file mode 100644 index 00000000..8b640711 --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/option/NarratorStatus.java @@ -0,0 +1,39 @@ +package xyz.gmitch215.socketmc.util.option; + +/** + * Represents the status of the narrator. + */ +public enum NarratorStatus { + + /** + * The narrator is off. + */ + OFF, + + /** + * The narrator speaks on everything. + */ + ALL, + + /** + * The narrator speaks on chat messages. + */ + CHAT, + + /** + * The narrator speaks on system messages. + */ + SYSTEM + + ; + + /** + * Gets the NarratorStatus by its ordinal. + * @param ordinal the ordinal + * @return NarratorStatus by ordinal + */ + public static NarratorStatus byOrdinal(int ordinal) { + return values()[ordinal]; + } + +} diff --git a/core/src/main/java/xyz/gmitch215/socketmc/util/option/ParticleRendering.java b/core/src/main/java/xyz/gmitch215/socketmc/util/option/ParticleRendering.java new file mode 100644 index 00000000..0c5701fc --- /dev/null +++ b/core/src/main/java/xyz/gmitch215/socketmc/util/option/ParticleRendering.java @@ -0,0 +1,37 @@ +package xyz.gmitch215.socketmc.util.option; + +import org.jetbrains.annotations.NotNull; + +/** + * Represents the different ways particles can be rendered. + */ +public enum ParticleRendering { + + /** + * Particles are rendered in full. + */ + ALL, + + /** + * Particles are rendered in a reduced form. + */ + DECREASED, + + /** + * Particles are not rendered at all. + */ + MINIMAL + + ; + + /** + * Gets the ParticleRendering by its ordinal. + * @param ordinal + * @return ParticleRendering by ordinal + */ + @NotNull + public static ParticleRendering byOrdinal(int ordinal) { + return values()[ordinal]; + } + +} diff --git a/core/src/main/javadoc/xyz/gmitch215/socketmc/util/option/package-info.java b/core/src/main/javadoc/xyz/gmitch215/socketmc/util/option/package-info.java new file mode 100644 index 00000000..5010bfe4 --- /dev/null +++ b/core/src/main/javadoc/xyz/gmitch215/socketmc/util/option/package-info.java @@ -0,0 +1,4 @@ +/** + * Package containing different client options that can be set in the game. + */ +package xyz.gmitch215.socketmc.util.option; \ No newline at end of file diff --git a/core/src/test/java/xyz/gmitch215/socketmc/util/TestLifecycleMap.java b/core/src/test/java/xyz/gmitch215/socketmc/util/TestLifecycleMap.java new file mode 100644 index 00000000..ed14402e --- /dev/null +++ b/core/src/test/java/xyz/gmitch215/socketmc/util/TestLifecycleMap.java @@ -0,0 +1,64 @@ +package xyz.gmitch215.socketmc.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.function.Function; + +public class TestLifecycleMap { + + @Test + @DisplayName("Test LifecycleMap#put") + public void testPut() { + LifecycleMap map = new LifecycleMap<>(); + + map.put(1, 0, 1000); + map.put(2, 1000, 1000); + map.put(3, 2000, 1000); + + Assertions.assertEquals(3, map.size()); + for (int i = 1; i <= 3; i++) { + Assertions.assertTrue(map.containsKey(i)); + Assertions.assertEquals(1000, map.getDuration(i)); + } + } + + @Test + @DisplayName("Test LifecycleMap#run") + public void testRun() { + LifecycleMap map = new LifecycleMap<>(); + + map.put(1, 0, 1000); + map.put(2, 1000, 1000); + map.put(3, 2000, 1000); + + Assertions.assertEquals(3, map.size()); + + while (map.size() > 0) { + map.run(); + } + + Assertions.assertEquals(0, map.size()); + } + + @Test + @DisplayName("Test LifecycleMap#store") + public void testStore() { + LifecycleMap> map = new LifecycleMap<>(); + + map.store(i -> i + 1, 500); + map.store(i -> i * 2, 1000); + map.store(i -> i * i, 1500); + + Assertions.assertEquals(3, map.size()); + + while (map.size() > 0) { + map.run(); + map.forEach(f -> f.apply(0)); + } + + Assertions.assertEquals(0, map.size()); + } + +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2c352119..a4b76b95 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b415..df97d72b 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.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/mod/fabric/build.gradle.kts b/mod/fabric/build.gradle.kts index a13e38a8..a14fac44 100644 --- a/mod/fabric/build.gradle.kts +++ b/mod/fabric/build.gradle.kts @@ -9,7 +9,7 @@ plugins { description = "Fabric Mod for SocketMC Client-side Implementation" -val minecraft = project.ext["minecraft_version"].toString() +val mc = project.ext["minecraft_version"].toString() val parchment = project.ext["parchment"].toString() val fabric = "0.102.0" @@ -18,10 +18,10 @@ dependencies { api(project(":socketmc-core")) api(project(":socketmc-shared")) - minecraft("com.mojang:minecraft:$minecraft") + minecraft("com.mojang:minecraft:$mc") mappings(loom.layered { officialMojangMappings() - parchment("org.parchmentmc.data:parchment-$minecraft:$parchment@zip") + parchment("org.parchmentmc.data:parchment-$mc:$parchment@zip") }) modImplementation("net.fabricmc:fabric-loader:0.15.11") @@ -35,7 +35,7 @@ dependencies { "fabric-screen-api-v1", "fabric-key-binding-api-v1" ).forEach { - modImplementation(fabricApi.module(it, "$fabric+$minecraft")) + modImplementation(fabricApi.module(it, "$fabric+$mc")) } annotationProcessor("org.spongepowered:mixin:0.8.6:processor") @@ -92,13 +92,14 @@ modrinth { versionType.set(project.ext["version_type"].toString()) uploadFile.set(tasks.remapJar) - gameVersions.add(project.ext["minecraft_version"].toString()) changelog.set(project.ext["changelog"].toString()) + gameVersions.add(mc) + gameVersions.addAll((project.ext["similar_versions"] as List<*>).map { it.toString() }) + loaders.addAll(listOf("fabric", "quilt")) - dependencies { - required.project("fabric-api") - } + + required.project("fabric-api") syncBodyFrom.set(rootProject.file("README.md").bufferedReader().use { it.readText() }) } \ No newline at end of file diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricRendering.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricRendering.java new file mode 100644 index 00000000..0db75c69 --- /dev/null +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricRendering.java @@ -0,0 +1,19 @@ +package xyz.gmitch215.socketmc.fabric; + +import com.mojang.blaze3d.platform.Window; + +import static xyz.gmitch215.socketmc.fabric.FabricSocketMC.minecraft; +import static xyz.gmitch215.socketmc.util.RenderingProperties.REFRESH_RATE; + +public final class FabricRendering { + + private FabricRendering() {} + + public static void frameTick() { + // Set Rendering Properties + Window window = minecraft.getWindow(); + + REFRESH_RATE.set(window.getRefreshRate()); + } + +} diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricRetriever.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricRetriever.java index bbb464aa..8e5a8276 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricRetriever.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricRetriever.java @@ -3,15 +3,19 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import net.minecraft.network.FriendlyByteBuf; +import xyz.gmitch215.socketmc.fabric.machines.*; import xyz.gmitch215.socketmc.retriever.ClientProperty; import xyz.gmitch215.socketmc.retriever.Retriever; import xyz.gmitch215.socketmc.retriever.RetrieverType; import xyz.gmitch215.socketmc.retriever.Window; +import xyz.gmitch215.socketmc.util.Identifier; import xyz.gmitch215.socketmc.util.InputType; +import xyz.gmitch215.socketmc.util.RenderingProperties; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; +import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -44,7 +48,7 @@ private FabricRetriever() {} window.getGuiScale(), window.getFramerateLimit(), com.mojang.blaze3d.platform.Window.getPlatform(), - window.getRefreshRate() + RenderingProperties.REFRESH_RATE.get() ); }), create(RetrieverType.PAUSED, minecraft::isPaused), @@ -58,7 +62,15 @@ private FabricRetriever() {} case MOUSE -> InputType.MOUSE; default -> InputType.NONE; }), - create(RetrieverType.COMMAND_HISTORY, () -> minecraft.commandHistory().history().toArray(new String[0])) + create(RetrieverType.COMMAND_HISTORY, () -> minecraft.commandHistory().history().toArray(new String[0])), + create(RetrieverType.DRAWN_CONTENTS, () -> Stream.of( + DrawTextMachine.lifecycle.getIdentifiers(), + DrawShapeMachine.lifecycle.getIdentifiers(), + DrawTextureMachine.lifecycle.getIdentifiers(), + DrawBufferMachine.lifecycle.getIdentifiers(), + DrawContextMachine.lifecycle.getIdentifiers(), + DrawItemStackMachine.lifecycle.getIdentifiers() + ).flatMap(Set::stream).distinct().toArray(Identifier[]::new)) ) ).collect(Collectors.toSet()); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricSocketMC.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricSocketMC.java index 1c6a0268..713fa395 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricSocketMC.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/FabricSocketMC.java @@ -41,6 +41,8 @@ public void onInitializeClient() { // Events - Machines HudRenderCallback.EVENT.register((graphics, delta) -> { + FabricRendering.frameTick(); + DrawTextMachine.frameTick(graphics, delta); DrawShapeMachine.frameTick(graphics, delta); DrawBufferMachine.frameTick(graphics, delta); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawBufferMachine.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawBufferMachine.java index e705dec8..7608fab8 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawBufferMachine.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawBufferMachine.java @@ -21,7 +21,7 @@ public final class DrawBufferMachine implements Machine { private DrawBufferMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawContextMachine.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawContextMachine.java index a0ff3c33..bd1b7463 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawContextMachine.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawContextMachine.java @@ -43,7 +43,7 @@ public final class DrawContextMachine implements Machine { private DrawContextMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawItemStackMachine.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawItemStackMachine.java index 69d2907e..77cad292 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawItemStackMachine.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawItemStackMachine.java @@ -20,7 +20,7 @@ public final class DrawItemStackMachine implements Machine { private DrawItemStackMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawShapeMachine.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawShapeMachine.java index 379d91be..31ca488e 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawShapeMachine.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawShapeMachine.java @@ -17,7 +17,7 @@ public final class DrawShapeMachine implements Machine { private DrawShapeMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextMachine.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextMachine.java index b51d510e..1ad5995d 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextMachine.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextMachine.java @@ -20,7 +20,7 @@ public final class DrawTextMachine implements Machine { private DrawTextMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextureMachine.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextureMachine.java index eed57d23..99c5ed6e 100644 --- a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextureMachine.java +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/machines/DrawTextureMachine.java @@ -19,7 +19,7 @@ public final class DrawTextureMachine implements Machine { private DrawTextureMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/mixin/events/PlayerChangeOptionEvent.java b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/mixin/events/PlayerChangeOptionEvent.java new file mode 100644 index 00000000..ba2d2948 --- /dev/null +++ b/mod/fabric/src/main/java/xyz/gmitch215/socketmc/fabric/mixin/events/PlayerChangeOptionEvent.java @@ -0,0 +1,73 @@ +package xyz.gmitch215.socketmc.fabric.mixin.events; + +import net.minecraft.client.*; +import net.minecraft.client.NarratorStatus; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import xyz.gmitch215.socketmc.fabric.FabricSocketMC; +import xyz.gmitch215.socketmc.util.Arm; +import xyz.gmitch215.socketmc.util.option.*; + +import java.util.Map; +import java.util.function.Function; + +@Mixin(OptionInstance.class) +public class PlayerChangeOptionEvent { + + @Final + @Shadow + Component caption; + + @Shadow + Object value; + + @Final + @Shadow + Function toString; + + @Inject(method = "set", at = @At("HEAD")) + public void onOptionChange(Object newValue, CallbackInfo ci) { + if (!FabricSocketMC.eventsEnabled) return; + + String oldValueS = toString.apply(value).getString(); + String newValueS = toString.apply(newValue).getString(); + + Object oldValue0 = socketMC$convertOptionValue(value); + Object newValue0 = socketMC$convertOptionValue(newValue); + + String key = ((TranslatableContents) caption.getContents()).getKey(); + + FabricSocketMC.sendEvent(10, Map.of( + "option", key, + "old_value", oldValue0, + "old_value_string", oldValueS, + "new_value", newValue0, + "new_value_string", newValueS + )); + } + + @Unique + private static Object socketMC$convertOptionValue(Object value) { + return switch (value) { + case AttackIndicatorStatus a -> AttackIndicator.byOrdinal(a.getId()); + case ChatVisiblity a -> ChatVisibility.byOrdinal(a.getId()); + case PrioritizeChunkUpdates a -> ChunkUpdatePriority.byOrdinal(a.getId()); + case CloudStatus a -> CloudRendering.byOrdinal(a.getId()); + case GraphicsStatus a -> GraphicsQuality.byOrdinal(a.getId()); + case NarratorStatus a -> xyz.gmitch215.socketmc.util.option.NarratorStatus.byOrdinal(a.getId()); + case ParticleStatus a -> ParticleRendering.byOrdinal(a.getId()); + case HumanoidArm a -> Arm.byOrdinal(a.getId()); + default -> value; + }; + } + +} diff --git a/mod/fabric/src/main/resources/socketmc-fabric.mixins.json b/mod/fabric/src/main/resources/socketmc-fabric.mixins.json index 1ad26b93..77820f36 100644 --- a/mod/fabric/src/main/resources/socketmc-fabric.mixins.json +++ b/mod/fabric/src/main/resources/socketmc-fabric.mixins.json @@ -10,6 +10,7 @@ "events.PlayerPressKeyEvent", "events.PlayerMouseInputEvent", - "events.PlayerChangeScreenEvent" + "events.PlayerChangeScreenEvent", + "events.PlayerChangeOptionEvent" ] } \ No newline at end of file diff --git a/mod/forge/build.gradle.kts b/mod/forge/build.gradle.kts index 40b6c935..45e4cb31 100644 --- a/mod/forge/build.gradle.kts +++ b/mod/forge/build.gradle.kts @@ -7,7 +7,7 @@ plugins { description = "Forge Mod for SocketMC Client-side Implementation" -val minecraft = project.ext["minecraft_version"].toString() +val mc = project.ext["minecraft_version"].toString() val parchment = project.ext["parchment"].toString() val forge = "51.0.0" @@ -16,13 +16,13 @@ dependencies { api(project(":socketmc-core")) api(project(":socketmc-shared")) - minecraft("net.minecraftforge:forge:$minecraft-$forge") + minecraft("net.minecraftforge:forge:$mc-$forge") annotationProcessor("org.spongepowered:mixin:0.8.6:processor") } minecraft { - mappings("parchment", "$parchment-$minecraft") + mappings("parchment", "$parchment-$mc") accessTransformer("src/main/resources/META-INF/accesstransformer.cfg") @@ -73,9 +73,11 @@ modrinth { versionType.set(project.ext["version_type"].toString()) uploadFile.set(tasks.jar.get().archiveFile.get().asFile) - gameVersions.add(project.ext["minecraft_version"].toString()) changelog.set(project.ext["changelog"].toString()) + gameVersions.add(mc) + gameVersions.addAll((project.ext["similar_versions"] as List<*>).map { it.toString() }) + loaders.add("forge") syncBodyFrom.set(rootProject.file("README.md").bufferedReader().use { it.readText() }) diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/ForgeRendering.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/ForgeRendering.java new file mode 100644 index 00000000..dcff6fa0 --- /dev/null +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/ForgeRendering.java @@ -0,0 +1,19 @@ +package xyz.gmitch215.socketmc.forge; + +import com.mojang.blaze3d.platform.Window; + +import static xyz.gmitch215.socketmc.forge.ForgeSocketMC.minecraft; +import static xyz.gmitch215.socketmc.util.RenderingProperties.REFRESH_RATE; + +public final class ForgeRendering { + + private ForgeRendering() {} + + public static void frameTick() { + // Set Rendering Properties + Window window = minecraft.getWindow(); + + REFRESH_RATE.set(window.getRefreshRate()); + } + +} diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/ForgeRetriever.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/ForgeRetriever.java index 2a070591..ed318e30 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/ForgeRetriever.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/ForgeRetriever.java @@ -1,19 +1,24 @@ package xyz.gmitch215.socketmc.forge; +import com.mojang.blaze3d.systems.RenderSystem; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import net.minecraft.network.FriendlyByteBuf; +import xyz.gmitch215.socketmc.forge.machines.*; import xyz.gmitch215.socketmc.retriever.ClientProperty; import xyz.gmitch215.socketmc.retriever.Retriever; import xyz.gmitch215.socketmc.retriever.RetrieverType; import xyz.gmitch215.socketmc.retriever.Window; +import xyz.gmitch215.socketmc.util.Identifier; import xyz.gmitch215.socketmc.util.InputType; +import xyz.gmitch215.socketmc.util.RenderingProperties; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.Set; import java.util.UUID; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -44,7 +49,7 @@ private ForgeRetriever() {} window.getGuiScale(), window.getFramerateLimit(), com.mojang.blaze3d.platform.Window.getPlatform(), - window.getRefreshRate() + RenderingProperties.REFRESH_RATE.get() ); }), create(RetrieverType.PAUSED, minecraft::isPaused), @@ -58,7 +63,15 @@ private ForgeRetriever() {} case MOUSE -> InputType.MOUSE; default -> InputType.NONE; }), - create(RetrieverType.COMMAND_HISTORY, () -> minecraft.commandHistory().history().toArray(new String[0])) + create(RetrieverType.COMMAND_HISTORY, () -> minecraft.commandHistory().history().toArray(new String[0])), + create(RetrieverType.DRAWN_CONTENTS, () -> Stream.of( + DrawTextMachine.lifecycle.getIdentifiers(), + DrawShapeMachine.lifecycle.getIdentifiers(), + DrawTextureMachine.lifecycle.getIdentifiers(), + DrawBufferMachine.lifecycle.getIdentifiers(), + DrawContextMachine.lifecycle.getIdentifiers(), + DrawItemStackMachine.lifecycle.getIdentifiers() + ).flatMap(Set::stream).distinct().toArray(Identifier[]::new)) ) ).collect(Collectors.toSet()); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawBufferMachine.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawBufferMachine.java index 2fded0b7..7519fab8 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawBufferMachine.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawBufferMachine.java @@ -21,7 +21,7 @@ public final class DrawBufferMachine implements Machine { private DrawBufferMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawContextMachine.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawContextMachine.java index d2cd1b4d..ca7d728a 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawContextMachine.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawContextMachine.java @@ -41,7 +41,7 @@ public final class DrawContextMachine implements Machine { private DrawContextMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawItemStackMachine.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawItemStackMachine.java index 028facfe..c8376ad1 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawItemStackMachine.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawItemStackMachine.java @@ -20,7 +20,7 @@ public final class DrawItemStackMachine implements Machine { private DrawItemStackMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawShapeMachine.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawShapeMachine.java index e245282a..c9d15f72 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawShapeMachine.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawShapeMachine.java @@ -17,7 +17,7 @@ public final class DrawShapeMachine implements Machine { private DrawShapeMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextMachine.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextMachine.java index 1f454fc9..ade80668 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextMachine.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextMachine.java @@ -20,7 +20,7 @@ public final class DrawTextMachine implements Machine { private DrawTextMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextureMachine.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextureMachine.java index a2f82132..61198fe2 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextureMachine.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/machines/DrawTextureMachine.java @@ -19,7 +19,7 @@ public final class DrawTextureMachine implements Machine { private DrawTextureMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/mixin/GuiMixin.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/mixin/GuiMixin.java index aadc1198..bb80096d 100644 --- a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/mixin/GuiMixin.java +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/mixin/GuiMixin.java @@ -1,6 +1,5 @@ package xyz.gmitch215.socketmc.forge.mixin; -import xyz.gmitch215.socketmc.forge.machines.*; import net.minecraft.client.DeltaTracker; import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.GuiGraphics; @@ -8,12 +7,16 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import xyz.gmitch215.socketmc.forge.ForgeRendering; +import xyz.gmitch215.socketmc.forge.machines.*; @Mixin(Gui.class) public class GuiMixin { @Inject(method = "render", at = @At(value = "TAIL")) public void render(GuiGraphics drawContext, DeltaTracker tickDelta, CallbackInfo callbackInfo) { + ForgeRendering.frameTick(); + DrawTextMachine.frameTick(drawContext, tickDelta); DrawShapeMachine.frameTick(drawContext, tickDelta); DrawBufferMachine.frameTick(drawContext, tickDelta); diff --git a/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/mixin/events/PlayerChangeOptionEvent.java b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/mixin/events/PlayerChangeOptionEvent.java new file mode 100644 index 00000000..8696ffc8 --- /dev/null +++ b/mod/forge/src/main/java/xyz/gmitch215/socketmc/forge/mixin/events/PlayerChangeOptionEvent.java @@ -0,0 +1,73 @@ +package xyz.gmitch215.socketmc.forge.mixin.events; + +import net.minecraft.client.NarratorStatus; +import net.minecraft.client.*; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import xyz.gmitch215.socketmc.forge.ForgeSocketMC; +import xyz.gmitch215.socketmc.util.Arm; +import xyz.gmitch215.socketmc.util.option.*; + +import java.util.Map; +import java.util.function.Function; + +@Mixin(OptionInstance.class) +public class PlayerChangeOptionEvent { + + @Final + @Shadow + Component caption; + + @Shadow + Object value; + + @Final + @Shadow + Function toString; + + @Inject(method = "set", at = @At("HEAD")) + public void onOptionChange(Object newValue, CallbackInfo ci) { + if (!ForgeSocketMC.eventsEnabled) return; + + String oldValueS = toString.apply(value).getString(); + String newValueS = toString.apply(newValue).getString(); + + Object oldValue0 = socketMC$convertOptionValue(value); + Object newValue0 = socketMC$convertOptionValue(newValue); + + String key = ((TranslatableContents) caption.getContents()).getKey(); + + ForgeSocketMC.sendEvent(10, Map.of( + "option", key, + "old_value", oldValue0, + "old_value_string", oldValueS, + "new_value", newValue0, + "new_value_string", newValueS + )); + } + + @Unique + private static Object socketMC$convertOptionValue(Object value) { + return switch (value) { + case AttackIndicatorStatus a -> AttackIndicator.byOrdinal(a.getId()); + case ChatVisiblity a -> ChatVisibility.byOrdinal(a.getId()); + case PrioritizeChunkUpdates a -> ChunkUpdatePriority.byOrdinal(a.getId()); + case CloudStatus a -> CloudRendering.byOrdinal(a.getId()); + case GraphicsStatus a -> GraphicsQuality.byOrdinal(a.getId()); + case NarratorStatus a -> xyz.gmitch215.socketmc.util.option.NarratorStatus.byOrdinal(a.getId()); + case ParticleStatus a -> ParticleRendering.byOrdinal(a.getId()); + case HumanoidArm a -> Arm.byOrdinal(a.getId()); + default -> value; + }; + } + +} diff --git a/mod/forge/src/main/resources/socketmc-forge.mixins.json b/mod/forge/src/main/resources/socketmc-forge.mixins.json index f54671ca..de366e09 100644 --- a/mod/forge/src/main/resources/socketmc-forge.mixins.json +++ b/mod/forge/src/main/resources/socketmc-forge.mixins.json @@ -11,6 +11,7 @@ "events.PlayerPressKeyEvent", "events.PlayerMouseInputEvent", - "events.PlayerChangeScreenEvent" + "events.PlayerChangeScreenEvent", + "events.PlayerChangeOptionEvent" ] } \ No newline at end of file diff --git a/mod/neoforge/build.gradle.kts b/mod/neoforge/build.gradle.kts index 5b60a7fa..02c58351 100644 --- a/mod/neoforge/build.gradle.kts +++ b/mod/neoforge/build.gradle.kts @@ -6,7 +6,7 @@ plugins { description = "NeoForge Mod for SocketMC Client-side Implementation" -val minecraft = project.ext["minecraft_version"].toString() +val mc = project.ext["minecraft_version"].toString() val parchmentV = project.ext["parchment"].toString() val neoforge = "21.0.167" @@ -26,7 +26,7 @@ minecraft { subsystems { parchment { - minecraftVersion.set(minecraft) + minecraftVersion.set(mc) mappingsVersion.set(parchmentV) } } @@ -73,9 +73,11 @@ modrinth { versionType.set(project.ext["version_type"].toString()) uploadFile.set(tasks.jar.get().archiveFile.get().asFile) - gameVersions.add(project.ext["minecraft_version"].toString()) changelog.set(project.ext["changelog"].toString()) + gameVersions.add(mc) + gameVersions.addAll((project.ext["similar_versions"] as List<*>).map { it.toString() }) + loaders.add("neoforge") syncBodyFrom.set(rootProject.file("README.md").bufferedReader().use { it.readText() }) diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/NeoForgeRendering.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/NeoForgeRendering.java new file mode 100644 index 00000000..4095b5cd --- /dev/null +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/NeoForgeRendering.java @@ -0,0 +1,19 @@ +package xyz.gmitch215.socketmc.neoforge; + +import com.mojang.blaze3d.platform.Window; + +import static xyz.gmitch215.socketmc.neoforge.NeoForgeSocketMC.minecraft; +import static xyz.gmitch215.socketmc.util.RenderingProperties.REFRESH_RATE; + +public final class NeoForgeRendering { + + private NeoForgeRendering() {} + + public static void frameTick() { + // Set Rendering Properties + Window window = minecraft.getWindow(); + + REFRESH_RATE.set(window.getRefreshRate()); + } + +} diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/NeoForgeRetriever.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/NeoForgeRetriever.java index 1356b097..805dad92 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/NeoForgeRetriever.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/NeoForgeRetriever.java @@ -3,11 +3,14 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import net.minecraft.network.FriendlyByteBuf; +import xyz.gmitch215.socketmc.neoforge.machines.*; import xyz.gmitch215.socketmc.retriever.ClientProperty; import xyz.gmitch215.socketmc.retriever.Retriever; import xyz.gmitch215.socketmc.retriever.RetrieverType; import xyz.gmitch215.socketmc.retriever.Window; +import xyz.gmitch215.socketmc.util.Identifier; import xyz.gmitch215.socketmc.util.InputType; +import xyz.gmitch215.socketmc.util.RenderingProperties; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -44,7 +47,7 @@ private NeoForgeRetriever() {} window.getGuiScale(), window.getFramerateLimit(), com.mojang.blaze3d.platform.Window.getPlatform(), - window.getRefreshRate() + RenderingProperties.REFRESH_RATE.get() ); }), create(RetrieverType.PAUSED, minecraft::isPaused), @@ -58,7 +61,15 @@ private NeoForgeRetriever() {} case MOUSE -> InputType.MOUSE; default -> InputType.NONE; }), - create(RetrieverType.COMMAND_HISTORY, () -> minecraft.commandHistory().history().toArray(new String[0])) + create(RetrieverType.COMMAND_HISTORY, () -> minecraft.commandHistory().history().toArray(new String[0])), + create(RetrieverType.DRAWN_CONTENTS, () -> Stream.of( + DrawTextMachine.lifecycle.getIdentifiers(), + DrawShapeMachine.lifecycle.getIdentifiers(), + DrawTextureMachine.lifecycle.getIdentifiers(), + DrawBufferMachine.lifecycle.getIdentifiers(), + DrawContextMachine.lifecycle.getIdentifiers(), + DrawItemStackMachine.lifecycle.getIdentifiers() + ).flatMap(Set::stream).distinct().toArray(Identifier[]::new)) ) ).collect(Collectors.toSet()); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawBufferMachine.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawBufferMachine.java index a2cdaf6a..fbf8df6c 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawBufferMachine.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawBufferMachine.java @@ -21,7 +21,7 @@ public final class DrawBufferMachine implements Machine { private DrawBufferMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawContextMachine.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawContextMachine.java index 4717e4e1..bc5184d7 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawContextMachine.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawContextMachine.java @@ -41,7 +41,7 @@ public final class DrawContextMachine implements Machine { private DrawContextMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawItemStackMachine.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawItemStackMachine.java index 26982f60..141dd882 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawItemStackMachine.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawItemStackMachine.java @@ -20,7 +20,7 @@ public final class DrawItemStackMachine implements Machine { private DrawItemStackMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawShapeMachine.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawShapeMachine.java index d5e2a35c..08f283d1 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawShapeMachine.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawShapeMachine.java @@ -17,7 +17,7 @@ public final class DrawShapeMachine implements Machine { private DrawShapeMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextMachine.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextMachine.java index 61a62ddc..5401aa97 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextMachine.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextMachine.java @@ -20,7 +20,7 @@ public final class DrawTextMachine implements Machine { private DrawTextMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextureMachine.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextureMachine.java index d4980565..fe7a7962 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextureMachine.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/machines/DrawTextureMachine.java @@ -19,7 +19,7 @@ public final class DrawTextureMachine implements Machine { private DrawTextureMachine() {} - private static final LifecycleMap> lifecycle = new LifecycleMap<>(); + public static final LifecycleMap> lifecycle = new LifecycleMap<>(); public static void frameTick(GuiGraphics graphics, DeltaTracker delta) { lifecycle.run(); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/mixin/GuiMixin.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/mixin/GuiMixin.java index 26c5d26d..e9338093 100644 --- a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/mixin/GuiMixin.java +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/mixin/GuiMixin.java @@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import xyz.gmitch215.socketmc.neoforge.NeoForgeRendering; import xyz.gmitch215.socketmc.neoforge.machines.*; @Mixin(Gui.class) @@ -14,6 +15,8 @@ public class GuiMixin { @Inject(method = "render", at = @At(value = "TAIL")) public void render(GuiGraphics drawContext, DeltaTracker tickDelta, CallbackInfo callbackInfo) { + NeoForgeRendering.frameTick(); + DrawTextMachine.frameTick(drawContext, tickDelta); DrawShapeMachine.frameTick(drawContext, tickDelta); DrawBufferMachine.frameTick(drawContext, tickDelta); diff --git a/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/mixin/events/PlayerChangeOptionEvent.java b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/mixin/events/PlayerChangeOptionEvent.java new file mode 100644 index 00000000..05a4ef2b --- /dev/null +++ b/mod/neoforge/src/main/java/xyz/gmitch215/socketmc/neoforge/mixin/events/PlayerChangeOptionEvent.java @@ -0,0 +1,73 @@ +package xyz.gmitch215.socketmc.neoforge.mixin.events; + +import net.minecraft.client.NarratorStatus; +import net.minecraft.client.*; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.world.entity.HumanoidArm; +import net.minecraft.world.entity.player.ChatVisiblity; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import xyz.gmitch215.socketmc.neoforge.NeoForgeSocketMC; +import xyz.gmitch215.socketmc.util.Arm; +import xyz.gmitch215.socketmc.util.option.*; + +import java.util.Map; +import java.util.function.Function; + +@Mixin(OptionInstance.class) +public class PlayerChangeOptionEvent { + + @Final + @Shadow + public Component caption; + + @Shadow + Object value; + + @Final + @Shadow + public Function toString; + + @Inject(method = "set", at = @At("HEAD")) + public void onOptionChange(Object newValue, CallbackInfo ci) { + if (!NeoForgeSocketMC.eventsEnabled) return; + + String oldValueS = toString.apply(value).getString(); + String newValueS = toString.apply(newValue).getString(); + + Object oldValue0 = socketMC$convertOptionValue(value); + Object newValue0 = socketMC$convertOptionValue(newValue); + + String key = ((TranslatableContents) caption.getContents()).getKey(); + + NeoForgeSocketMC.sendEvent(10, Map.of( + "option", key, + "old_value", oldValue0, + "old_value_string", oldValueS, + "new_value", newValue0, + "new_value_string", newValueS + )); + } + + @Unique + private static Object socketMC$convertOptionValue(Object value) { + return switch (value) { + case AttackIndicatorStatus a -> AttackIndicator.byOrdinal(a.getId()); + case ChatVisiblity a -> ChatVisibility.byOrdinal(a.getId()); + case PrioritizeChunkUpdates a -> ChunkUpdatePriority.byOrdinal(a.getId()); + case CloudStatus a -> CloudRendering.byOrdinal(a.getId()); + case GraphicsStatus a -> GraphicsQuality.byOrdinal(a.getId()); + case NarratorStatus a -> xyz.gmitch215.socketmc.util.option.NarratorStatus.byOrdinal(a.getId()); + case ParticleStatus a -> ParticleRendering.byOrdinal(a.getId()); + case HumanoidArm a -> Arm.byOrdinal(a.getId()); + default -> value; + }; + } + +} diff --git a/mod/neoforge/src/main/resources/socketmc-neoforge.mixins.json b/mod/neoforge/src/main/resources/socketmc-neoforge.mixins.json index dd2cc507..c2acc107 100644 --- a/mod/neoforge/src/main/resources/socketmc-neoforge.mixins.json +++ b/mod/neoforge/src/main/resources/socketmc-neoforge.mixins.json @@ -11,6 +11,7 @@ "events.PlayerPressKeyEvent", "events.PlayerMouseInputEvent", - "events.PlayerChangeScreenEvent" + "events.PlayerChangeScreenEvent", + "events.PlayerChangeOptionEvent" ] } \ No newline at end of file diff --git a/mod/shared/src/main/java/xyz/gmitch215/socketmc/util/RenderingProperties.java b/mod/shared/src/main/java/xyz/gmitch215/socketmc/util/RenderingProperties.java new file mode 100644 index 00000000..1e197536 --- /dev/null +++ b/mod/shared/src/main/java/xyz/gmitch215/socketmc/util/RenderingProperties.java @@ -0,0 +1,9 @@ +package xyz.gmitch215.socketmc.util; + +import java.util.concurrent.atomic.AtomicInteger; + +public interface RenderingProperties { + + AtomicInteger REFRESH_RATE = new AtomicInteger(0); + +} diff --git a/plugin/spigot/src/main/java/xyz/gmitch215/socketmc/events/system/AsyncPlayerChangeOptionEvent.java b/plugin/spigot/src/main/java/xyz/gmitch215/socketmc/events/system/AsyncPlayerChangeOptionEvent.java new file mode 100644 index 00000000..3463b014 --- /dev/null +++ b/plugin/spigot/src/main/java/xyz/gmitch215/socketmc/events/system/AsyncPlayerChangeOptionEvent.java @@ -0,0 +1,81 @@ +package xyz.gmitch215.socketmc.events.system; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.gmitch215.socketmc.events.SocketEvent; +import xyz.gmitch215.socketmc.spigot.SocketPlayer; + +/** + * Called when a player changes a game option. + */ +public class AsyncPlayerChangeOptionEvent extends SocketEvent { + + private final String key; + private final Object oldValue; + private final String oldValueString; + private final Object newValue; + private final String newValueString; + + /** + * Creates a new AsyncPlayerChangeOptionEvent. + * @param player The player associated with this event + */ + public AsyncPlayerChangeOptionEvent(@NotNull String key, @Nullable Object oldValue, @NotNull String oldValueString, @Nullable Object newValue, @NotNull String newValueString, @NotNull SocketPlayer player) { + super(player); + + if (key == null) throw new IllegalArgumentException("key cannot be null"); + if (oldValueString == null) throw new IllegalArgumentException("oldValueString cannot be null"); + if (newValueString == null) throw new IllegalArgumentException("newValueString cannot be null"); + + this.key = key; + this.oldValue = oldValue; + this.oldValueString = oldValueString; + this.newValue = newValue; + this.newValueString = newValueString; + } + + /** + * Gets the key of the option that was changed. + * @return Option Identifier Key + */ + @NotNull + public String getKey() { + return key; + } + + /** + * Gets the old value of the option. + * @return Old Value + */ + @Nullable + public Object getOldValue() { + return oldValue; + } + + /** + * Gets the old value of the option as a string. + * @return Old Value as a String + */ + @NotNull + public String getOldValueString() { + return oldValueString; + } + + /** + * Gets the new value of the option. + * @return New Value + */ + @Nullable + public Object getNewValue() { + return newValue; + } + + /** + * Gets the new value of the option as a string. + * @return New Value as a String + */ + @NotNull + public String getNewValueString() { + return newValueString; + } +} diff --git a/plugin/spigot/src/main/java/xyz/gmitch215/socketmc/spigot/EventFactory.java b/plugin/spigot/src/main/java/xyz/gmitch215/socketmc/spigot/EventFactory.java index e75a2521..2c942973 100644 --- a/plugin/spigot/src/main/java/xyz/gmitch215/socketmc/spigot/EventFactory.java +++ b/plugin/spigot/src/main/java/xyz/gmitch215/socketmc/spigot/EventFactory.java @@ -3,6 +3,7 @@ import io.netty.channel.ChannelPipeline; import xyz.gmitch215.socketmc.events.SocketEvent; import xyz.gmitch215.socketmc.events.input.*; +import xyz.gmitch215.socketmc.events.system.AsyncPlayerChangeOptionEvent; import xyz.gmitch215.socketmc.screen.AbstractScreen; import xyz.gmitch215.socketmc.screen.ui.AbstractButton; import xyz.gmitch215.socketmc.screen.ui.CheckboxButton; @@ -114,6 +115,16 @@ static void addPacketInjector(SocketPlayer p) { boolean success = (boolean) params.get("success"); return new AsyncPlayerClickExternalMessageBoxEvent(success, p); + }, + // PlayerChangeOptionEvent - 10 + (p, params) -> { + String option = (String) params.get("option"); + Object oldValue = params.get("old_value"); + String oldValueS = (String) params.get("old_value_string"); + Object newValue = params.get("new_value"); + String newValueS = (String) params.get("new_value_string"); + + return new AsyncPlayerChangeOptionEvent(option, oldValue, oldValueS, newValue, newValueS, p); } ); diff --git a/plugin/spigot/src/main/javadoc/xyz/gmitch215/socketmc/events/system/package-info.java b/plugin/spigot/src/main/javadoc/xyz/gmitch215/socketmc/events/system/package-info.java new file mode 100644 index 00000000..4c823a90 --- /dev/null +++ b/plugin/spigot/src/main/javadoc/xyz/gmitch215/socketmc/events/system/package-info.java @@ -0,0 +1,4 @@ +/** + * Package for client system events. + */ +package xyz.gmitch215.socketmc.events.system; \ No newline at end of file