Initial port of 1.18.2-3.0.1 to 1.19.2.

This commit is contained in:
Micle
2022-10-31 20:07:14 +00:00
commit 27a424aa21
28 changed files with 1612 additions and 0 deletions

8
.gitattributes vendored Normal file
View File

@ -0,0 +1,8 @@
*.blend filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.kra filter=lfs diff=lfs merge=lfs -text
*.mtl filter=lfs diff=lfs merge=lfs -text
*.bbmodel filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/.gradle/
/.idea/
/build/
/run/
/src/test/
/src/generated/resources/.cache/cache

2
LICENSE Normal file
View File

@ -0,0 +1,2 @@
Copyright (c) 2022 Micle
All rights reserved.

125
build.gradle Normal file
View File

@ -0,0 +1,125 @@
buildscript {
repositories {
// These repositories are only for Gradle plugins, put any other repositories in the repository block further below
maven { url = 'https://maven.minecraftforge.net' }
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' }
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.spongepowered.mixin'
def archiveVersion = "${project.mcVersion}-${project.buildVersion}" as Object
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
minecraft {
mappings channel: 'official', version: mcVersion
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
arg "-mixin.config=${modID}.mixins.json"
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
mods {
loginprotection {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
arg "-mixin.config=${modID}.mixins.json"
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
mods {
loginprotection {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
arg "-mixin.config=${modID}.mixins.json"
property 'mixin.env.remapRefMap', 'true'
property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
args '--mod', 'loginprotection', '--all',
'--existing', file('src/main/resources').toString(),
'--existing', file('src/generated/resources').toString(),
'--output', file('src/generated/resources/')
mods {
loginprotection {
source sourceSets.main
}
}
}
}
}
mixin {
add sourceSets.main, "${modID}.refmap.json"
config "${modID}.mixins.json"
}
sourceSets.main.resources {
srcDir 'src/generated/resources'
}
repositories {
maven {
name = "Progwml6 maven"
url = "https://dvs1.progwml6.com/files/maven/"
}
maven {
name = "ModMaven"
url = "https://modmaven.dev"
}
}
dependencies {
minecraft "net.minecraftforge:forge:${project.mcVersion}-${project.forgeVersion}"
annotationProcessor 'org.spongepowered:mixin:0.8.5:processor'
}
jar {
archiveFileName = "${project.archivesBaseName}-${archiveVersion}.jar"
manifest {
attributes([
"Specification-Title" : project.name,
"Specification-Vendor" : project.author,
"Specification-Version" : "1",
"Implementation-Title" : project.name,
"Implementation-Vendor" : project.author,
"Implementation-Version" : archiveVersion,
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
jar.finalizedBy('reobfJar')

12
gradle.properties Normal file
View File

@ -0,0 +1,12 @@
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false
group = dev.micle
archivesBaseName = micles-login-protection-forge
modID = loginprotection
name = Micle's Login Protection
author = Micle
buildVersion = 3.0.0
mcVersion = 1.19.2
forgeVersion = 43.1.47

View File

@ -0,0 +1 @@
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip

1
settings.gradle Normal file
View File

@ -0,0 +1 @@
rootProject.name = 'LoginProtection-1.19'

View File

@ -0,0 +1,43 @@
package dev.micle.loginprotection;
import dev.micle.loginprotection.proxy.IProxy;
import dev.micle.loginprotection.proxy.Proxy;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import java.util.Optional;
@Mod(LoginProtection.MOD_ID)
public class LoginProtection {
public static final String MOD_ID = "loginprotection";
private static IProxy proxy;
public LoginProtection() {
proxy = DistExecutor.safeRunForDist(
() -> Proxy.Client::new,
() -> Proxy.Server::new
);
}
public static ResourceLocation createResourceLocation(String name) throws IllegalArgumentException {
if (name.contains(":")) {
throw new IllegalArgumentException("Name contains namespace!");
}
return new ResourceLocation(MOD_ID, name);
}
public static String getVersion() {
Optional<? extends ModContainer> modContainer = ModList.get().getModContainerById(MOD_ID);
if (modContainer.isPresent()) {
return modContainer.get().getModInfo().getVersion().toString();
}
return "0.0.0";
}
public static IProxy getProxy() {
return proxy;
}
}

View File

@ -0,0 +1,76 @@
package dev.micle.loginprotection.data;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
public class ProtectedPlayer {
// Initialize variables
private final UUID playerUUID;
private final Timer timer = new Timer();
private TimerTask afkTimerTask, gracePeriodTimerTask;
private State state;
/**
* Constructor for a ProtectedPlayer.
* @param playerUUID UUID of player to use.
*/
public ProtectedPlayer(UUID playerUUID, State state) {
this.playerUUID = playerUUID;
this.state = state;
}
/**
* @return UUID of player,
*/
public UUID getPlayerUUID() {
return playerUUID;
}
public Timer getTimer() {
return timer;
}
public void setGracePeriodTimerTask(TimerTask gracePeriodTimerTask, long delay) {
if (this.gracePeriodTimerTask != null) {
this.gracePeriodTimerTask.cancel();
}
if (gracePeriodTimerTask != null) {
this.gracePeriodTimerTask = gracePeriodTimerTask;
timer.schedule(this.gracePeriodTimerTask, delay);
}
}
public void setAfkTimerTask(TimerTask afkTimerTask, long delay) {
if (this.afkTimerTask != null) {
this.afkTimerTask.cancel();
}
if (afkTimerTask != null) {
this.afkTimerTask = afkTimerTask;
timer.schedule(this.afkTimerTask, delay);
}
}
/**
* @return Current state of the player.
*/
public State getState() {
return state;
}
/**
* Set the state of the player.
* @param state Player's new state.
*/
public void setState(State state) {
this.state = state;
}
public enum State {
JOINING,
AFK,
ACTIVE,
LOGIN_GRACE,
AFK_GRACE
}
}

View File

@ -0,0 +1,234 @@
package dev.micle.loginprotection.data;
import dev.micle.loginprotection.LoginProtection;
import dev.micle.loginprotection.network.NetworkManager;
import dev.micle.loginprotection.network.server.PlayerStatePacket;
import dev.micle.loginprotection.network.server.RequestLastInputTickPacket;
import dev.micle.loginprotection.setup.Config;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.network.NetworkDirection;
import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;
import java.util.UUID;
public class ProtectedPlayerManager {
// Initialize variables
private static final List<ProtectedPlayer> protectedPlayers = new ArrayList<>();
/**
* Method for initializing the ProtectedPlayerManager.
*/
public static void init() {
for (ProtectedPlayer protectedPlayer : protectedPlayers) {
removePlayer(protectedPlayer.getPlayerUUID());
}
}
/**
* Adds a player to be protected.
* @param playerUUID UUID of player to protect.
*/
public static void addPlayer(UUID playerUUID) {
if (getPlayer(playerUUID) != null) {
return;
}
try {
protectedPlayers.add(new ProtectedPlayer(playerUUID, ProtectedPlayer.State.JOINING));
NetworkManager.getChannel().sendTo(new PlayerStatePacket(ProtectedPlayer.State.JOINING),
LoginProtection.getProxy().getServer().getPlayerList().getPlayer(playerUUID).connection.getConnection(),
NetworkDirection.PLAY_TO_CLIENT);
} catch (NullPointerException ignored) {}
}
/**
* Gets a protected player from the list of protected players.
* @param playerUUID UUID of player to get.
* @return ProtectedPlayer instance if player is present, otherwise null.
*/
public static ProtectedPlayer getPlayer(UUID playerUUID) {
for (ProtectedPlayer protectedPlayer : protectedPlayers) {
if (protectedPlayer.getPlayerUUID().equals(playerUUID)) {
return protectedPlayer;
}
}
return null;
}
/**
* Removes a player from the list of protected players.
* @param playerUUID UUID of player to remove.
*/
public static void removePlayer(UUID playerUUID) {
ProtectedPlayer player = getPlayer(playerUUID);
if (player == null) {
return;
}
player.getTimer().cancel();
protectedPlayers.remove(player);
}
/**
* Updates a player's state appropriately.
* @param playerUUID UUID of player to update the state of.
*/
public static void updateState(UUID playerUUID) {
ProtectedPlayer protectedPlayer = getPlayer(playerUUID);
ServerPlayer player = LoginProtection.getProxy().getServer().getPlayerList().getPlayer(playerUUID);
if (player == null) {
removePlayer(playerUUID);
return;
}
if (protectedPlayer == null) {
addPlayer(playerUUID);
} else {
ProtectedPlayer.State currentState = protectedPlayer.getState();
if (currentState.equals(ProtectedPlayer.State.JOINING)) {
if (Config.Server.LOGIN_GRACE_ENABLED.get()) {
// JOINING -> LOGIN_GRACE
protectedPlayer.setState(ProtectedPlayer.State.LOGIN_GRACE);
startGraceTimer(playerUUID, Config.Server.LOGIN_GRACE_DURATION.get() * 1000);
} else {
// JOINING -> ACTIVE
protectedPlayer.setState(ProtectedPlayer.State.ACTIVE);
if (Config.Server.LOGIN_APPLY_POST_EFFECTS.get()) {
applyPostEffects(playerUUID);
}
if (Config.Server.AFK_PROTECTION_ENABLED.get()) {
startAfkTimer(playerUUID, Config.Server.AFK_TIME_THRESHOLD.get() * 1000);
} else {
removePlayer(playerUUID);
}
}
} else if (currentState.equals(ProtectedPlayer.State.LOGIN_GRACE) ||
currentState.equals(ProtectedPlayer.State.AFK_GRACE)) {
// LOGIN_GRACE, AFK_GRACE -> ACTIVE
protectedPlayer.setState(ProtectedPlayer.State.ACTIVE);
if ((currentState.equals(ProtectedPlayer.State.LOGIN_GRACE) && Config.Server.LOGIN_APPLY_POST_EFFECTS.get()) ||
(currentState.equals(ProtectedPlayer.State.AFK_GRACE) && Config.Server.AFK_APPLY_POST_EFFECTS.get())) {
applyPostEffects(playerUUID);
}
if (Config.Server.AFK_PROTECTION_ENABLED.get()) {
startAfkTimer(playerUUID, Config.Server.AFK_TIME_THRESHOLD.get() * 1000);
} else {
removePlayer(playerUUID);
}
} else if (currentState.equals(ProtectedPlayer.State.ACTIVE)) {
// ACTIVE -> AFK
protectedPlayer.setState(ProtectedPlayer.State.AFK);
} else if (currentState.equals(ProtectedPlayer.State.AFK)) {
if (Config.Server.AFK_GRACE_ENABLED.get()) {
// AFK -> AFK_GRACE
protectedPlayer.setState(ProtectedPlayer.State.AFK_GRACE);
startGraceTimer(playerUUID, Config.Server.AFK_GRACE_DURATION.get() * 1000);
} else {
// AFK -> ACTIVE
protectedPlayer.setState(ProtectedPlayer.State.ACTIVE);
if (Config.Server.AFK_APPLY_POST_EFFECTS.get()) {
applyPostEffects(playerUUID);
}
if (Config.Server.AFK_PROTECTION_ENABLED.get()) {
startAfkTimer(playerUUID, Config.Server.AFK_TIME_THRESHOLD.get() * 1000);
} else {
removePlayer(playerUUID);
}
}
}
// Send state packet to player
NetworkManager.getChannel().sendTo(new PlayerStatePacket(protectedPlayer.getState()),
player.connection.getConnection(),
NetworkDirection.PLAY_TO_CLIENT);
}
}
/**
* Starts the afk timer for a given player if they are a protected player.
* @param playerUUID The UUID of the player.
* @param delay After how much time should the task run? (in milliseconds)
*/
public static void startAfkTimer(UUID playerUUID, long delay) {
ProtectedPlayer player = getPlayer(playerUUID);
if (player == null) {
return;
}
// Create scheduled task
player.setAfkTimerTask(new TimerTask() {
@Override
public void run() {
try {
// Send request for list input tick packet to player
NetworkManager.getChannel().sendTo(new RequestLastInputTickPacket(),
LoginProtection.getProxy().getServer().getPlayerList().getPlayer(playerUUID).connection.getConnection(),
NetworkDirection.PLAY_TO_CLIENT);
} catch (NullPointerException e) {
removePlayer(playerUUID);
}
}
}, delay);
}
/**
* Starts the grace period timer for a given player if they are a protected player.
* @param playerUUID UUID of the player.
* @param delay How long should the grace period last? (in milliseconds)
*/
private static void startGraceTimer(UUID playerUUID, long delay) {
ProtectedPlayer player = getPlayer(playerUUID);
if (player == null) {
return;
}
// Create scheduled task
player.setGracePeriodTimerTask(new TimerTask() {
@Override
public void run() {
// Update player state
updateState(playerUUID);
}
}, delay);
}
/**
* Applies effects to the player.
* @param playerUUID UUID of player to apply effects to.
*/
private static void applyPostEffects(UUID playerUUID) {
// Get player entity
Player player = LoginProtection.getProxy().getServer().getPlayerList().getPlayer(playerUUID);
if (player == null) {
removePlayer(playerUUID);
return;
}
// Apply effects
if (player.isInWater()) {
if (Config.Server.POST_REFILL_AIR_ENABLED.get()) {
player.setAirSupply(player.getMaxAirSupply());
}
if (Config.Server.POST_WATER_ENABLED.get()) {
player.addEffect(new MobEffectInstance(MobEffects.WATER_BREATHING,
Config.Server.POST_WATER_DURATION.get() * 20, 0));
}
}
if (player.isInLava()) {
if (Config.Server.POST_LAVA_ENABLED.get()) {
player.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE,
Config.Server.POST_LAVA_DURATION.get()*20, 0));
}
}
if (player.isOnFire()) {
if (Config.Server.POST_FIRE_ENABLED.get()) {
player.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE,
Config.Server.POST_FIRE_DURATION.get()*20, 0));
}
}
}
}

View File

@ -0,0 +1,345 @@
package dev.micle.loginprotection.events.client;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.network.NetworkManager;
import dev.micle.loginprotection.network.client.InputPacket;
import dev.micle.loginprotection.proxy.Proxy;
import dev.micle.loginprotection.setup.Config;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraft.client.gui.screens.ChatScreen;
import net.minecraft.client.gui.screens.PauseScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.InventoryScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.event.InputEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import org.lwjgl.glfw.GLFW;
import java.util.Arrays;
import java.util.List;
@OnlyIn(Dist.CLIENT)
public class OnClientInputEventHandler {
private static boolean isPausePressed = false;
private static boolean isDebugPressed = false;
private static boolean isFullscreenPressed = false;
private static boolean isTogglePerspectivePressed = false;
private static boolean isSmoothCameraPressed = false;
private static boolean isScreenshotPressed = false;
private static boolean isSpectatorOutlinesPressed = false;
private static boolean isAdvancementsPressed = false;
private static boolean isPlayerListPressed = false;
private static boolean isChatPressed = false;
private static boolean isChatCommandPressed = false;
private static boolean isChatEnterPressed = false;
private static boolean isSocialInteractionsPressed = false;
private static boolean isLoadHotbarActivatorPressed = false;
private static boolean isSaveHotbarActivatorPressed = false;
private static boolean isSwapOffhandPressed = false;
private static boolean isInventoryPressed = false;
private static boolean isDropItemPressed = false;
private static boolean isUseItemPressed = false;
private static boolean isPickBlockPressed = false;
private static boolean isAttackPressed = false;
private static boolean isMoveUpPressed = false;
private static boolean isMoveRightPressed = false;
private static boolean isMoveDownPressed = false;
private static boolean isMoveLeftPressed = false;
private static boolean isMoveSprintPressed = false;
private static boolean isSneakPressed = false;
private static boolean isJumpPressed = false;
private static final Boolean[] isHotBarPressed = new Boolean[9];
private static Screen previousScreen = null;
public OnClientInputEventHandler() {
// Initialize isHotBarPressed to false
Arrays.fill(isHotBarPressed, false);
}
@SubscribeEvent
public void KeyInputEvent(InputEvent.KeyInputEvent event) {
handle(event.getAction(), event.getKey());
}
@SubscribeEvent
public void MouseInputEvent(InputEvent.MouseInputEvent event) {
handle(event.getAction(), event.getButton());
}
private static void handle(int action, int key) {
// Initialize variables
Minecraft minecraft = Minecraft.getInstance();
// Cancel event if not in a game
if ((minecraft.getCurrentServer() == null && minecraft.getSingleplayerServer() == null) ||
Proxy.Client.getPlayerState() == null) {
return;
}
// Check if input is a press or release
if (action == GLFW.GLFW_PRESS || action == GLFW.GLFW_RELEASE) {
// Initialize variables
Options keyBinds = minecraft.options;
boolean isPressed = action == GLFW.GLFW_PRESS;
List<String> allowedKeys = (Proxy.Client.getPlayerState().equals(ProtectedPlayer.State.JOINING)) ?
(List<String>) Config.Server.LOGIN_KEY_ALLOW_LIST.get() :
(List<String>) Config.Server.AFK_KEY_ALLOW_LIST.get();
// Check if the key is monitored, save it's state, update last input tick and notify server if not allowed
if (key == GLFW.GLFW_KEY_ESCAPE) {
isPausePressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.PAUSE.toString())) {
updateAndNotify();
}
} else if (key == GLFW.GLFW_KEY_F3) {
isDebugPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.DEBUG.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyFullscreen.getKey().getValue()) {
isFullscreenPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.FULLSCREEN.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyTogglePerspective.getKey().getValue()) {
isTogglePerspectivePressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.PERSPECTIVE.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keySmoothCamera.getKey().getValue()) {
isSmoothCameraPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.SMOOTH_CAMERA.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyScreenshot.getKey().getValue()) {
isScreenshotPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.SCREENSHOT.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keySpectatorOutlines.getKey().getValue()) {
isSpectatorOutlinesPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.SPECTATOR_OUTLINES.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyAdvancements.getKey().getValue()) {
isAdvancementsPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.ADVANCEMENTS.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyPlayerList.getKey().getValue()) {
isPlayerListPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.PLAYER_LIST.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyChat.getKey().getValue()) {
isChatPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.CHAT.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyCommand.getKey().getValue()) {
isChatCommandPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.CHAT.toString())) {
updateAndNotify();
}
} else if (key == GLFW.GLFW_KEY_ENTER) {
isChatEnterPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.CHAT.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keySocialInteractions.getKey().getValue()) {
isSocialInteractionsPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.SOCIAL_INTERACTIONS.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyLoadHotbarActivator.getKey().getValue()) {
isLoadHotbarActivatorPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.LOAD_HOTBAR_ACTIVATOR.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keySaveHotbarActivator.getKey().getValue()) {
isSaveHotbarActivatorPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.SAVE_HOTBAR_ACTIVATOR.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keySwapOffhand.getKey().getValue()) {
isSwapOffhandPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.SWAP_ITEM.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyInventory.getKey().getValue()) {
isInventoryPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.INVENTORY.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyDrop.getKey().getValue()) {
isDropItemPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.DROP_ITEM.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyUse.getKey().getValue()) {
isUseItemPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.USE_ITEM.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyPickItem.getKey().getValue()) {
isPickBlockPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.PICK_BLOCK.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyAttack.getKey().getValue()) {
isAttackPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.ATTACK.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyUp.getKey().getValue()) {
isMoveUpPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.MOVE.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyRight.getKey().getValue()) {
isMoveRightPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.MOVE.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyDown.getKey().getValue()) {
isMoveDownPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.MOVE.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyLeft.getKey().getValue()) {
isMoveLeftPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.MOVE.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keySprint.getKey().getValue()) {
isMoveSprintPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.MOVE.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyShift.getKey().getValue()) {
isSneakPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.SNEAK.toString())) {
updateAndNotify();
}
} else if (key == keyBinds.keyJump.getKey().getValue()) {
isJumpPressed = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.JUMP.toString())) {
updateAndNotify();
}
} else {
for (int i = 0; i < isHotBarPressed.length; i++) {
if (key == keyBinds.keyHotbarSlots[i].getKey().getValue()) {
isHotBarPressed[i] = isPressed;
if (!checkIfScreenIsAllowed(allowedKeys, minecraft.screen, !isPressed) &&
!allowedKeys.contains(Config.Server.KEYS.HOTBAR.toString())) {
updateAndNotify();
}
}
}
}
}
}
private static boolean checkIfScreenIsAllowed(List<String> allowedKeys, Screen screen, boolean isActionReleased) {
// Initialize variables
boolean isAllowed;
// Check if the previous screen or the current screen are significant and their respective keys are allowed
if (previousScreen instanceof PauseScreen || screen instanceof PauseScreen) {
isAllowed = allowedKeys.contains(Config.Server.KEYS.PAUSE.toString());
} else if (previousScreen instanceof InventoryScreen || screen instanceof InventoryScreen) {
isAllowed = allowedKeys.contains(Config.Server.KEYS.INVENTORY.toString());
} else if (previousScreen instanceof ChatScreen || screen instanceof ChatScreen) {
isAllowed = allowedKeys.contains(Config.Server.KEYS.CHAT.toString());
} else {
// Allow any other screen that is not the game itself
isAllowed = screen != null;
}
// Only update the previous screen when key is released
if (isActionReleased) {
previousScreen = screen;
}
// Return value
return isAllowed;
}
private static void updateAndNotify() {
// Update last input tick
Proxy.Client.updateLastInputTick();
// Send an input packet if player is joining or is afk
if (Proxy.Client.getPlayerState().equals(ProtectedPlayer.State.JOINING) ||
Proxy.Client.getPlayerState().equals(ProtectedPlayer.State.AFK)) {
NetworkManager.getChannel().sendToServer(new InputPacket());
}
}
public static void checkIfInputIsAllowed() {
// Get list of allowed keys
List<String> allowedKeys = (Proxy.Client.getPlayerState().equals(ProtectedPlayer.State.JOINING)) ?
(List<String>) Config.Server.LOGIN_KEY_ALLOW_LIST.get() :
(List<String>) Config.Server.AFK_KEY_ALLOW_LIST.get();
// Update last input tick and notify server if any of the monitored keys are pressed and not allowed
if ((isPausePressed && !allowedKeys.contains(Config.Server.KEYS.PAUSE.toString())) ||
(isDebugPressed && !allowedKeys.contains(Config.Server.KEYS.DEBUG.toString())) ||
(isFullscreenPressed && !allowedKeys.contains(Config.Server.KEYS.FULLSCREEN.toString())) ||
(isTogglePerspectivePressed && !allowedKeys.contains(Config.Server.KEYS.PERSPECTIVE.toString())) ||
(isSmoothCameraPressed && !allowedKeys.contains(Config.Server.KEYS.SMOOTH_CAMERA.toString())) ||
(isScreenshotPressed && !allowedKeys.contains(Config.Server.KEYS.SCREENSHOT.toString())) ||
(isSpectatorOutlinesPressed && !allowedKeys.contains(Config.Server.KEYS.SPECTATOR_OUTLINES.toString())) ||
(isAdvancementsPressed && !allowedKeys.contains(Config.Server.KEYS.ADVANCEMENTS.toString())) ||
(isPlayerListPressed && !allowedKeys.contains(Config.Server.KEYS.PLAYER_LIST.toString())) ||
((isChatPressed || isChatCommandPressed || isChatEnterPressed) &&
!allowedKeys.contains(Config.Server.KEYS.CHAT.toString())) ||
(isSocialInteractionsPressed && !allowedKeys.contains(Config.Server.KEYS.SOCIAL_INTERACTIONS.toString())) ||
(isLoadHotbarActivatorPressed && !allowedKeys.contains(Config.Server.KEYS.LOAD_HOTBAR_ACTIVATOR.toString())) ||
(isSaveHotbarActivatorPressed && !allowedKeys.contains(Config.Server.KEYS.SAVE_HOTBAR_ACTIVATOR.toString())) ||
(isSwapOffhandPressed && !allowedKeys.contains(Config.Server.KEYS.SWAP_ITEM.toString())) ||
(isInventoryPressed && !allowedKeys.contains(Config.Server.KEYS.INVENTORY.toString())) ||
(isDropItemPressed && !allowedKeys.contains(Config.Server.KEYS.DROP_ITEM.toString())) ||
(isUseItemPressed && !allowedKeys.contains(Config.Server.KEYS.USE_ITEM.toString())) ||
(isPickBlockPressed && !allowedKeys.contains(Config.Server.KEYS.PICK_BLOCK.toString())) ||
(isAttackPressed && !allowedKeys.contains(Config.Server.KEYS.ATTACK.toString())) ||
((isMoveUpPressed || isMoveRightPressed || isMoveDownPressed || isMoveLeftPressed || isMoveSprintPressed) &&
!allowedKeys.contains(Config.Server.KEYS.MOVE.toString())) ||
(isSneakPressed && !allowedKeys.contains(Config.Server.KEYS.SNEAK.toString())) ||
(isJumpPressed && !allowedKeys.contains(Config.Server.KEYS.JUMP.toString())) ||
(Arrays.stream(isHotBarPressed).anyMatch(b -> b) && !allowedKeys.contains(Config.Server.KEYS.HOTBAR.toString()))) {
updateAndNotify();
}
}
}

View File

@ -0,0 +1,32 @@
package dev.micle.loginprotection.events.common;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.data.ProtectedPlayerManager;
import dev.micle.loginprotection.setup.Config;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
public class OnLivingSetAttackTargetEventHandler {
@SubscribeEvent
public void LivingSetAttackTargetEvent(LivingSetAttackTargetEvent event) {
if (!(event.getTarget() instanceof Player target)) {
return;
}
ProtectedPlayer player = ProtectedPlayerManager.getPlayer(target.getUUID());
if (player == null) {
return;
}
// Check if mob should ignore player
if ((player.getState().equals(ProtectedPlayer.State.JOINING) && Config.Server.LOGIN_MOBS_IGNORE_PLAYER.get()) ||
(player.getState().equals(ProtectedPlayer.State.AFK) && Config.Server.AFK_MOBS_IGNORE_PLAYER.get()) ||
(player.getState().equals(ProtectedPlayer.State.LOGIN_GRACE) && Config.Server.LOGIN_GRACE_MOBS_IGNORE_PLAYER.get()) ||
(player.getState().equals(ProtectedPlayer.State.AFK_GRACE) && Config.Server.AFK_GRACE_MOBS_IGNORE_PLAYER.get())) {
((Mob) event.getEntityLiving()).setTarget(null);
}
}
}

View File

@ -0,0 +1,23 @@
package dev.micle.loginprotection.events.common;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.data.ProtectedPlayerManager;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.entity.living.LivingDamageEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
public class OnPlayerDamageEventHandler {
@SubscribeEvent
public void LivingDamageEvent(LivingDamageEvent event) {
if (!(event.getEntity() instanceof Player player)) {
return;
}
ProtectedPlayer protectedPlayer = ProtectedPlayerManager.getPlayer(player.getUUID());
if (protectedPlayer == null || protectedPlayer.getState().equals(ProtectedPlayer.State.ACTIVE)) {
return;
}
event.setCanceled(true);
}
}

View File

@ -0,0 +1,17 @@
package dev.micle.loginprotection.events.common;
import dev.micle.loginprotection.data.ProtectedPlayerManager;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
public class OnPlayerJoinEventHandler {
@SubscribeEvent
public void EntityJoinWorldEvent(PlayerEvent.PlayerLoggedInEvent event) {
if (!(event.getEntity() instanceof Player player)) {
return;
}
ProtectedPlayerManager.addPlayer(player.getUUID());
}
}

View File

@ -0,0 +1,17 @@
package dev.micle.loginprotection.events.common;
import dev.micle.loginprotection.data.ProtectedPlayerManager;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
public class OnPlayerLeaveEventHandler {
@SubscribeEvent
public void PlayerLeaveEvent(PlayerEvent.PlayerLoggedOutEvent event) {
if (!(event.getEntity() instanceof Player player)) {
return;
}
ProtectedPlayerManager.removePlayer(player.getUUID());
}
}

View File

@ -0,0 +1,50 @@
package dev.micle.loginprotection.mixin;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.proxy.Proxy;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.gui.ForgeIngameGui;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ForgeIngameGui.class)
@OnlyIn(Dist.CLIENT)
public class GuiRenderTickMixin {
@Inject(method = "render", at = @At(value = "HEAD"))
private void onClientTick(PoseStack poseStack, float partialTicks, CallbackInfo callbackInfo) {
// Setup
poseStack.pushPose();
poseStack.translate(Minecraft.getInstance().getWindow().getGuiScaledWidth() / 2.0,
Minecraft.getInstance().getWindow().getGuiScaledHeight() / 2.0, 0);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
// Render player state text
poseStack.pushPose();
poseStack.scale(5, 5, 5);
// Check if we should draw the state
if (Proxy.Client.getPlayerState() != null && !Proxy.Client.getPlayerState().equals(ProtectedPlayer.State.ACTIVE)) {
// Initialize variables
Font font = Minecraft.getInstance().font;
float offsetX = -(font.width(Proxy.Client.getPlayerState().toString()) / 2f);
float offsetY = -((font.lineHeight / 2f) + ((Minecraft.getInstance().getWindow().getGuiScaledHeight() / 4f) / 5));
int argb = 0xFFFFFFFF;
// Draw the player's protection state
font.drawShadow(poseStack, Proxy.Client.getPlayerState().toString().replace("_", " "), offsetX, offsetY, argb);
}
poseStack.popPose();
// Finish
RenderSystem.disableBlend();
poseStack.popPose();
}
}

View File

@ -0,0 +1,49 @@
package dev.micle.loginprotection.network;
import dev.micle.loginprotection.LoginProtection;
import dev.micle.loginprotection.network.client.InputPacket;
import dev.micle.loginprotection.network.client.LastInputTickPacket;
import dev.micle.loginprotection.network.server.PlayerStatePacket;
import dev.micle.loginprotection.network.server.RequestLastInputTickPacket;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.simple.SimpleChannel;
public class NetworkManager {
private static SimpleChannel channel;
public static void init() {
// Create channel
channel = NetworkRegistry.ChannelBuilder.named(LoginProtection.createResourceLocation("network"))
.clientAcceptedVersions(v -> v.equals(LoginProtection.getVersion()))
.serverAcceptedVersions(v -> v.equals(LoginProtection.getVersion()))
.networkProtocolVersion(LoginProtection::getVersion)
.simpleChannel();
// Register packets
int id = 0;
channel.messageBuilder(InputPacket.class, id++)
.encoder(InputPacket::encode)
.decoder(InputPacket::decode)
.consumer(InputPacket::handle)
.add();
channel.messageBuilder(PlayerStatePacket.class, id++)
.encoder(PlayerStatePacket::encode)
.decoder(PlayerStatePacket::decode)
.consumer(PlayerStatePacket::handle)
.add();
channel.messageBuilder(RequestLastInputTickPacket.class, id++)
.encoder(RequestLastInputTickPacket::encode)
.decoder(RequestLastInputTickPacket::decode)
.consumer(RequestLastInputTickPacket::handle)
.add();
channel.messageBuilder(LastInputTickPacket.class, id++)
.encoder(LastInputTickPacket::encode)
.decoder(LastInputTickPacket::decode)
.consumer(LastInputTickPacket::handle)
.add();
}
public static SimpleChannel getChannel() {
return channel;
}
}

View File

@ -0,0 +1,41 @@
package dev.micle.loginprotection.network.client;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.data.ProtectedPlayerManager;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class InputPacket {
public static void encode(final InputPacket packet, final FriendlyByteBuf buffer) {}
public static InputPacket decode(final FriendlyByteBuf buffer) {
return new InputPacket();
}
public static void handle(final InputPacket packet, final Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkEvent.Context context = contextSupplier.get();
context.enqueueWork(() -> {
// Get sender
ServerPlayer sender = context.getSender();
if (sender == null) {
return;
}
// Get protected player
ProtectedPlayer protectedPlayer = ProtectedPlayerManager.getPlayer(sender.getUUID());
if (protectedPlayer == null) {
return;
}
// Update player state if they are joining or afk
if (protectedPlayer.getState().equals(ProtectedPlayer.State.JOINING) ||
protectedPlayer.getState().equals(ProtectedPlayer.State.AFK)) {
ProtectedPlayerManager.updateState(protectedPlayer.getPlayerUUID());
}
});
context.setPacketHandled(true);
}
}

View File

@ -0,0 +1,56 @@
package dev.micle.loginprotection.network.client;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.data.ProtectedPlayerManager;
import dev.micle.loginprotection.proxy.Proxy;
import dev.micle.loginprotection.setup.Config;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class LastInputTickPacket {
private final int lastInputTick;
public LastInputTickPacket() {
this(Proxy.Client.getLastInputTick());
}
public LastInputTickPacket(int lastInputTick) {
this.lastInputTick = lastInputTick;
}
public static void encode(final LastInputTickPacket packet, final FriendlyByteBuf buffer) {
buffer.writeInt(packet.lastInputTick);
}
public static LastInputTickPacket decode(final FriendlyByteBuf buffer) {
return new LastInputTickPacket(buffer.readInt());
}
public static void handle(final LastInputTickPacket packet, final Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkEvent.Context context = contextSupplier.get();
context.enqueueWork(() -> {
// Get sender
ServerPlayer sender = context.getSender();
if (sender == null) {
return;
}
// Get protected player
ProtectedPlayer protectedPlayer = ProtectedPlayerManager.getPlayer(sender.getUUID());
if (protectedPlayer == null) {
return;
}
// Check if player is afk
if (sender.tickCount - packet.lastInputTick >= Config.Server.AFK_TIME_THRESHOLD.get() * 20) {
ProtectedPlayerManager.updateState(sender.getUUID()); // Update state
} else {
ProtectedPlayerManager.startAfkTimer(sender.getUUID(), (long) ((Config.Server.AFK_TIME_THRESHOLD.get() -
((sender.tickCount - packet.lastInputTick) / 20.0)) * 1000)); // Start new afk timer
}
});
context.setPacketHandled(true);
}
}

View File

@ -0,0 +1,32 @@
package dev.micle.loginprotection.network.server;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.proxy.Proxy;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class PlayerStatePacket {
private final ProtectedPlayer.State state;
public PlayerStatePacket(ProtectedPlayer.State state) {
this.state = state;
}
public static void encode(final PlayerStatePacket packet, final FriendlyByteBuf buffer) {
buffer.writeUtf(packet.state.toString());
}
public static PlayerStatePacket decode(final FriendlyByteBuf buffer) {
return new PlayerStatePacket(ProtectedPlayer.State.valueOf(buffer.readUtf()));
}
public static void handle(final PlayerStatePacket packet, final Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkEvent.Context context = contextSupplier.get();
context.enqueueWork(() -> {
Proxy.Client.setPlayerState(packet.state);
});
context.setPacketHandled(true);
}
}

View File

@ -0,0 +1,30 @@
package dev.micle.loginprotection.network.server;
import dev.micle.loginprotection.events.client.OnClientInputEventHandler;
import dev.micle.loginprotection.network.NetworkManager;
import dev.micle.loginprotection.network.client.LastInputTickPacket;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class RequestLastInputTickPacket {
public static void encode(final RequestLastInputTickPacket packet, final FriendlyByteBuf buffer) {
}
public static RequestLastInputTickPacket decode(final FriendlyByteBuf buffer) {
return new RequestLastInputTickPacket();
}
public static void handle(final RequestLastInputTickPacket packet, final Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkEvent.Context context = contextSupplier.get();
context.enqueueWork(() -> {
// Update last input tick (This works around GLFW forgetting about a repeat key after another one is pressed)
OnClientInputEventHandler.checkIfInputIsAllowed();
// Send last input tick packet back to server
NetworkManager.getChannel().sendToServer(new LastInputTickPacket());
});
context.setPacketHandled(true);
}
}

View File

@ -0,0 +1,11 @@
package dev.micle.loginprotection.proxy;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
public interface IProxy {
MinecraftServer getServer();
Player getClientPlayer();
Level getClientWorld();
}

View File

@ -0,0 +1,145 @@
package dev.micle.loginprotection.proxy;
import dev.micle.loginprotection.LoginProtection;
import dev.micle.loginprotection.data.ProtectedPlayer;
import dev.micle.loginprotection.data.ProtectedPlayerManager;
import dev.micle.loginprotection.events.client.OnClientInputEventHandler;
import dev.micle.loginprotection.events.common.OnLivingSetAttackTargetEventHandler;
import dev.micle.loginprotection.events.common.OnPlayerDamageEventHandler;
import dev.micle.loginprotection.events.common.OnPlayerJoinEventHandler;
import dev.micle.loginprotection.events.common.OnPlayerLeaveEventHandler;
import dev.micle.loginprotection.network.NetworkManager;
import dev.micle.loginprotection.setup.Config;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AddReloadListenerEvent;
import net.minecraftforge.event.server.ServerStartedEvent;
import net.minecraftforge.event.server.ServerStoppingEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.event.lifecycle.*;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
public class Proxy implements IProxy {
// Initialize variables
private static MinecraftServer server = null;
// Common setup
public Proxy() {
// Initialize setup
Config.init();
NetworkManager.init();
// Register mod event bus listeners
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(Proxy::setup);
modEventBus.addListener(Proxy::imcEnqueue);
modEventBus.addListener(Proxy::imcProcess);
// Register event but listeners
MinecraftForge.EVENT_BUS.addListener(Proxy::onAddReloadListeners);
MinecraftForge.EVENT_BUS.addListener(Proxy::serverStarted);
MinecraftForge.EVENT_BUS.addListener(Proxy::serverStopping);
// Register event handlers
MinecraftForge.EVENT_BUS.register(new OnLivingSetAttackTargetEventHandler());
MinecraftForge.EVENT_BUS.register(new OnPlayerDamageEventHandler());
MinecraftForge.EVENT_BUS.register(new OnPlayerJoinEventHandler());
MinecraftForge.EVENT_BUS.register(new OnPlayerLeaveEventHandler());
}
private static void setup(FMLCommonSetupEvent event) {}
private static void imcEnqueue(InterModEnqueueEvent event) {}
private static void imcProcess(InterModProcessEvent event) {}
private static void onAddReloadListeners(AddReloadListenerEvent event) {}
private static void serverStarted(ServerStartedEvent event) {
ProtectedPlayerManager.init();
server = event.getServer();
}
private static void serverStopping(ServerStoppingEvent event) {
server = null;
}
@Override
public MinecraftServer getServer() {
return server;
}
@Override
public Player getClientPlayer() {
return null;
}
@Override
public Level getClientWorld() {
return null;
}
// Client setup
public static class Client extends Proxy {
private static ProtectedPlayer.State playerState;
private static int lastInputTick;
public Client() {
// Register mod event bus listeners
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(Client::setup);
modEventBus.addListener(Client::postSetup);
// Register event handlers
MinecraftForge.EVENT_BUS.register(new OnClientInputEventHandler());
}
private static void setup(FMLClientSetupEvent event) {}
private static void postSetup(FMLLoadCompleteEvent event) {}
public static ProtectedPlayer.State getPlayerState() {
return playerState;
}
public static void setPlayerState(ProtectedPlayer.State newPlayerState) {
playerState = newPlayerState;
}
public static int getLastInputTick() {
return lastInputTick;
}
public static void updateLastInputTick() {
lastInputTick = LoginProtection.getProxy().getClientPlayer().tickCount;
}
@Override
@OnlyIn(Dist.CLIENT)
public Player getClientPlayer() {
return Minecraft.getInstance().player;
}
@Override
@OnlyIn(Dist.CLIENT)
public Level getClientWorld() {
return Minecraft.getInstance().level;
}
}
// Server setup
public static class Server extends Proxy {
public Server() {
// Register mod event bus listeners
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(Server::setup);
}
private static void setup(FMLDedicatedServerSetupEvent event) {}
}
}

View File

@ -0,0 +1,174 @@
package dev.micle.loginprotection.setup;
import com.google.common.collect.Lists;
import dev.micle.loginprotection.LoginProtection;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
@Mod.EventBusSubscriber(modid = LoginProtection.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public final class Config {
public static final Server SERVER;
public static final ForgeConfigSpec SERVER_SPEC;
static {
Pair<Server, ForgeConfigSpec> spec_pair = new ForgeConfigSpec.Builder().configure(Server::new);
SERVER = spec_pair.getLeft();
SERVER_SPEC = spec_pair.getRight();
}
public static void init() {
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, SERVER_SPEC);
}
public static class Server {
public static ForgeConfigSpec.BooleanValue POST_REFILL_AIR_ENABLED;
public static ForgeConfigSpec.BooleanValue POST_WATER_ENABLED;
public static ForgeConfigSpec.IntValue POST_WATER_DURATION;
public static ForgeConfigSpec.BooleanValue POST_LAVA_ENABLED;
public static ForgeConfigSpec.IntValue POST_LAVA_DURATION;
public static ForgeConfigSpec.BooleanValue POST_FIRE_ENABLED;
public static ForgeConfigSpec.IntValue POST_FIRE_DURATION;
public static ForgeConfigSpec.BooleanValue LOGIN_MOBS_IGNORE_PLAYER;
public static ForgeConfigSpec.BooleanValue LOGIN_APPLY_POST_EFFECTS;
public static ForgeConfigSpec.ConfigValue<List<? extends String>> LOGIN_KEY_ALLOW_LIST;
public static ForgeConfigSpec.BooleanValue LOGIN_GRACE_ENABLED;
public static ForgeConfigSpec.BooleanValue LOGIN_GRACE_MOBS_IGNORE_PLAYER;
public static ForgeConfigSpec.IntValue LOGIN_GRACE_DURATION;
public static ForgeConfigSpec.BooleanValue AFK_PROTECTION_ENABLED;
public static ForgeConfigSpec.IntValue AFK_TIME_THRESHOLD;
public static ForgeConfigSpec.BooleanValue AFK_APPLY_POST_EFFECTS;
public static ForgeConfigSpec.BooleanValue AFK_MOBS_IGNORE_PLAYER;
public static ForgeConfigSpec.ConfigValue<List<? extends String>> AFK_KEY_ALLOW_LIST;
public static ForgeConfigSpec.BooleanValue AFK_GRACE_ENABLED;
public static ForgeConfigSpec.BooleanValue AFK_GRACE_MOBS_IGNORE_PLAYER;
public static ForgeConfigSpec.IntValue AFK_GRACE_DURATION;
Server(ForgeConfigSpec.Builder builder) {
builder.comment("Settings for protecting players while they are joining.").push("Login");
LOGIN_APPLY_POST_EFFECTS = builder
.comment("Whether to apply any post protection effects to joining players.")
.define("applyPostProtectionEffects", true);
LOGIN_MOBS_IGNORE_PLAYER = builder
.comment("Whether mobs will ignore a protected player. (They will not attack/aggro)")
.define("mobsIgnorePlayer", true);
builder.push("AllowedKeys");
LOGIN_KEY_ALLOW_LIST = builder
.comment("Allowed keys players can press without becoming active.\n" +
"Available values: PAUSE, DEBUG, FULLSCREEN, PERSPECTIVE, SMOOTH_CAMERA, SCREENSHOT, SPECTATOR_OUTLINES,\n" +
"ADVANCEMENTS, PLAYER_LIST, CHAT, SOCIAL_INTERACTIONS, LOAD_HOTBAR_ACTIVATOR, SAVE_HOTBAR_ACTIVATOR,\n" +
"SWAP_ITEM, INVENTORY, HOTBAR, DROP_ITEM, USE_ITEM, PICK_BLOCK, ATTACK, MOVE, SNEAK, JUMP")
.defineList("allowedKeys", Lists.newArrayList(KEYS.PAUSE.toString(), KEYS.DEBUG.toString(), KEYS.FULLSCREEN.toString(), KEYS.PERSPECTIVE.toString(), KEYS.SMOOTH_CAMERA.toString(),
KEYS.SCREENSHOT.toString(), KEYS.SPECTATOR_OUTLINES.toString(), KEYS.ADVANCEMENTS.toString(), KEYS.PLAYER_LIST.toString(), KEYS.CHAT.toString(), KEYS.SOCIAL_INTERACTIONS.toString(),
KEYS.LOAD_HOTBAR_ACTIVATOR.toString(), KEYS.SAVE_HOTBAR_ACTIVATOR.toString(), KEYS.SWAP_ITEM.toString(), KEYS.HOTBAR.toString(), KEYS.PICK_BLOCK.toString()), o -> o instanceof String);
builder.pop();
builder.push("Grace");
LOGIN_GRACE_ENABLED = builder
.comment("Whether a player receives a grace period after becoming active or not.")
.define("graceEnabled", true);
LOGIN_GRACE_MOBS_IGNORE_PLAYER = builder
.comment("Whether mobs ignore the player during their grace period.")
.define("graceMobsIgnorePlayer", true);
LOGIN_GRACE_DURATION = builder
.comment("How long the grace period lasts in seconds.")
.defineInRange("graceDuration", 10, 1, Integer.MAX_VALUE);
builder.pop();
builder.pop();
builder.comment("Settings for protecting players that are afk.").push("AFK");
AFK_PROTECTION_ENABLED = builder
.comment("Enable protection of afk players?")
.define("enabled", true);
AFK_TIME_THRESHOLD = builder
.comment("How long a player needs to be afk to become protected. (seconds)")
.defineInRange("timeThreshold", 600, 1, Integer.MAX_VALUE/20);
AFK_APPLY_POST_EFFECTS = builder
.comment("Whether to apply any post protection effects to afk players.")
.define("applyPostProtectionEffects", false);
AFK_MOBS_IGNORE_PLAYER = builder
.comment("Whether mobs will ignore a protected player. (They will not attack/aggro")
.define("mobsIgnorePlayerEnabled", true);
builder.push("AllowedKeys");
AFK_KEY_ALLOW_LIST = builder
.comment("Allowed keys players can press without becoming active.\n" +
"Available values: PAUSE, DEBUG, FULLSCREEN, PERSPECTIVE, SMOOTH_CAMERA, SCREENSHOT, SPECTATOR_OUTLINES,\n" +
"ADVANCEMENTS, PLAYER_LIST, CHAT, SOCIAL_INTERACTIONS, LOAD_HOTBAR_ACTIVATOR, SAVE_HOTBAR_ACTIVATOR,\n" +
"SWAP_ITEM, INVENTORY, HOTBAR, DROP_ITEM, USE_ITEM, PICK_BLOCK, ATTACK, MOVE, SNEAK, JUMP")
.defineList("allowedKeys", Lists.newArrayList(KEYS.PAUSE.toString(), KEYS.FULLSCREEN.toString(), KEYS.SCREENSHOT.toString(), KEYS.ADVANCEMENTS.toString()), o -> o instanceof String);
builder.pop();
builder.push("Grace");
AFK_GRACE_ENABLED = builder
.comment("Whether a player receives a grace period after becoming active or not.")
.define("graceEnabled", false);
AFK_GRACE_MOBS_IGNORE_PLAYER = builder
.comment("Whether mobs ignore the player during their grace period.")
.define("graceMobsIgnorePlayer", true);
AFK_GRACE_DURATION = builder
.comment("How long the grace period lasts in seconds.")
.defineInRange("graceDuration", 5, 1, Integer.MAX_VALUE);
builder.pop();
builder.pop();
builder.comment("Additional protection settings that apply as soon as a player becomes active if enabled.").push("Post");
builder.push("WaterProtection");
POST_REFILL_AIR_ENABLED = builder
.comment("Whether a player's air supply gets refilled.")
.define("refillAir", true);
POST_WATER_ENABLED = builder
.comment("Whether a player receives water breathing when in water.")
.define("waterEnabled", false);
POST_WATER_DURATION = builder
.comment("Water breathing duration in seconds.")
.defineInRange("waterDuration", 10, 1, Integer.MAX_VALUE/20);
builder.pop();
builder.push("LavaProtection");
POST_LAVA_ENABLED = builder
.comment("Whether a player receives fire resistance when in lava.")
.define("enabled", true);
POST_LAVA_DURATION = builder
.comment("Fire resistance duration in seconds.")
.defineInRange("duration", 10, 1, Integer.MAX_VALUE/20);
builder.pop();
builder.push("FireProtection");
POST_FIRE_ENABLED = builder
.comment("Whether a player receives fire resistance when on fire.")
.define("enabled", false);
POST_FIRE_DURATION = builder
.comment("Fire resistance duration in seconds.")
.defineInRange("duration", 10, 1, Integer.MAX_VALUE/20);
builder.pop();
builder.pop();
}
public enum KEYS {
PAUSE,
DEBUG,
FULLSCREEN,
PERSPECTIVE,
SMOOTH_CAMERA,
SCREENSHOT,
SPECTATOR_OUTLINES,
ADVANCEMENTS,
PLAYER_LIST,
CHAT,
SOCIAL_INTERACTIONS,
LOAD_HOTBAR_ACTIVATOR,
SAVE_HOTBAR_ACTIVATOR,
SWAP_ITEM,
INVENTORY,
HOTBAR,
DROP_ITEM,
USE_ITEM,
PICK_BLOCK,
ATTACK,
MOVE,
SNEAK,
JUMP
}
}
}

View File

@ -0,0 +1,58 @@
# This is an example mods.toml file. It contains the data relating to the loading mods.
# There are several mandatory fields (#mandatory), and many more that are optional (#optional).
# The overall format is standard TOML format, v0.5.0.
# Note that there are a couple of TOML lists in this file.
# Find more information on toml format here: https://github.com/toml-lang/toml
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
modLoader = "javafml" #mandatory
# A version range to match for said mod loader - for regular FML @Mod it will be the forge version
loaderVersion = "[40,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
license = "All Rights Reserved"
# A URL to refer people to when problems occur with this mod
#issueTrackerURL="http://my.issue.tracker/" #optional
# A list of mods - how many allowed here is determined by the individual mod loader
[[mods]] #mandatory
# The modid of the mod
modId = "loginprotection" #mandatory
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata
# see the associated build.gradle script for how to populate this completely automatically during a build
version = "${file.jarVersion}" #mandatory
# A display name for the mod
displayName = "Micle's Login Protection" #mandatory
# A URL to query for updates for this mod. See the JSON update specification <here>
#updateJSONURL="http://myurl.me/" #optional
# A URL for the "homepage" for this mod, displayed in the mod UI
#displayURL="http://example.com/" #optional
# A file name (in the root of the mod JAR) containing a logo for display
logoFile="logo.jpg" #optional
# A text field displayed in the mod UI
#credits="Thanks for this example mod goes to Java" #optional
# A text field displayed in the mod UI
authors = "Micle" #optional
# The description text for the mod (multi line!) (#mandatory)
description = '''
Protects players from damage while they are are joining a server or are AFK.
'''
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
[[dependencies.loginprotection]] #optional
# the modid of the dependency
modId = "forge" #mandatory
# Does this dependency have to exist - if not, ordering below must be specified
mandatory = true #mandatory
# The version range of the dependency
versionRange = "[40,)" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
ordering = "NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER
side = "BOTH"
# Here's another dependency
[[dependencies.loginprotection]]
modId = "minecraft"
mandatory = true
# This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange = "[1.18.2,1.19)"
ordering = "NONE"
side = "BOTH"

View File

@ -0,0 +1,15 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.micle.loginprotection.mixin",
"compatibilityLevel": "JAVA_17",
"refmap": "loginprotection.refmap.json",
"mixins": [
],
"injectors": {
"defaultRequire": 1
},
"client": [
"GuiRenderTickMixin"
]
}

BIN
src/main/resources/logo.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
{
"pack": {
"description": "loginprotection resources",
"pack_format": 8
}
}