diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java index fce5d87..bd358c4 100644 --- a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java @@ -1,21 +1,19 @@ package com.therainbowville.minegasm.client; -import com.mojang.authlib.GameProfile; import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.common.*; import com.therainbowville.minegasm.config.ClientConfig; import com.therainbowville.minegasm.config.MinegasmConfig; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; + import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; -import net.minecraft.world.IWorld; + +import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.ToolType; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; @@ -25,149 +23,117 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; + import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.*; +import java.util.stream.Collectors; +import java.lang.Thread; -@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) +@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ClientEventHandler { private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); - private static String playerName = null; - private static UUID playerID = null; - private static final int TICKS_PER_SECOND = 20; + private static int tickCounter = -1; private static int clientTickCounter = -1; - private static final double[] state = new double[1200]; private static boolean paused = false; - - private static void clearState() { - playerName = null; - playerID = null; - tickCounter = -1; - clientTickCounter = -1; - Arrays.fill(state, 0); - paused = false; + private static UUID playerId = null; + + private static Map vibrationStates = new HashMap(); + + static { + vibrationStates.put("advancement", new VibrationStateAdvancement()); + vibrationStates.put("attack", new VibrationStateAttack()); + vibrationStates.put("fish", new VibrationStateFish()); + vibrationStates.put("hurt", new VibrationStateHurt()); + vibrationStates.put("mine", new VibrationStateMine()); + vibrationStates.put("place", new VibrationStatePlace()); + vibrationStates.put("harvest", new VibrationStateHarvest((VibrationStateMine)vibrationStates.get("mine"))); + vibrationStates.put("vitality", new VibrationStateVitality()); + vibrationStates.put("xpChange", new VibrationStateXpChange()); + vibrationStates.put("generic", new VibrationStateClient()); } - private static int getStateCounter() { - return tickCounter / 20; + public static void afterConnect() + { + //setState(getStateCounter(), 5); + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); } - - private static void setState(int start, int duration, int intensity, boolean decay) { - if (duration <= 0) { - return; + + private static double getIntensity() + { + double intensity = 0; + for (Map.Entry state : vibrationStates.entrySet()) + { + intensity = Math.max(intensity, state.getValue().getIntensity()); +// LOGGER.info(state.getKey() + ": " + state.getValue().getIntensity()); + } - - if (decay) { - int safeDuration = Math.max(0, duration - 2); - for (int i = 0; i < safeDuration; i++) { - setState(start+i, intensity); - } - setState(start+safeDuration, intensity/2); - setState(start+safeDuration+1, intensity/4); - } else { - for (int i = 0; i < duration; i++) { - setState(start+i, intensity); - } + return intensity / 100; + } + + private static void tickAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.onTick(); } } - - private static void setState(int counter, int intensity) { - boolean accumulate = false; //XXX reserved for future use - setState(counter, intensity, accumulate); + + private static void resetAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.resetState(); + } } - private static void setState(int counter, int intensity, boolean accumulate) { - int safeCounter = counter % state.length; - if (accumulate) { - state[safeCounter] = Math.min(1.0, state[safeCounter] + (intensity / 100.0)); - } else { - state[safeCounter] = Math.min(1.0, Math.max(state[safeCounter], (intensity / 100.0))); + private static boolean isPlayer(Entity entity){ + try { + if (entity instanceof PlayerEntity && !(entity instanceof FakePlayer)) { + PlayerEntity player = (PlayerEntity) entity;; + UUID uuid = player.getGameProfile().getId(); + return uuid.equals(playerId); } + } catch (Throwable e) { + LOGGER.throwing(e); + } + return false; } - private static int getIntensity(String type) { - Map normal = new HashMap<>(); - normal.put("attack", 60); - normal.put("hurt", 0); - normal.put("mine", 80); - normal.put("xpChange", 100); - normal.put("harvest", 0); - normal.put("vitality", 0); - - Map masochist = new HashMap<>(); - masochist.put("attack", 0); - masochist.put("hurt", 100); - masochist.put("mine", 0); - masochist.put("xpChange", 0); - masochist.put("harvest", 0); - masochist.put("vitality", 10); - - Map hedonist = new HashMap<>(); - hedonist.put("attack", 60); - hedonist.put("hurt", 10); - hedonist.put("mine", 80); - hedonist.put("xpChange", 100); - hedonist.put("harvest", 20); - hedonist.put("vitality", 10); - - Map custom = new HashMap<>(); - custom.put("attack", MinegasmConfig.attackIntensity); - custom.put("hurt", MinegasmConfig.hurtIntensity); - custom.put("mine", MinegasmConfig.mineIntensity); - custom.put("xpChange", MinegasmConfig.xpChangeIntensity); - custom.put("harvest", MinegasmConfig.harvestIntensity); - custom.put("vitality", MinegasmConfig.vitalityIntensity); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - return masochist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.HEDONIST)) { - return hedonist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.CUSTOM)) { - return custom.get(type); - } else { - return normal.get(type); - } + private static void clearState() { + tickCounter = -1; + clientTickCounter = -1; + paused = false; + resetAll(); } @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { - if (event.phase == TickEvent.Phase.END) { + try { + if (event.phase == TickEvent.Phase.END && isPlayer(event.player)) { PlayerEntity player = event.player; - GameProfile profile = player.getGameProfile(); - - float playerHealth = player.getHealth(); - float playerFoodLevel = player.getFoodData().getFoodLevel(); - - tickCounter = (tickCounter + 1) % (20 * (60 * TICKS_PER_SECOND)); // 20 min day cycle - - if (tickCounter % TICKS_PER_SECOND == 0) { // every 1 sec - if (profile.getId().equals(playerID)) { - int stateCounter = getStateCounter(); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - if (playerHealth > 0 && playerHealth <= 1) { - setState(stateCounter, getIntensity("vitality")); - } - } else if (playerHealth >= 20 && playerFoodLevel >= 20) { - setState(stateCounter, getIntensity("vitality")); - } - - double newVibrationLevel = state[stateCounter]; - state[stateCounter] = 0; - - LOGGER.trace("Tick " + stateCounter + ": " + newVibrationLevel); - - if (ToyController.currentVibrationLevel != newVibrationLevel) { - ToyController.setVibrationLevel(newVibrationLevel); - } - } + + tickCounter = (tickCounter + 1) % 100; + + + if (tickCounter % MinegasmConfig.tickFrequency == 0) // TODO: Add ticks per second config option (Default: Every tick) + { + tickAll(); + + ((VibrationStateVitality)vibrationStates.get("vitality")).onTick(player); + ((VibrationStateFish)vibrationStates.get("fish")).onTick(Minecraft.getInstance().player); + + double newVibrationLevel = getIntensity(); + + if (ToyController.currentVibrationLevel != newVibrationLevel) + ToyController.setVibrationLevel(newVibrationLevel); } - if (tickCounter % (5 * TICKS_PER_SECOND) == 0) { // 5 secs - LOGGER.debug("Health: " + playerHealth); - LOGGER.debug("Food: " + playerFoodLevel); - } + } + } catch (Throwable e) { + LOGGER.throwing(e); } } @@ -196,14 +162,9 @@ public static void onClientTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public static void onAttack(AttackEntityEvent event) { - Entity entity = event.getEntityLiving(); - if (entity instanceof PlayerEntity) { - PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - setState(getStateCounter(), 3, getIntensity("attack"), true); - } + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateAttack)vibrationStates.get("attack")).onAttack(); } } @@ -216,84 +177,36 @@ public static void onCriticalHit(CriticalHitEvent event) @SubscribeEvent public static void onHurt(LivingHurtEvent event) { - Entity entity = event.getEntityLiving(); - if (entity instanceof PlayerEntity) { - PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - setState(getStateCounter(), 3, getIntensity("hurt"), true); - } + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateHurt)vibrationStates.get("hurt")).onHurt(); } } @SubscribeEvent - public static void onDeath(LivingDeathEvent event) + public static void onBreak(BlockEvent.BreakEvent event) { - Entity entity = event.getEntityLiving(); - if (entity instanceof PlayerEntity) { - PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - ToyController.setVibrationLevel(0); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateMine)vibrationStates.get("mine")).onBreak(event.getState()); } } - + + // Triggers when player starts to break block @SubscribeEvent public static void onHarvest(PlayerEvent.HarvestCheck event) { - PlayerEntity player = event.getPlayer(); - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - BlockState blockState = event.getTargetBlock(); - Block block = blockState.getBlock(); - - // ToolType. AXE, HOE, PICKAXE, SHOVEL - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - LOGGER.debug("Harvest: tool: " + - block.getHarvestTool(blockState) + - " can harvest? " + event.canHarvest() + " hardness: " + blockHardness); - - int intensity = Math.toIntExact(Math.round((getIntensity("harvest") / 100.0 * (blockHardness / 50.0)) * 100)); - - if (event.canHarvest()) { - setState(getStateCounter(), 1, intensity, false); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateHarvest)vibrationStates.get("harvest")).onHarvest(); } } - + @SubscribeEvent - public static void onBreak(BlockEvent.BreakEvent event) - { - PlayerEntity player = event.getPlayer(); - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - BlockState blockState = event.getState(); - Block block = blockState.getBlock(); - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - - LOGGER.info("Breaking: " + block.toString()); - - ToolType blockHarvestTool = block.getHarvestTool(blockState); - ItemStack mainhandItem = event.getPlayer().getMainHandItem(); - Set mainhandToolTypes = mainhandItem.getItem().getToolTypes(mainhandItem); - - boolean usingPickaxe = mainhandToolTypes.contains(ToolType.PICKAXE); - boolean usingAppropriateTool = mainhandToolTypes.contains(blockHarvestTool); - LOGGER.debug("mainhand: " + mainhandItem + " [" + mainhandToolTypes + "]"); - LOGGER.debug("using pickaxe: " + usingPickaxe + ", using appropriate tool: " + usingAppropriateTool); - - if (usingPickaxe && usingAppropriateTool) { - int duration = Math.max(1, Math.min(5, Math.toIntExact(Math.round(Math.ceil(Math.log(blockHardness + 0.5)))))); - int intensity = Math.toIntExact(Math.round((getIntensity("mine") / 100.0 * (blockHardness / 50.0)) * 100)); - setState(getStateCounter(), duration, intensity, true); - } - - LOGGER.info("XP to drop: " + event.getExpToDrop()); + public static void onPlace(BlockEvent.EntityPlaceEvent event){ + if (isPlayer(event.getEntity())) + { + ((VibrationStatePlace)vibrationStates.get("place")).onPlace(); } } @@ -312,68 +225,84 @@ public static void onXpPickup(PlayerXpEvent.PickupXp event) @SubscribeEvent public static void onXpChange(PlayerXpEvent.XpChange event) { - PlayerEntity player = event.getPlayer(); - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - int xpChange = event.getAmount(); - long duration = Math.round(Math.ceil(Math.log(xpChange + 0.5))); - - LOGGER.info("XP CHANGE: " + xpChange); - LOGGER.debug("duration: " + duration); - - setState(getStateCounter(), Math.toIntExact(duration), getIntensity("xpChange"), true); + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateXpChange)vibrationStates.get("xpChange")).onXpChange(((PlayerEntity)event.getEntityLiving()).totalExperience, event.getAmount()); + } + } + + + @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event) + { + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateAdvancement)vibrationStates.get("advancement")).onAdvancement(event); } } @SubscribeEvent public static void onRespawn(PlayerEvent.PlayerRespawnEvent event) { - clearState(); - ToyController.setVibrationLevel(0); - populatePlayerInfo(); - } + Entity entity = event.getEntity(); + if( !entity.level.isClientSide() ) { + return; + } - private static void populatePlayerInfo() { - GameProfile profile = Minecraft.getInstance().getUser().getGameProfile(); - playerName = profile.getName(); - playerID = profile.getId(); - System.out.println("Current player: " + playerName + " " + playerID.toString()); - } + if (entity instanceof PlayerEntity) { + LOGGER.info("Client Entered world: " + entity.toString()); - @SubscribeEvent - public static void onWorldLoaded(WorldEvent.Load event) { - IWorld world = event.getWorld(); - System.out.println("World loaded: " + world.toString()); + try { + PlayerEntity player = (PlayerEntity) entity; + UUID uuid = player.getGameProfile().getId(); + + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { + LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + clearState(); + ToyController.setVibrationLevel(0); + playerId = uuid; + } + } catch (Throwable e) { + LOGGER.throwing(e); + } + } - populatePlayerInfo(); } + @SubscribeEvent public static void onWorldEntry(EntityJoinWorldEvent event) { Entity entity = event.getEntity(); - if (entity instanceof ClientPlayerEntity) { - System.out.println("Entered world: " + entity.toString()); + if( !entity.level.isClientSide() ) { + return; + } + + if (ToyController.isConnected) return; - if (playerName != null) { + if (entity instanceof PlayerEntity) { + LOGGER.info("Player respawn world: " + entity.toString()); + + new Thread(()-> { try { PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - System.out.println("Player in: " + playerName + " " + playerID.toString()); + UUID uuid = player.getGameProfile().getId(); + + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { + LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + LOGGER.info("Stealth: " + MinegasmConfig.stealth); if (ToyController.connectDevice()) { - setState(getStateCounter(), 5); - player.displayClientMessage(new StringTextComponent(String.format("Connected to " + TextFormatting.GREEN + "%s" + TextFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); - } else { + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); + if (!MinegasmConfig.stealth){ + player.displayClientMessage(new StringTextComponent(String.format("Connected to " + TextFormatting.GREEN + "%s" + TextFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); + } + } else if (!MinegasmConfig.stealth){ player.displayClientMessage(new StringTextComponent(String.format(TextFormatting.YELLOW + "Minegasm " + TextFormatting.RESET + "failed to start\n%s", ToyController.getLastErrorMessage())), false); } + playerId = uuid; } - } + } catch (Throwable e) { + LOGGER.throwing(e); + }}).start(); } } - @SubscribeEvent - public static void onWorldExit(WorldEvent.Unload event) { - clearState(); - } } diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java index 4d5a865..4577128 100644 --- a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java @@ -10,10 +10,16 @@ import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.Executors; public class ToyController { private static final Logger LOGGER = LogManager.getLogger(); - private static final ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); + private static ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); private static ButtplugClientDevice device = null; private static boolean shutDownHookAdded = false; public static String lastErrorMessage = ""; @@ -24,9 +30,28 @@ public static boolean connectDevice() { try { device = null; client.disconnect(); + LOGGER.info("URL: " + MinegasmConfig.serverUrl); - client.connect(new URI(MinegasmConfig.serverUrl)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new Callable() { + public Void call() throws Exception { + client.connect(new URI(MinegasmConfig.serverUrl)); + return null; + } + }); + + try + { + future.get(3, TimeUnit.SECONDS); + } catch (TimeoutException e) { + future.cancel(true); + client = new ButtplugClientWSClient("Minegasm"); + throw new TimeoutException("Could not find WebSocket"); + } finally { + executor.shutdownNow(); + } + client.startScanning(); Thread.sleep(5000); @@ -73,7 +98,7 @@ public static boolean connectDevice() { isConnected = true; } catch (Exception e) { lastErrorMessage = e.getMessage(); - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } return Objects.nonNull(device); diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java new file mode 100644 index 0000000..8e264a0 --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java @@ -0,0 +1,132 @@ +package com.therainbowville.minegasm.common; + +import java.util.Map; +import java.util.HashMap; + +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Architecture inspired from https://github.com/Fyustorm/mInetiface +public abstract class AbstractVibrationState +{ + + protected static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); + protected final float streakCountdownAmount; + protected float intensity; + + protected float vibrationCountdown; + protected float vibrationFeedbackCountdown; + + protected AbstractVibrationState(float streakSeconds) + { + streakCountdownAmount = streakSeconds; + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + public void onTick() + { + if (accumulationEnabled()) + { + if (vibrationCountdown > 0) + vibrationCountdown--; + else if (intensity > 0) { + intensity = Math.max(0, intensity - 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + vibrationCountdown = Math.max(0, vibrationCountdown - 1); + } + + vibrationFeedbackCountdown = Math.max(0, vibrationFeedbackCountdown - 1); + } + + public void resetState() + { + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + protected static boolean accumulationEnabled() + { + return MinegasmConfig.mode.equals(ClientConfig.GameplayMode.ACCUMULATION); + } + + public static int getIntensity(String type) { + Map normal = new HashMap<>(); + normal.put("attack", 60); + normal.put("hurt", 0); + normal.put("mine", 80); + normal.put("place", 20); + normal.put("xpChange", 100); + normal.put("harvest", 10); + normal.put("fishing", 50); + normal.put("vitality", 0); + normal.put("advancement", 100); + + Map masochist = new HashMap<>(); + masochist.put("attack", 0); + masochist.put("hurt", 100); + masochist.put("mine", 0); + masochist.put("place", 0); + masochist.put("xpChange", 0); + masochist.put("fishing", 0); + masochist.put("harvest", 0); + masochist.put("vitality", 10); + masochist.put("advancement", 0); + + Map hedonist = new HashMap<>(); + hedonist.put("attack", 60); + hedonist.put("hurt", 10); + hedonist.put("mine", 80); + hedonist.put("place", 20); + hedonist.put("xpChange", 100); + hedonist.put("fishing", 50); + hedonist.put("harvest", 20); + hedonist.put("vitality", 10); + hedonist.put("advancement", 100); + + Map accumulation = new HashMap<>(); + accumulation.put("attack", 1); + accumulation.put("hurt", 1); + accumulation.put("mine", 1); + accumulation.put("place", 1); + accumulation.put("xpChange", 1); + accumulation.put("fishing", 50); + accumulation.put("harvest", 10); + accumulation.put("vitality", 0); + accumulation.put("advancement", 1); + + Map custom = new HashMap<>(); + custom.put("attack", MinegasmConfig.attackIntensity); + custom.put("hurt", MinegasmConfig.hurtIntensity); + custom.put("mine", MinegasmConfig.mineIntensity); + custom.put("place", MinegasmConfig.placeIntensity); + custom.put("xpChange", MinegasmConfig.xpChangeIntensity); + custom.put("fishing", MinegasmConfig.fishingIntensity); + custom.put("harvest", MinegasmConfig.harvestIntensity); + custom.put("vitality", MinegasmConfig.vitalityIntensity); + custom.put("advancement", MinegasmConfig.advancementIntensity); + + + int returnValue = -1; + + switch (MinegasmConfig.mode) + { + case NORMAL: returnValue = normal.get(type); + case MASOCHIST: returnValue = masochist.get(type); + case HEDONIST: returnValue = hedonist.get(type); + case ACCUMULATION: returnValue = accumulation.get(type); + case CUSTOM: returnValue = custom.get(type); + }; + + return returnValue; + } + + public abstract int getIntensity(); +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java new file mode 100644 index 0000000..09d478d --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java @@ -0,0 +1,55 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.advancements.FrameType; +import net.minecraft.advancements.Advancement; +import net.minecraftforge.event.entity.player.AdvancementEvent; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAdvancement extends AbstractVibrationState +{ + public VibrationStateAdvancement() + { + super(0); + } + + public void onAdvancement(AdvancementEvent event) + { + if (getIntensity("advancement") == 0) return; + try { + LOGGER.info("Advancement Event: " + event); + Advancement advancement = event.getAdvancement(); + if (advancement == null) return; + FrameType type = advancement.getDisplay().getFrame(); + int duration = 0; + + switch (type) { + case TASK: + duration = 5; + break; + case GOAL: + duration = 7; + break; + case CHALLENGE: + duration = 10; + break; + }; + + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("advancement") + 20); + else if (vibrationCountdown > 0) + return getIntensity("advancement"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java new file mode 100644 index 0000000..acd0375 --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAttack extends AbstractVibrationState +{ + public VibrationStateAttack() + { + super(3); + } + + public void onAttack() + { + if (getIntensity("attack") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * 0; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("attack") + 20); + else if (vibrationCountdown > 0) + return getIntensity("attack"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java new file mode 100644 index 0000000..c952b68 --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java @@ -0,0 +1,24 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateClient extends AbstractVibrationState +{ + public VibrationStateClient() + { + super(0); + } + + public void setVibration(int intensity, int durationSeconds) + { + intensity = intensity; + vibrationCountdown = durationSeconds * MinegasmConfig.ticksPerSecond; + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return Math.toIntExact(Math.round(intensity)); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java new file mode 100644 index 0000000..6353a0e --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java @@ -0,0 +1,43 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.entity.projectile.FishingBobberEntity; +import net.minecraft.util.math.Vec3d; + +import com.therainbowville.minegasm.config.MinegasmConfig; + + +public class VibrationStateFish extends AbstractVibrationState +{ + + public VibrationStateFish() + { + super(0); + } + + public void onTick(ClientPlayerEntity player) + { + if (player == null) return; + + if (player.fishing != null) + { + Vec3d vector = player.fishing.getDeltaMovement(); + double x = vector.x(); + double y = vector.y(); + double z = vector.z(); + if (y < -0.075 && player.fishing.isInWater() && x == 0 && z == 0) + { + vibrationCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + LOGGER.info("Fishing!"); + } + } + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return getIntensity("fishing"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java new file mode 100644 index 0000000..a7254ab --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java @@ -0,0 +1,30 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHarvest extends AbstractVibrationState +{ + private VibrationStateMine mineState; + + public VibrationStateHarvest(VibrationStateMine state) + { + super(0); + mineState = state; + } + + public void onHarvest() { + vibrationCountdown = 3; + mineState.onHarvest(); + } + + public int getIntensity() + { + if (vibrationCountdown > 0){ + if (accumulationEnabled()) + return Math.min(100, mineState.getIntensity() + 20); + else + return getIntensity("harvest"); + } + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java new file mode 100644 index 0000000..7219c5e --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java @@ -0,0 +1,36 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHurt extends AbstractVibrationState +{ + public VibrationStateHurt() + { + super(3); + } + + public void onHurt() { + if (getIntensity("hurt") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 10); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("hurt") + 20); + else if (vibrationCountdown > 0) + return getIntensity("hurt"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java new file mode 100644 index 0000000..477f80b --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.block.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateMine extends AbstractVibrationState +{ + public VibrationStateMine() + { + super(5); + } + + public void onBreak(BlockState block) { + if (getIntensity("mine") == 0) return; + + String blockName = block.getBlock().getName().getString(); + if (accumulationEnabled()) + { + if (blockName.contains("Ore")) { + intensity = Math.min(100, intensity + 1); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + intensity = Math.min(100, intensity + .25f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + if (blockName.contains("Ore")) { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public void onHarvest() { + if (accumulationEnabled()){ + vibrationCountdown = Math.max(3, vibrationCountdown); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("mine") + 20); + else if (vibrationCountdown > 0) + return getIntensity("mine"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java new file mode 100644 index 0000000..aee4ebf --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java @@ -0,0 +1,35 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStatePlace extends AbstractVibrationState +{ + public VibrationStatePlace() + { + super(5); + } + + public void onPlace() { + if (getIntensity("place") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + .5f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("place") + 20); + else if (vibrationCountdown > 0) + return getIntensity("place"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java new file mode 100644 index 0000000..20c13d9 --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java @@ -0,0 +1,62 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.entity.player.PlayerEntity; + +import com.therainbowville.minegasm.config.MinegasmConfig; +import com.therainbowville.minegasm.config.ClientConfig; + +public class VibrationStateVitality extends AbstractVibrationState +{ + private int intensityCooldown; + private boolean targetMet; + + public VibrationStateVitality() + { + super(1); + intensityCooldown = 0; + targetMet = false; + } + + public void onTick(PlayerEntity player) + { + float playerHealth = player.getHealth(); + float playerFoodLevel = player.getFoodData().getFoodLevel(); + + if ((MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth > 0 && playerHealth <= 1 ) + || (!MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth >= 20 && playerFoodLevel >= 20) ){ + + if (targetMet == false){ + targetMet = true; + vibrationFeedbackCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } else + targetMet = false; + +// if (accumulationEnabled() && targetMet) +// { +// if (intensityCooldown == 0) { +// intensity = Math.min(100, intensity + .1f); +// intensityCooldown = 10 * 20; +// } +// vibrationCountdown = streakCountdownAmount; +// intensityCooldown = Math.max(0, intensityCooldown - 1); +// } else + if (targetMet) { + vibrationCountdown = 1; + } + } + + public int getIntensity() + { + if (getIntensity("vitality") == 0) return 0; + + //if (accumulationEnabled()) + //return Math.toIntExact(Math.round(intensity)); + //else + if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("vitality") + 20); + else if (vibrationCountdown > 0) + return getIntensity("vitality"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java new file mode 100644 index 0000000..34b1633 --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateXpChange extends AbstractVibrationState +{ + private int lastLevel; + + public VibrationStateXpChange() + { + super(1); + lastLevel = -1; + } + + // Code adapted from https://github.com/Fyustorm/mInetiface + public void onXpChange(int level, int amount) { + if (amount == 0 || getIntensity("xpChange") == 0) + return; + + if (lastLevel == -1) { + lastLevel = level; + } + + if (lastLevel != level) { + amount *= 2; + } + + lastLevel = level; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + amount / 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + int duration = Math.toIntExact( Math.round( Math.ceil( Math.log(amount + 0.5) ) ) ); + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("xpChange") + 20); + else if (vibrationCountdown > 0) + return getIntensity("xpChange"); + else return 0; + } +} + diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java index d802600..bbd310c 100644 --- a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java @@ -1,86 +1,147 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.Minecraft; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.mclanguageprovider.MinecraftModLanguageProvider; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.common.ForgeConfigSpec.IntValue; import java.util.Objects; public final class ClientConfig { final ForgeConfigSpec.ConfigValue serverUrl; - final ForgeConfigSpec.ConfigValue version; final ForgeConfigSpec.BooleanValue vibrate; final ForgeConfigSpec.EnumValue mode; + final ForgeConfigSpec.BooleanValue stealth; + final ForgeConfigSpec.EnumValue tickFrequency; + final ForgeConfigSpec.IntValue attackIntensity; final ForgeConfigSpec.IntValue hurtIntensity; final ForgeConfigSpec.IntValue mineIntensity; + final ForgeConfigSpec.IntValue placeIntensity; final ForgeConfigSpec.IntValue xpChangeIntensity; + final ForgeConfigSpec.IntValue fishingIntensity; final ForgeConfigSpec.IntValue harvestIntensity; final ForgeConfigSpec.IntValue vitalityIntensity; + final ForgeConfigSpec.IntValue advancementIntensity; + + static final String DEFAULT_SERVER_URL = "ws://localhost:12345/buttplug"; + static final boolean DEFAULT_VIBRATE = true; + static final GameplayMode DEFAULT_MODE = GameplayMode.NORMAL; + static final boolean DEFAULT_STEALTH = false; + + static final int DEFAULT_ATTACK_INTENSITY = 60; + static final int DEFAULT_HURT_INTENSITY = 0; + static final int DEFAULT_MINE_INTENSITY = 80; + static final int DEFAULT_PLACE_INTENSITY = 20; + static final int DEFAULT_XP_CHANGE_INTENSITY = 100; + static final int DEFAULT_FISHING_INTENSITY = 50; + static final int DEFAULT_HARVEST_INTENSITY = 0; + static final int DEFAULT_VITALITY_INTENSITY = 0; + static final int DEFAULT_ADVANCEMENT_INTENSITY = 100; + ClientConfig(final ForgeConfigSpec.Builder builder) { builder.push("buttplug"); serverUrl = builder .translation(Minegasm.MOD_ID + ".config.serverUrl") - .define("serverUrl", "ws://localhost:12345/buttplug"); + .define("serverUrl", DEFAULT_SERVER_URL); builder.pop(); builder.push("minegasm"); - version = builder - .translation(Minegasm.MOD_ID + ".config.version") - .define("version", "0.3"); - vibrate = builder .translation(Minegasm.MOD_ID + ".config.vibrate") - .define("vibrate", true); + .define("vibrate", DEFAULT_VIBRATE); mode = builder .translation(Minegasm.MOD_ID + ".config.mode") - .defineEnum("mode", GameplayMode.NORMAL); + .defineEnum("mode", DEFAULT_MODE); + stealth = builder + .translation(Minegasm.MOD_ID + ".config.stealth") + .define("stealth", DEFAULT_STEALTH); + + tickFrequency = builder + .translation(Minegasm.MOD_ID + ".config.mode") + .defineEnum("tickFrequency", TickFrequencyOptions.EVERY_TICK); builder.push("intensity"); attackIntensity = builder .comment("Vibration intensity when attacking on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.attack") - .defineInRange("attackIntensity", 60, 0, 100); + .defineInRange("attackIntensity", DEFAULT_ATTACK_INTENSITY, 0, 100); hurtIntensity = builder .comment("Vibration intensity when hurting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.hurt") - .defineInRange("hurtIntensity", 0, 0, 100); + .defineInRange("hurtIntensity", DEFAULT_HURT_INTENSITY, 0, 100); mineIntensity = builder .comment("Vibration intensity when mining on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.mine") - .defineInRange("mineIntensity", 80, 0, 100); + .defineInRange("mineIntensity", DEFAULT_MINE_INTENSITY, 0, 100); + + placeIntensity = builder + .comment("Vibration intensity when placing blocks on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.place") + .defineInRange("placeIntensity", DEFAULT_PLACE_INTENSITY, 0, 100); xpChangeIntensity = builder .comment("Vibration intensity when gaining XP on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.xp_change") - .defineInRange("xpChangeIntensity", 100, 0, 100); + .defineInRange("xpChangeIntensity", DEFAULT_XP_CHANGE_INTENSITY, 0, 100); + + fishingIntensity = builder + .comment("Vibration intensity when fishing on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.fishing") + .defineInRange("fishingIntensity", DEFAULT_FISHING_INTENSITY, 0, 100); harvestIntensity = builder .comment("Vibration intensity when harvesting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.harvest") - .defineInRange("harvestIntensity", 0, 0, 100); + .defineInRange("harvestIntensity", DEFAULT_HARVEST_INTENSITY, 0, 100); vitalityIntensity = builder .comment("Vibration intensity on high level of player's vitality on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.vitality") - .defineInRange("vitalityIntensity", 0, 0, 100); + .defineInRange("vitalityIntensity", DEFAULT_VITALITY_INTENSITY, 0, 100); + + advancementIntensity = builder + .comment("Vibration intensity on achieving advancement on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.advancement") + .defineInRange("advancementIntensity", DEFAULT_ADVANCEMENT_INTENSITY, 0, 100); builder.pop(); builder.pop(); } + + public void resetConfigUrl() + { + ConfigHolder.CLIENT.serverUrl.set(DEFAULT_SERVER_URL); + } + + public void resetConfigCustom() + { + ConfigHolder.CLIENT.attackIntensity.set(DEFAULT_ATTACK_INTENSITY); + ConfigHolder.CLIENT.hurtIntensity.set(DEFAULT_HURT_INTENSITY); + ConfigHolder.CLIENT.mineIntensity.set(DEFAULT_MINE_INTENSITY); + ConfigHolder.CLIENT.placeIntensity.set(DEFAULT_PLACE_INTENSITY); + ConfigHolder.CLIENT.xpChangeIntensity.set(DEFAULT_XP_CHANGE_INTENSITY); + ConfigHolder.CLIENT.fishingIntensity.set(DEFAULT_FISHING_INTENSITY); + ConfigHolder.CLIENT.harvestIntensity.set(DEFAULT_HARVEST_INTENSITY); + ConfigHolder.CLIENT.vitalityIntensity.set(DEFAULT_VITALITY_INTENSITY); + ConfigHolder.CLIENT.advancementIntensity.set(DEFAULT_ADVANCEMENT_INTENSITY); + } + public enum GameplayMode { NORMAL("gui." + Minegasm.MOD_ID + ".config.mode.normal"), MASOCHIST("gui." + Minegasm.MOD_ID + ".config.mode.masochist"), HEDONIST("gui." + Minegasm.MOD_ID + ".config.mode.hedonist"), + ACCUMULATION("gui." + Minegasm.MOD_ID + ".config.mode.accumulation"), CUSTOM("gui." + Minegasm.MOD_ID + ".config.mode.custom"); private final String translateKey; @@ -93,5 +154,65 @@ public enum GameplayMode { public String getTranslateKey() { return this.translateKey; } + + public GameplayMode next() + { + boolean foundCurrent = false; + for (GameplayMode type : values()) + { + if (foundCurrent) + return type; + else if (this == type) + foundCurrent = true; + } + return values()[0]; + } + + } + + public enum TickFrequencyOptions { + EVERY_TICK(1), + EVERY_OTHER_TICK(2), + EVERY_5_TICKS(5), + EVERY_10_TICKS(10), + EVERY_20_TICKS(20), + EVERY_30_TICKS(30), + EVERY_40_TICKS(40), + EVERY_50_TICKS(50); + + private int value; + + TickFrequencyOptions(int value) { + this.value = value; + } + + public int getInt() + { + return value; + } + + public static TickFrequencyOptions fromInt(int value) + { + for (TickFrequencyOptions type : values()) { + if (type.getInt() == value) { + return type; + } + } + return null; + } + + public TickFrequencyOptions next() + { + boolean foundCurrent = false; + for (TickFrequencyOptions type : values()) + { + if (foundCurrent) + return type; + else if (this == type) + foundCurrent = true; + } + return values()[0]; + } } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java index 4441fb2..c647c9f 100644 --- a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java @@ -1,20 +1,61 @@ package com.therainbowville.minegasm.config; +//import net.minecraftforge.fmlclient.ConfigGuiHandler; +//import net.minecraftforge.common.ForgeConfigSpec; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public final class ConfigHelper { + private static final Logger LOGGER = LogManager.getLogger(); public static void bakeClient() { MinegasmConfig.serverUrl = ConfigHolder.CLIENT.serverUrl.get(); MinegasmConfig.vibrate = ConfigHolder.CLIENT.vibrate.get(); MinegasmConfig.mode = ConfigHolder.CLIENT.mode.get(); + MinegasmConfig.stealth = ConfigHolder.CLIENT.stealth.get(); + MinegasmConfig.tickFrequency = ConfigHolder.CLIENT.tickFrequency.get().getInt(); + MinegasmConfig.ticksPerSecond = Math.max(1, Math.toIntExact(20 / MinegasmConfig.tickFrequency)); + MinegasmConfig.attackIntensity = ConfigHolder.CLIENT.attackIntensity.get(); MinegasmConfig.hurtIntensity = ConfigHolder.CLIENT.hurtIntensity.get(); MinegasmConfig.mineIntensity = ConfigHolder.CLIENT.mineIntensity.get(); + MinegasmConfig.placeIntensity = ConfigHolder.CLIENT.placeIntensity.get(); MinegasmConfig.xpChangeIntensity = ConfigHolder.CLIENT.xpChangeIntensity.get(); + MinegasmConfig.fishingIntensity = ConfigHolder.CLIENT.fishingIntensity.get(); MinegasmConfig.harvestIntensity = ConfigHolder.CLIENT.harvestIntensity.get(); MinegasmConfig.vitalityIntensity = ConfigHolder.CLIENT.vitalityIntensity.get(); + MinegasmConfig.advancementIntensity = ConfigHolder.CLIENT.advancementIntensity.get(); } public static void bakeServer() { } + + public static void saveClient() + { + try{ + + MinegasmConfigBuffer buffer = new MinegasmConfigBuffer(); + + ConfigHolder.CLIENT.serverUrl.set(buffer.serverUrl); + ConfigHolder.CLIENT.vibrate.set(buffer.vibrate); + ConfigHolder.CLIENT.mode.set(buffer.mode); + ConfigHolder.CLIENT.stealth.set(buffer.stealth); + ConfigHolder.CLIENT.tickFrequency.set(ClientConfig.TickFrequencyOptions.fromInt(buffer.tickFrequency)); + + ConfigHolder.CLIENT.attackIntensity.set(buffer.attackIntensity); + ConfigHolder.CLIENT.hurtIntensity.set(buffer.hurtIntensity); + ConfigHolder.CLIENT.mineIntensity.set(buffer.mineIntensity); + ConfigHolder.CLIENT.placeIntensity.set(buffer.placeIntensity); + ConfigHolder.CLIENT.xpChangeIntensity.set(buffer.xpChangeIntensity); + ConfigHolder.CLIENT.fishingIntensity.set(buffer.fishingIntensity); + ConfigHolder.CLIENT.harvestIntensity.set(buffer.harvestIntensity); + ConfigHolder.CLIENT.vitalityIntensity.set(buffer.vitalityIntensity); + ConfigHolder.CLIENT.advancementIntensity.set(buffer.advancementIntensity); + } catch (Throwable e) + { + LOGGER.info(e); + } + } } \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java index 26ff331..634ae5f 100644 --- a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java @@ -1,209 +1,345 @@ package com.therainbowville.minegasm.config; -import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.GameSettings; -import net.minecraft.client.gui.screen.IngameMenuScreen; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.IngameMenuScreen; +import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.client.gui.widget.list.OptionsRowList; -import net.minecraft.client.settings.AbstractOption; -import net.minecraft.client.settings.BooleanOption; -import net.minecraft.client.settings.IteratableOption; -import net.minecraft.client.settings.SliderPercentageOption; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.StringTextComponent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import java.util.Objects; +import net.minecraftforge.fml.client.gui.widget.ExtendedButton; +import net.minecraftforge.eventbus.api.SubscribeEvent; -public final class ConfigScreen extends Screen { - private static final Logger LOGGER = LogManager.getLogger(); - private static final int TITLE_HEIGHT = 8; - private static final int OPTIONS_LIST_TOP_HEIGHT = 24; // top screen to top option list - private static final int OPTIONS_LIST_BOTTOM_OFFSET = 32; // bottom screen to bottom option list - private static final int OPTIONS_LIST_ITEM_HEIGHT = 25; +import net.minecraftforge.client.gui.widget.ForgeSlider; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.client.ToyController; +import com.therainbowville.minegasm.client.ClientEventHandler; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; - private static final int BUTTON_WIDTH = 200; - private static final int BUTTON_HEIGHT = 20; - private static final int DONE_BUTTON_TOP_OFFSET = 26; // bottom screen to done button top - private final Screen lastScreen; - private OptionsRowList optionsRowList; +import java.lang.reflect.Field; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Objects; - private static final ClientConfig clientConfig = ConfigHolder.getClientInstance(); +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; - public ConfigScreen(Screen parentScreen) { - super(new StringTextComponent(Minegasm.NAME)); - this.lastScreen = parentScreen; - } +public class ConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + TextFieldWidget wsHost = null; - private static boolean vibrate = false; - private static int mode = 0; - private static int attackIntensity = 0; - private static int hurtIntensity = 0; - private static int mineIntensity = 0; - private static int xpChangeIntensity = 0; - private static int harvestIntensity = 0; - private static int vitalityIntensity = 0; + public ClientConfig.TickFrequencyOptions tickValue; + private PlainTextLabel connectResponse; + + public ConfigScreen(Screen previous) { + super(new StringTextComponent("Minegasm Config")); + this.previous = previous; + pauseMenu = false; + tickValue = ClientConfig.TickFrequencyOptions.fromInt(MinegasmConfig.tickFrequency); + } + + public ConfigScreen(Screen previous, boolean pause) { + super(new StringTextComponent("Minegasm Config")); + this.previous = previous; + pauseMenu = pause; + tickValue = ClientConfig.TickFrequencyOptions.fromInt(MinegasmConfig.tickFrequency); + } @Override protected void init() { - LOGGER.debug("Initializing config screen"); - - vibrate = MinegasmConfig.vibrate; - mode = MinegasmConfig.mode.ordinal(); - attackIntensity = MinegasmConfig.attackIntensity; - hurtIntensity = MinegasmConfig.hurtIntensity; - mineIntensity = MinegasmConfig.mineIntensity; - xpChangeIntensity = MinegasmConfig.xpChangeIntensity; - harvestIntensity = MinegasmConfig.harvestIntensity; - vitalityIntensity = MinegasmConfig.vitalityIntensity; - - this.optionsRowList = createOptions(); - this.children.add(this.optionsRowList); - - this.addButton(new Button( - (this.width - BUTTON_WIDTH) / 2, - this.height - DONE_BUTTON_TOP_OFFSET, - BUTTON_WIDTH, BUTTON_HEIGHT, - "Done", - button -> this.onClose() + wsHost = new TextFieldWidget(Minecraft.getInstance().font, this.width / 2 - 100, this.height / 6, 200, 20, "ws://localhost:12345"); + wsHost.setValue(MinegasmConfig.serverUrl); + this.addButton(wsHost); + + wsHost.setResponder(s -> { + LOGGER.info(s); + MinegasmConfig.serverUrl = s; + }); + + this.addButton(new ExtendedButton( + this.width / 2 - 155, this.height / 6 + 25, 150, 20, + "Reset Server Url", button -> { + ConfigHolder.getClientInstance().resetConfigUrl(); + MinegasmConfig.serverUrl = ConfigHolder.getClientInstance().serverUrl.get(); + wsHost.setValue(MinegasmConfig.serverUrl); + } )); - } + + connectResponse = new PlainTextLabel(this.width / 2 - 155, this.height / 6 + 50, 310, 15, ("" + TextFormatting.GREEN)); - private OptionsRowList createOptions() { - OptionsRowList optionsRowList = new OptionsRowList( - Objects.requireNonNull(this.minecraft), this.width, this.height, - OPTIONS_LIST_TOP_HEIGHT, - this.height - OPTIONS_LIST_BOTTOM_OFFSET, - OPTIONS_LIST_ITEM_HEIGHT + this.addButton(connectResponse); + + Button reconnectButton = new ExtendedButton( + this.width / 2 + 5, this.height / 6 + 25, 150, 20, + "Reconnect", button -> { + button.active = false; + connectResponse.setValue("Connecting"); + new Thread(() -> { + if (ToyController.connectDevice()) { + ClientEventHandler.afterConnect(); + button.active = true; + connectResponse.setValue(String.format("Connected to " + TextFormatting.GREEN + "%s" + TextFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())); + } else { + button.active = true; + connectResponse.setValue(String.format(TextFormatting.YELLOW + "Minegasm " + TextFormatting.RESET + "failed to start: %s", ToyController.getLastErrorMessage())); + } + + }).start(); + } ); + this.addButton(reconnectButton); + + reconnectButton.active = pauseMenu; + + this.addButton(new ExtendedButton(this.width / 2 - 155, this.height / 6 + 25 * 3, 150, 20, + ("Vibration: " + (MinegasmConfig.vibrate ? "True" : "False")), (button) -> { + MinegasmConfig.vibrate = !MinegasmConfig.vibrate; + button.setMessage(("Vibration: " + (MinegasmConfig.vibrate ? "True" : "False"))); + })); - String VIBRATE = "gui.minegasm.config.vibrate"; - AbstractOption vibrateOption = new BooleanOption( - VIBRATE, - (gameSettings) -> vibrate, - (gameSettings, newValue) -> vibrate = newValue - ); + this.addButton(new ExtendedButton(this.width / 2 + 5, this.height / 6 + 25 * 3, 150, 20, + ("Stealth: " + (MinegasmConfig.stealth ? "True" : "False")), (button) -> { + MinegasmConfig.stealth = !MinegasmConfig.stealth; + button.setMessage(("Stealth: " + (MinegasmConfig.stealth ? "True" : "False"))); + })); - String MODE = "gui.minegasm.config.mode"; - AbstractOption modeOption = new IteratableOption( - MODE, - (gameSettings, newValue) -> mode = (mode + newValue) % ClientConfig.GameplayMode.values().length, - (gameSettings, option) -> MODE + ": " + ClientConfig.GameplayMode.values()[mode].getTranslateKey()); - - // Intensity - String ATTACK_INTENSITY = "gui.minegasm.config.intensity.attack"; - AbstractOption attackIntensityOption = new SliderPercentageOption( - ATTACK_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) attackIntensity, - (gameSettings, newValue) -> { - attackIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(ATTACK_INTENSITY, gameSettings, option) - ); - String HURT_INTENSITY = "gui.minegasm.config.intensity.hurt"; - AbstractOption hurtIntensityOption = new SliderPercentageOption( - HURT_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) hurtIntensity, - (gameSettings, newValue) -> { - hurtIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(HURT_INTENSITY, gameSettings, option) - ); + this.addButton(new ExtendedButton(this.width / 2 - 155, this.height / 6 + 25 * 4, 150, 20, + ("Mode: " + gameplayModeToString(MinegasmConfig.mode)), (button) -> { + MinegasmConfig.mode = MinegasmConfig.mode.next(); + button.setMessage(("Mode: " + gameplayModeToString(MinegasmConfig.mode))); + } + )); - String MINE_INTENSITY = "gui.minegasm.config.intensity.mine"; - AbstractOption mineIntensityOption = new SliderPercentageOption( - MINE_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) mineIntensity, - (gameSettings, newValue) -> { - mineIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(MINE_INTENSITY, gameSettings, option) - ); + this.addButton(new ExtendedButton( + this.width / 2 + 5, this.height / 6 + 25 * 4, 150, 20, + ("Edit Custom Settings"), button -> minecraft.setScreen(new CustomModeConfigScreen(this, pauseMenu)))); - String XP_CHANGE_INTENSITY = "gui.minegasm.config.intensity.xp"; - AbstractOption xpChangeIntensityOption = new SliderPercentageOption( - XP_CHANGE_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) xpChangeIntensity, - (gameSettings, newValue) -> { - xpChangeIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(XP_CHANGE_INTENSITY, gameSettings, option) - ); + this.addButton(new ExtendedButton(this.width / 2 - 100, this.height / 6 + 25 * 5, 200, 20, + ("Tick Frequency: " + tickFrequencyToString(MinegasmConfig.tickFrequency)), (button) -> { + tickValue = tickValue.next(); + MinegasmConfig.tickFrequency = tickValue.getInt(); + MinegasmConfig.ticksPerSecond = Math.max(1, Math.toIntExact(20 / MinegasmConfig.tickFrequency)); + button.setMessage(("Tick Frequency: " + tickFrequencyToString(MinegasmConfig.tickFrequency))); + } + )); - String HARVEST_INTENSITY = "gui.minegasm.config.intensity.harvest"; - AbstractOption harvestIntensityOption = new SliderPercentageOption( - HARVEST_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) harvestIntensity, - (gameSettings, newValue) -> { - harvestIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(HARVEST_INTENSITY, gameSettings, option) - ); + this.addButton(new ExtendedButton( + this.width / 2 - 100, this.height - 27, 200, 20, + ("Done"), button -> this.onClose())); + } + + private String gameplayModeToString(ClientConfig.GameplayMode mode){ + switch (mode) { + case NORMAL: return "Normal"; + case MASOCHIST: return "Masochist"; + case HEDONIST: return "Hedonist"; + case ACCUMULATION: return "Accumulation"; + case CUSTOM: return "Custom"; + default: return ""; + } + } - String VITALITY_INTENSITY = "gui.minegasm.config.intensity.vitality"; - AbstractOption vitalityIntensityOption = new SliderPercentageOption( - VITALITY_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) vitalityIntensity, - (gameSettings, newValue) -> { - vitalityIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(VITALITY_INTENSITY, gameSettings, option) - ); + private String tickFrequencyToString(Integer frequency){ + switch (frequency) { + case 1: return "Every Tick"; + case 2: return "Every Other Tick"; + case 5: return "Every 5 Ticks"; + case 10: return "Every 10 Ticks"; + case 20: return "Every Second"; + default: return "Every " + Float.toString(frequency / 20f)+ " Seconds"; + } + } + + @Override + public void tick() { + super.tick(); - optionsRowList.addSmall(vibrateOption, modeOption); - optionsRowList.addSmall(attackIntensityOption, hurtIntensityOption); - optionsRowList.addSmall(mineIntensityOption, xpChangeIntensityOption); - optionsRowList.addSmall(harvestIntensityOption, vitalityIntensityOption); + // Add ticking logic for TextFieldWidget in editBox + if (this.wsHost != null) + this.wsHost.tick(); + } - return optionsRowList; + @Override + public void onClose() { + connectResponse.setValue(""); + this.minecraft.setScreen(this.previous); + MinegasmConfig.save(); } - private String getPercentValueComponent(String translationKey, GameSettings gameSettings, SliderPercentageOption option) { - return translationKey + ": " + (option.toPct(option.get(gameSettings)) == 0.0D ? "Off" : (int) option.get(gameSettings) + "%"); + @Override + public void render(int i, int j, float f) { + if (pauseMenu) + this.renderBackground(); + else + this.renderDirtBackground(0); + drawCenteredString(this.font, this.title.getString(), this.width / 2, 15, 0xFFFFFF); + super.render(i, j, f); + } + + class PlainTextLabel extends Widget { + + private StringTextComponent text = new StringTextComponent(""); + private int x; + private int y; + + public PlainTextLabel(int x, int y, int width, int height, String text) { + super(x, y, width, height, text); + this.x = x; + this.y = y; + } + + public void setValue(String value) + { + text = new StringTextComponent(value); + } + + @Override + public void render(int i, int j, float f) { + if (text == null || text.getString().isEmpty()) + return; + + drawCenteredString(Minecraft.getInstance().font, text.getString(), Minecraft.getInstance().screen.width / 2, this.y + this.height / 4, 0xFFFFFF); + } + } + +} + +class CustomModeConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + + public CustomModeConfigScreen(Screen previous) { + super(new StringTextComponent("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = false; + } + + public CustomModeConfigScreen(Screen previous, boolean pause) { + super(new StringTextComponent("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = pause; } @Override - public void render(int mouseX, int mouseY, float partialTicks) { - this.renderBackground(); - this.children.remove(this.optionsRowList); - this.optionsRowList = createOptions(); - this.children.add(this.optionsRowList); - this.optionsRowList.render(mouseX, mouseY, partialTicks); + protected void init() { + try{ + this.addButton(new ExtendedButton( + this.width / 2 + 5, this.height - 27, 150, 20, + ("Done"), button -> this.onClose())); - drawCenteredString(this.font, this.title.getString(), - this.width / 2, TITLE_HEIGHT, 0xFFFFFF); + IntensitiySliderBar.sliders.clear(); - super.render(mouseX, mouseY, partialTicks); + // Attack + this.addButton(new IntensitiySliderBar(this, "Attack: ", MinegasmConfig.class.getField("attackIntensity"))); + + // Hurt + this.addButton(new IntensitiySliderBar(this, "Hurt: ", MinegasmConfig.class.getField("hurtIntensity"))); + + // Mine + this.addButton(new IntensitiySliderBar(this, "Mine: ", MinegasmConfig.class.getField("mineIntensity"))); + + // Place + this.addButton(new IntensitiySliderBar(this, "Place: ", MinegasmConfig.class.getField("placeIntensity"))); + + // XP Change + this.addButton(new IntensitiySliderBar(this, "XP Change: ", MinegasmConfig.class.getField("xpChangeIntensity"))); + + // Fishing + this.addButton(new IntensitiySliderBar(this, "Fishing: ", MinegasmConfig.class.getField("fishingIntensity"))); + + // Harvest + this.addButton(new IntensitiySliderBar(this, "Harvest: ", MinegasmConfig.class.getField("harvestIntensity"))); + + // Vitality + this.addButton(new IntensitiySliderBar(this, "Vitality: ", MinegasmConfig.class.getField("vitalityIntensity"))); + + // Advancement + this.addButton(new IntensitiySliderBar(this, "Advancement: ", MinegasmConfig.class.getField("advancementIntensity"))); + + this.addButton(new ExtendedButton( + this.width / 2 - 155, this.height - 27, 150, 20, + ("Reset Values"), button -> { + ConfigHolder.getClientInstance().resetConfigCustom(); + IntensitiySliderBar.refreshAllValues(); + } + )); + + + } catch (Throwable e) { + LOGGER.throwing(e); + } } @Override public void onClose() { - LOGGER.debug("saving..."); - clientConfig.vibrate.set(vibrate); - clientConfig.mode.set(ClientConfig.GameplayMode.values()[mode]); - clientConfig.attackIntensity.set(attackIntensity); - clientConfig.hurtIntensity.set(hurtIntensity); - clientConfig.mineIntensity.set(mineIntensity); - clientConfig.xpChangeIntensity.set(xpChangeIntensity); - clientConfig.harvestIntensity.set(harvestIntensity); - clientConfig.vitalityIntensity.set(vitalityIntensity); - ConfigHolder.CLIENT_SPEC.save(); - ConfigHelper.bakeClient(); - Objects.requireNonNull(this.minecraft).setScreen(this.lastScreen instanceof IngameMenuScreen ? null : this.lastScreen); + IntensitiySliderBar.sliders.clear(); + this.minecraft.setScreen(this.previous); + } + + @Override + public void render(int i, int j, float f) { + if (pauseMenu) + this.renderBackground(); + else + this.renderDirtBackground(0); + drawCenteredString(this.font, this.title.getString(), this.width / 2, 15, 0xFFFFFF); + super.render(i, j, f); + } +} + +class IntensitiySliderBar extends ForgeSlider +{ + private static final Logger LOGGER = LogManager.getLogger(); + public static ArrayList sliders = new ArrayList(); + private Field fieldReference; + + IntensitiySliderBar(CustomModeConfigScreen parent, String prefix, Field field) throws Exception + { + super( parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155), // x pos + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2), // y pos + 150, 20, // Width, height + prefix, // Prefix + "", // Suffix + 0, 100, field.getInt(null), 1, 1, true); // Min, Max, Default value, stepsize, percision, drawstring + fieldReference = field; + sliders.add(this); + } + + @Override + public void applyValue() + { + try { + fieldReference.set(null, this.getValueInt()); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public static void refreshAllValues() + { + for (IntensitiySliderBar slider : sliders) + { + slider.refreshValue(); + } + } + + private void refreshValue() + { + try { + this.setValue(fieldReference.getInt(null)); + } catch (Throwable e) { + LOGGER.throwing(e); + } } } \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java index 99e0757..79b2dd9 100644 --- a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java @@ -1,6 +1,7 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; @@ -8,7 +9,7 @@ import org.apache.logging.log4j.Logger; -@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) public class MinegasmConfig { private static final Logger LOGGER = LogManager.getLogger(); @@ -16,13 +17,20 @@ public class MinegasmConfig { public static String serverUrl; public static boolean vibrate; - public static Enum mode; + public static ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public static boolean stealth; + public static int tickFrequency; + public static int ticksPerSecond; + public static int attackIntensity; public static int hurtIntensity; public static int mineIntensity; + public static int placeIntensity; public static int xpChangeIntensity; + public static int fishingIntensity; public static int harvestIntensity; public static int vitalityIntensity; + public static int advancementIntensity; // Server // -- none at the moment @@ -39,4 +47,49 @@ public static void onModConfigEvent(final ModConfig.ModConfigEvent event) { LOGGER.debug("Baked server config"); } } + + public static void save() + { + ConfigHelper.saveClient(); + } + } + +class MinegasmConfigBuffer +{ + public String serverUrl; + + public boolean vibrate; + public ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public boolean stealth; + public int tickFrequency; + + public int attackIntensity; + public int hurtIntensity; + public int mineIntensity; + public int placeIntensity; + public int xpChangeIntensity; + public int fishingIntensity; + public int harvestIntensity; + public int vitalityIntensity; + public int advancementIntensity; + + MinegasmConfigBuffer() + { + this.serverUrl = MinegasmConfig.serverUrl; + this.vibrate = MinegasmConfig.vibrate; + this.mode = MinegasmConfig.mode; + this.stealth = MinegasmConfig.stealth; + this.tickFrequency = MinegasmConfig.tickFrequency; + + this.attackIntensity = MinegasmConfig.attackIntensity; + this.hurtIntensity = MinegasmConfig.hurtIntensity; + this.mineIntensity = MinegasmConfig.mineIntensity; + this.placeIntensity = MinegasmConfig.placeIntensity; + this.xpChangeIntensity = MinegasmConfig.xpChangeIntensity; + this.fishingIntensity = MinegasmConfig.fishingIntensity; + this.harvestIntensity = MinegasmConfig.harvestIntensity; + this.vitalityIntensity = MinegasmConfig.vitalityIntensity; + this.advancementIntensity = MinegasmConfig.advancementIntensity; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java new file mode 100644 index 0000000..2efdbf8 --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java @@ -0,0 +1,89 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.ResourceLocation; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Adapted from https://github.com/Creators-of-Create/Create/ +public class PauseMenuButton extends Button +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static ResourceLocation LOGO = new ResourceLocation(Minegasm.MOD_ID, "textures/logo.png"); + + int xPos; + int yPos; + + public PauseMenuButton(int x, int y) { + super(x, y, 20, 20, (""), PauseMenuButton::clicked); + xPos = x; + yPos = y; + } + + @Override + public void renderBg(Minecraft mc, int mouseX, int mouseY) { +// mstack.translate(xPos + width / 2 - (64 * 0.25f) / 2, yPos + height / 2 - (64 * 0.25f) / 2, 0); +// mstack.scale(0.25f, 0.25f, 1); +// blit(xPos, yPos, 0, 0, 20, 20); + super.renderBg(mc, mouseX, mouseY); + Minecraft.getInstance().getTextureManager().bind(LOGO); + blit(xPos + 2, yPos + 2, 0, 0, 0, 16, 16, 16, 16); + } + + public static void clicked(Button button) + { + Minecraft.getInstance().setScreen(new ConfigScreen(Minecraft.getInstance().screen, true)); + } + + public static class SingleMenuRow { + public final String left, right; + public SingleMenuRow(String left, String right) { + this.left = I18n.get(left); + this.right = I18n.get(right); + } + public SingleMenuRow(String center) { + this(center, center); + } + } + + public static class MenuRows { + public static final MenuRows MAIN_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.singleplayer"), + new SingleMenuRow("menu.multiplayer"), + new SingleMenuRow("fml.menu.mods", "menu.online"), + new SingleMenuRow("narrator.button.language", "narrator.button.accessibility") + )); + + public static final MenuRows INGAME_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.returnToGame"), + new SingleMenuRow("gui.advancements", "gui.stats"), + new SingleMenuRow("menu.sendFeedback", "menu.reportBugs"), + new SingleMenuRow("menu.options", "menu.shareToLan"), + new SingleMenuRow("menu.returnToMenu") + )); + + protected final List leftButtons, rightButtons; + + public MenuRows(List variants) { + leftButtons = variants.stream().map(r -> r.left).collect(Collectors.toList()); + rightButtons = variants.stream().map(r -> r.right).collect(Collectors.toList()); + } + } + +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButtonScreen.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButtonScreen.java new file mode 100644 index 0000000..cc1da2e --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButtonScreen.java @@ -0,0 +1,47 @@ +package com.therainbowville.minegasm.config; + + +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.gui.screen.IngameMenuScreen; + +import org.apache.commons.lang3.mutable.MutableObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.therainbowville.minegasm.common.Minegasm; + +@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class PauseMenuButtonScreen { + private static final Logger LOGGER = LogManager.getLogger(); + + @SubscribeEvent + public static void onGuiInit(GuiScreenEvent.InitGuiEvent event) { + if(event.getGui() instanceof IngameMenuScreen) { // Make sure GUI is Escape menu + PauseMenuButton.MenuRows menu = PauseMenuButton.MenuRows.INGAME_MENU; + int rowIdx = 3; + int offsetX = 4; + boolean onLeft = offsetX < 0; + String target = (onLeft ? menu.leftButtons : menu.rightButtons).get(rowIdx - 1); + LOGGER.info(target); + + int offsetX_ = offsetX; + MutableObject toAdd = new MutableObject<>(null); + event.getWidgetList() + .stream() + .filter(w -> w instanceof Widget) + .map(w -> (Widget) w) + .filter(w -> w.getMessage() + .equals(target)) + .findFirst() + .ifPresent(w -> toAdd + .setValue(new PauseMenuButton(w.x + offsetX_ + (onLeft ? -20 : w.getWidth()), w.y))); + if (toAdd.getValue() != null) + event.addWidget(toAdd.getValue()); + } + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java new file mode 100644 index 0000000..35bc090 --- /dev/null +++ b/forge/fg-6.0/1.15.2/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui.widget; + +import net.minecraft.client.gui.widget.AbstractSlider; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; + +import java.text.DecimalFormat; + +/** + * Slider widget implementation which allows inputting values in a certain range with optional step size. + */ +public class ForgeSlider extends AbstractSlider +{ + protected String prefix; + protected String suffix; + + protected double minValue; + protected double maxValue; + + /** Allows input of discontinuous values with a certain step */ + protected double stepSize; + + protected boolean drawString; + + private final DecimalFormat format; + + /** + * @param x x position of upper left corner + * @param y y position of upper left corner + * @param width Width of the widget + * @param height Height of the widget + * @param prefix {@link String} displayed before the value string + * @param suffix {@link String} displayed after the value string + * @param minValue Minimum (left) value of slider + * @param maxValue Maximum (right) value of slider + * @param currentValue Starting value when widget is first displayed + * @param stepSize Size of step used. Precision will automatically be calculated based on this value if this value is not 0. + * @param precision Only used when {@code stepSize} is 0. Limited to a maximum of 4 (inclusive). + * @param drawString Should text be displayed on the widget + */ + public ForgeSlider(int x, int y, int width, int height, String prefix, String suffix, double minValue, double maxValue, double currentValue, double stepSize, int precision, boolean drawString) + { + super(x, y, width, height, 0D); + this.prefix = prefix; + this.suffix = suffix; + this.minValue = minValue; + this.maxValue = maxValue; + this.stepSize = Math.abs(stepSize); + this.value = this.snapToNearest((currentValue - minValue) / (maxValue - minValue)); + this.drawString = drawString; + + if (stepSize == 0D) + { + precision = Math.min(precision, 4); + + StringBuilder builder = new StringBuilder("0"); + + if (precision > 0) + builder.append('.'); + + while (precision-- > 0) + builder.append('0'); + + this.format = new DecimalFormat(builder.toString()); + } + else if (MathHelper.equal(this.stepSize, Math.floor(this.stepSize))) + { + this.format = new DecimalFormat("0"); + } + else + { + this.format = new DecimalFormat(Double.toString(this.stepSize).replaceAll("\\d", "0")); + } + + this.updateMessage(); + } + + /** + * Overload with {@code stepSize} set to 1, useful for sliders with whole number values. + */ + public ForgeSlider(int x, int y, int width, int height, String prefix, String suffix, double minValue, double maxValue, double currentValue, boolean drawString) + { + this(x, y, width, height, prefix, suffix, minValue, maxValue, currentValue, 1D, 0, drawString); + } + + /** + * @return Current slider value as a double + */ + public double getValue() + { + return this.value * (maxValue - minValue) + minValue; + } + + /** + * @return Current slider value as an long + */ + public long getValueLong() + { + return Math.round(this.getValue()); + } + + /** + * @return Current slider value as an int + */ + public int getValueInt() + { + return (int) this.getValueLong(); + } + + /** + * @param value The new slider value + */ + public void setValue(double value) + { + this.value = this.snapToNearest((value - this.minValue) / (this.maxValue - this.minValue)); + this.updateMessage(); + } + + public String getValueString() + { + return this.format.format(this.getValue()); + } + + @Override + public void onClick(double mouseX, double mouseY) + { + this.setValueFromMouse(mouseX); + } + + @Override + protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) + { + super.onDrag(mouseX, mouseY, dragX, dragY); + this.setValueFromMouse(mouseX); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) + { + boolean flag = keyCode == GLFW.GLFW_KEY_LEFT; + if (flag || keyCode == GLFW.GLFW_KEY_RIGHT) + { + if (this.minValue > this.maxValue) + flag = !flag; + float f = flag ? -1F : 1F; + if (stepSize <= 0D) + this.setSliderValue(this.value + (f / (this.width - 8))); + else + this.setValue(this.getValue() + f * this.stepSize); + } + + return false; + } + + private void setValueFromMouse(double mouseX) + { + this.setSliderValue((mouseX - (this.x + 4)) / (this.width - 8)); + } + + /** + * @param value Percentage of slider range + */ + private void setSliderValue(double value) + { + double oldValue = this.value; + this.value = this.snapToNearest(value); + if (!MathHelper.equal(oldValue, this.value)) + this.applyValue(); + + this.updateMessage(); + } + + /** + * Snaps the value, so that the displayed value is the nearest multiple of {@code stepSize}. + * If {@code stepSize} is 0, no snapping occurs. + */ + private double snapToNearest(double value) + { + if(stepSize <= 0D) + return MathHelper.clamp(value, 0D, 1D); + + value = MathHelper.lerp(MathHelper.clamp(value, 0D, 1D), this.minValue, this.maxValue); + + value = (stepSize * Math.round(value / stepSize)); + + if (this.minValue > this.maxValue) + { + value = MathHelper.clamp(value, this.maxValue, this.minValue); + } + else + { + value = MathHelper.clamp(value, this.minValue, this.maxValue); + } + + return (value-this.minValue)/(this.maxValue-this.minValue) * (1D-0D) + 0D; +// return MathHelper.map(value, this.minValue, this.maxValue, 0D, 1D); + } + + @Override + protected void updateMessage() + { + if (this.drawString) + { + this.setMessage(prefix + this.getValueString() + suffix); + } + else + { + this.setMessage(""); + } + } + + @Override + protected void applyValue() {} +} \ No newline at end of file diff --git a/forge/fg-6.0/1.15.2/src/main/resources/assets/minegasm/textures/logo.png b/forge/fg-6.0/1.15.2/src/main/resources/assets/minegasm/textures/logo.png new file mode 100644 index 0000000..63eaa64 Binary files /dev/null and b/forge/fg-6.0/1.15.2/src/main/resources/assets/minegasm/textures/logo.png differ diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java index 75c15cf..6c0b4b9 100644 --- a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java @@ -1,21 +1,18 @@ package com.therainbowville.minegasm.client; -import com.mojang.authlib.GameProfile; import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.common.*; import com.therainbowville.minegasm.config.ClientConfig; import com.therainbowville.minegasm.config.MinegasmConfig; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; + import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; -import net.minecraft.world.IWorld; + +import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.ToolType; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.EntityLeaveWorldEvent; @@ -26,149 +23,117 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; + import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.*; +import java.util.stream.Collectors; +import java.lang.Thread; -@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) +@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ClientEventHandler { private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); - private static String playerName = null; - private static UUID playerID = null; - private static final int TICKS_PER_SECOND = 20; + private static int tickCounter = -1; private static int clientTickCounter = -1; - private static final double[] state = new double[1200]; private static boolean paused = false; - - private static void clearState() { - playerName = null; - playerID = null; - tickCounter = -1; - clientTickCounter = -1; - Arrays.fill(state, 0); - paused = false; + private static UUID playerId = null; + + private static Map vibrationStates = new HashMap(); + + static { + vibrationStates.put("advancement", new VibrationStateAdvancement()); + vibrationStates.put("attack", new VibrationStateAttack()); + vibrationStates.put("fish", new VibrationStateFish()); + vibrationStates.put("hurt", new VibrationStateHurt()); + vibrationStates.put("mine", new VibrationStateMine()); + vibrationStates.put("place", new VibrationStatePlace()); + vibrationStates.put("harvest", new VibrationStateHarvest((VibrationStateMine)vibrationStates.get("mine"))); + vibrationStates.put("vitality", new VibrationStateVitality()); + vibrationStates.put("xpChange", new VibrationStateXpChange()); + vibrationStates.put("generic", new VibrationStateClient()); } - private static int getStateCounter() { - return tickCounter / 20; + public static void afterConnect() + { + //setState(getStateCounter(), 5); + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); } - - private static void setState(int start, int duration, int intensity, boolean decay) { - if (duration <= 0) { - return; + + private static double getIntensity() + { + double intensity = 0; + for (Map.Entry state : vibrationStates.entrySet()) + { + intensity = Math.max(intensity, state.getValue().getIntensity()); +// LOGGER.info(state.getKey() + ": " + state.getValue().getIntensity()); + } - - if (decay) { - int safeDuration = Math.max(0, duration - 2); - for (int i = 0; i < safeDuration; i++) { - setState(start+i, intensity); - } - setState(start+safeDuration, intensity/2); - setState(start+safeDuration+1, intensity/4); - } else { - for (int i = 0; i < duration; i++) { - setState(start+i, intensity); - } + return intensity / 100; + } + + private static void tickAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.onTick(); } } - - private static void setState(int counter, int intensity) { - boolean accumulate = false; //XXX reserved for future use - setState(counter, intensity, accumulate); + + private static void resetAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.resetState(); + } } - private static void setState(int counter, int intensity, boolean accumulate) { - int safeCounter = counter % state.length; - if (accumulate) { - state[safeCounter] = Math.min(1.0, state[safeCounter] + (intensity / 100.0)); - } else { - state[safeCounter] = Math.min(1.0, Math.max(state[safeCounter], (intensity / 100.0))); + private static boolean isPlayer(Entity entity){ + try { + if (entity instanceof PlayerEntity && !(entity instanceof FakePlayer)) { + PlayerEntity player = (PlayerEntity) entity;; + UUID uuid = player.getGameProfile().getId(); + return uuid.equals(playerId); } + } catch (Throwable e) { + LOGGER.throwing(e); + } + return false; } - private static int getIntensity(String type) { - Map normal = new HashMap<>(); - normal.put("attack", 60); - normal.put("hurt", 0); - normal.put("mine", 80); - normal.put("xpChange", 100); - normal.put("harvest", 0); - normal.put("vitality", 0); - - Map masochist = new HashMap<>(); - masochist.put("attack", 0); - masochist.put("hurt", 100); - masochist.put("mine", 0); - masochist.put("xpChange", 0); - masochist.put("harvest", 0); - masochist.put("vitality", 10); - - Map hedonist = new HashMap<>(); - hedonist.put("attack", 60); - hedonist.put("hurt", 10); - hedonist.put("mine", 80); - hedonist.put("xpChange", 100); - hedonist.put("harvest", 20); - hedonist.put("vitality", 10); - - Map custom = new HashMap<>(); - custom.put("attack", MinegasmConfig.attackIntensity); - custom.put("hurt", MinegasmConfig.hurtIntensity); - custom.put("mine", MinegasmConfig.mineIntensity); - custom.put("xpChange", MinegasmConfig.xpChangeIntensity); - custom.put("harvest", MinegasmConfig.harvestIntensity); - custom.put("vitality", MinegasmConfig.vitalityIntensity); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - return masochist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.HEDONIST)) { - return hedonist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.CUSTOM)) { - return custom.get(type); - } else { - return normal.get(type); - } + private static void clearState() { + tickCounter = -1; + clientTickCounter = -1; + paused = false; + resetAll(); } @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { - if (event.phase == TickEvent.Phase.END) { + try { + if (event.phase == TickEvent.Phase.END && isPlayer(event.player)) { PlayerEntity player = event.player; - GameProfile profile = player.getGameProfile(); - - float playerHealth = player.getHealth(); - float playerFoodLevel = player.getFoodData().getFoodLevel(); - - tickCounter = (tickCounter + 1) % (20 * (60 * TICKS_PER_SECOND)); // 20 min day cycle - - if (tickCounter % TICKS_PER_SECOND == 0) { // every 1 sec - if (profile.getId().equals(playerID)) { - int stateCounter = getStateCounter(); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - if (playerHealth > 0 && playerHealth <= 1) { - setState(stateCounter, getIntensity("vitality")); - } - } else if (playerHealth >= 20 && playerFoodLevel >= 20) { - setState(stateCounter, getIntensity("vitality")); - } - - double newVibrationLevel = state[stateCounter]; - state[stateCounter] = 0; - - LOGGER.trace("Tick " + stateCounter + ": " + newVibrationLevel); - - if (ToyController.currentVibrationLevel != newVibrationLevel) { - ToyController.setVibrationLevel(newVibrationLevel); - } - } + + tickCounter = (tickCounter + 1) % 100; + + + if (tickCounter % MinegasmConfig.tickFrequency == 0) // TODO: Add ticks per second config option (Default: Every tick) + { + tickAll(); + + ((VibrationStateVitality)vibrationStates.get("vitality")).onTick(player); + ((VibrationStateFish)vibrationStates.get("fish")).onTick(player); + + double newVibrationLevel = getIntensity(); + + if (ToyController.currentVibrationLevel != newVibrationLevel) + ToyController.setVibrationLevel(newVibrationLevel); } - if (tickCounter % (5 * TICKS_PER_SECOND) == 0) { // 5 secs - LOGGER.debug("Health: " + playerHealth); - LOGGER.debug("Food: " + playerFoodLevel); - } + } + } catch (Throwable e) { + LOGGER.throwing(e); } } @@ -197,14 +162,9 @@ public static void onClientTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public static void onAttack(AttackEntityEvent event) { - Entity entity = event.getEntityLiving(); - if (entity instanceof PlayerEntity) { - PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - setState(getStateCounter(), 3, getIntensity("attack"), true); - } + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateAttack)vibrationStates.get("attack")).onAttack(); } } @@ -217,84 +177,36 @@ public static void onCriticalHit(CriticalHitEvent event) @SubscribeEvent public static void onHurt(LivingHurtEvent event) { - Entity entity = event.getEntityLiving(); - if (entity instanceof PlayerEntity) { - PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - setState(getStateCounter(), 3, getIntensity("hurt"), true); - } + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateHurt)vibrationStates.get("hurt")).onHurt(); } } @SubscribeEvent - public static void onDeath(LivingDeathEvent event) + public static void onBreak(BlockEvent.BreakEvent event) { - Entity entity = event.getEntityLiving(); - if (entity instanceof PlayerEntity) { - PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - ToyController.setVibrationLevel(0); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateMine)vibrationStates.get("mine")).onBreak(event.getState()); } } - + + // Triggers when player starts to break block @SubscribeEvent public static void onHarvest(PlayerEvent.HarvestCheck event) { - PlayerEntity player = event.getPlayer(); - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - BlockState blockState = event.getTargetBlock(); - Block block = blockState.getBlock(); - - // ToolType. AXE, HOE, PICKAXE, SHOVEL - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - LOGGER.debug("Harvest: tool: " + - block.getHarvestTool(blockState) + - " can harvest? " + event.canHarvest() + " hardness: " + blockHardness); - - int intensity = Math.toIntExact(Math.round((getIntensity("harvest") / 100.0 * (blockHardness / 50.0)) * 100)); - - if (event.canHarvest()) { - setState(getStateCounter(), 1, intensity, false); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateHarvest)vibrationStates.get("harvest")).onHarvest(); } } - + @SubscribeEvent - public static void onBreak(BlockEvent.BreakEvent event) - { - PlayerEntity player = event.getPlayer(); - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - BlockState blockState = event.getState(); - Block block = blockState.getBlock(); - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - - LOGGER.info("Breaking: " + block.toString()); - - ToolType blockHarvestTool = block.getHarvestTool(blockState); - ItemStack mainhandItem = event.getPlayer().getMainHandItem(); - Set mainhandToolTypes = mainhandItem.getItem().getToolTypes(mainhandItem); - - boolean usingPickaxe = mainhandToolTypes.contains(ToolType.PICKAXE); - boolean usingAppropriateTool = mainhandToolTypes.contains(blockHarvestTool); - LOGGER.debug("mainhand: " + mainhandItem + " [" + mainhandToolTypes + "]"); - LOGGER.debug("using pickaxe: " + usingPickaxe + ", using appropriate tool: " + usingAppropriateTool); - - if (usingPickaxe && usingAppropriateTool) { - int duration = Math.max(1, Math.min(5, Math.toIntExact(Math.round(Math.ceil(Math.log(blockHardness + 0.5)))))); - int intensity = Math.toIntExact(Math.round((getIntensity("mine") / 100.0 * (blockHardness / 50.0)) * 100)); - setState(getStateCounter(), duration, intensity, true); - } - - LOGGER.info("XP to drop: " + event.getExpToDrop()); + public static void onPlace(BlockEvent.EntityPlaceEvent event){ + if (isPlayer(event.getEntity())) + { + ((VibrationStatePlace)vibrationStates.get("place")).onPlace(); } } @@ -313,71 +225,83 @@ public static void onXpPickup(PlayerXpEvent.PickupXp event) @SubscribeEvent public static void onXpChange(PlayerXpEvent.XpChange event) { - PlayerEntity player = event.getPlayer(); - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - int xpChange = event.getAmount(); - long duration = Math.round(Math.ceil(Math.log(xpChange + 0.5))); - - LOGGER.info("XP CHANGE: " + xpChange); - LOGGER.debug("duration: " + duration); - - setState(getStateCounter(), Math.toIntExact(duration), getIntensity("xpChange"), true); + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateXpChange)vibrationStates.get("xpChange")).onXpChange(((PlayerEntity)event.getEntityLiving()).totalExperience, event.getAmount()); + } + } + + + @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event) + { + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateAdvancement)vibrationStates.get("advancement")).onAdvancement(event); } } @SubscribeEvent public static void onRespawn(PlayerEvent.PlayerRespawnEvent event) { - clearState(); - ToyController.setVibrationLevel(0); - populatePlayerInfo(); - } + Entity entity = event.getEntity(); + if( !entity.level.isClientSide() ) { + return; + } - private static void populatePlayerInfo() { - GameProfile profile = Minecraft.getInstance().getUser().getGameProfile(); - playerName = profile.getName(); - playerID = profile.getId(); - System.out.println("Current player: " + playerName + " " + playerID.toString()); - } + if (entity instanceof PlayerEntity) { + LOGGER.info("Client Entered world: " + entity.toString()); - @SubscribeEvent - public static void onWorldLoaded(WorldEvent.Load event) { - IWorld world = event.getWorld(); - System.out.println("World loaded: " + world.toString()); + try { + PlayerEntity player = (PlayerEntity) entity; + UUID uuid = player.getGameProfile().getId(); + + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { + LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + clearState(); + ToyController.setVibrationLevel(0); + playerId = uuid; + } + } catch (Throwable e) { + LOGGER.throwing(e); + } + } - populatePlayerInfo(); } + @SubscribeEvent public static void onWorldEntry(EntityJoinWorldEvent event) { Entity entity = event.getEntity(); - if (entity instanceof ClientPlayerEntity) { - System.out.println("Entered world: " + entity.toString()); + if( !entity.level.isClientSide() ) { + return; + } + + if (ToyController.isConnected) return; - if (playerName != null) { + if (entity instanceof PlayerEntity) { + LOGGER.info("Player respawn world: " + entity.toString()); + + new Thread(()-> { try { PlayerEntity player = (PlayerEntity) entity; - GameProfile profile = player.getGameProfile(); - - if (profile.getId().equals(playerID)) { - System.out.println("Player in: " + playerName + " " + playerID.toString()); + UUID uuid = player.getGameProfile().getId(); + + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { + LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + LOGGER.info("Stealth: " + MinegasmConfig.stealth); if (ToyController.connectDevice()) { - setState(getStateCounter(), 5); - player.displayClientMessage(new StringTextComponent(String.format("Connected to " + TextFormatting.GREEN + "%s" + TextFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); - } else { + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); + if (!MinegasmConfig.stealth){ + player.displayClientMessage(new StringTextComponent(String.format("Connected to " + TextFormatting.GREEN + "%s" + TextFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); + } + } else if (!MinegasmConfig.stealth){ player.displayClientMessage(new StringTextComponent(String.format(TextFormatting.YELLOW + "Minegasm " + TextFormatting.RESET + "failed to start\n%s", ToyController.getLastErrorMessage())), false); } + playerId = uuid; } - } - } - } - - @SubscribeEvent - public static void onWorldExit(EntityLeaveWorldEvent event) { - Entity entity = event.getEntity(); - if ((entity instanceof PlayerEntity) && (playerName != null)) { - clearState(); + } catch (Throwable e) { + LOGGER.throwing(e); + }}).start(); } } } diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ToyController.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ToyController.java index 4d5a865..4577128 100644 --- a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ToyController.java +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/client/ToyController.java @@ -10,10 +10,16 @@ import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.Executors; public class ToyController { private static final Logger LOGGER = LogManager.getLogger(); - private static final ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); + private static ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); private static ButtplugClientDevice device = null; private static boolean shutDownHookAdded = false; public static String lastErrorMessage = ""; @@ -24,9 +30,28 @@ public static boolean connectDevice() { try { device = null; client.disconnect(); + LOGGER.info("URL: " + MinegasmConfig.serverUrl); - client.connect(new URI(MinegasmConfig.serverUrl)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new Callable() { + public Void call() throws Exception { + client.connect(new URI(MinegasmConfig.serverUrl)); + return null; + } + }); + + try + { + future.get(3, TimeUnit.SECONDS); + } catch (TimeoutException e) { + future.cancel(true); + client = new ButtplugClientWSClient("Minegasm"); + throw new TimeoutException("Could not find WebSocket"); + } finally { + executor.shutdownNow(); + } + client.startScanning(); Thread.sleep(5000); @@ -73,7 +98,7 @@ public static boolean connectDevice() { isConnected = true; } catch (Exception e) { lastErrorMessage = e.getMessage(); - e.printStackTrace(); + LOGGER.error(e.getMessage(), e); } return Objects.nonNull(device); diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java new file mode 100644 index 0000000..8e264a0 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java @@ -0,0 +1,132 @@ +package com.therainbowville.minegasm.common; + +import java.util.Map; +import java.util.HashMap; + +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Architecture inspired from https://github.com/Fyustorm/mInetiface +public abstract class AbstractVibrationState +{ + + protected static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); + protected final float streakCountdownAmount; + protected float intensity; + + protected float vibrationCountdown; + protected float vibrationFeedbackCountdown; + + protected AbstractVibrationState(float streakSeconds) + { + streakCountdownAmount = streakSeconds; + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + public void onTick() + { + if (accumulationEnabled()) + { + if (vibrationCountdown > 0) + vibrationCountdown--; + else if (intensity > 0) { + intensity = Math.max(0, intensity - 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + vibrationCountdown = Math.max(0, vibrationCountdown - 1); + } + + vibrationFeedbackCountdown = Math.max(0, vibrationFeedbackCountdown - 1); + } + + public void resetState() + { + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + protected static boolean accumulationEnabled() + { + return MinegasmConfig.mode.equals(ClientConfig.GameplayMode.ACCUMULATION); + } + + public static int getIntensity(String type) { + Map normal = new HashMap<>(); + normal.put("attack", 60); + normal.put("hurt", 0); + normal.put("mine", 80); + normal.put("place", 20); + normal.put("xpChange", 100); + normal.put("harvest", 10); + normal.put("fishing", 50); + normal.put("vitality", 0); + normal.put("advancement", 100); + + Map masochist = new HashMap<>(); + masochist.put("attack", 0); + masochist.put("hurt", 100); + masochist.put("mine", 0); + masochist.put("place", 0); + masochist.put("xpChange", 0); + masochist.put("fishing", 0); + masochist.put("harvest", 0); + masochist.put("vitality", 10); + masochist.put("advancement", 0); + + Map hedonist = new HashMap<>(); + hedonist.put("attack", 60); + hedonist.put("hurt", 10); + hedonist.put("mine", 80); + hedonist.put("place", 20); + hedonist.put("xpChange", 100); + hedonist.put("fishing", 50); + hedonist.put("harvest", 20); + hedonist.put("vitality", 10); + hedonist.put("advancement", 100); + + Map accumulation = new HashMap<>(); + accumulation.put("attack", 1); + accumulation.put("hurt", 1); + accumulation.put("mine", 1); + accumulation.put("place", 1); + accumulation.put("xpChange", 1); + accumulation.put("fishing", 50); + accumulation.put("harvest", 10); + accumulation.put("vitality", 0); + accumulation.put("advancement", 1); + + Map custom = new HashMap<>(); + custom.put("attack", MinegasmConfig.attackIntensity); + custom.put("hurt", MinegasmConfig.hurtIntensity); + custom.put("mine", MinegasmConfig.mineIntensity); + custom.put("place", MinegasmConfig.placeIntensity); + custom.put("xpChange", MinegasmConfig.xpChangeIntensity); + custom.put("fishing", MinegasmConfig.fishingIntensity); + custom.put("harvest", MinegasmConfig.harvestIntensity); + custom.put("vitality", MinegasmConfig.vitalityIntensity); + custom.put("advancement", MinegasmConfig.advancementIntensity); + + + int returnValue = -1; + + switch (MinegasmConfig.mode) + { + case NORMAL: returnValue = normal.get(type); + case MASOCHIST: returnValue = masochist.get(type); + case HEDONIST: returnValue = hedonist.get(type); + case ACCUMULATION: returnValue = accumulation.get(type); + case CUSTOM: returnValue = custom.get(type); + }; + + return returnValue; + } + + public abstract int getIntensity(); +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java new file mode 100644 index 0000000..09d478d --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java @@ -0,0 +1,55 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.advancements.FrameType; +import net.minecraft.advancements.Advancement; +import net.minecraftforge.event.entity.player.AdvancementEvent; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAdvancement extends AbstractVibrationState +{ + public VibrationStateAdvancement() + { + super(0); + } + + public void onAdvancement(AdvancementEvent event) + { + if (getIntensity("advancement") == 0) return; + try { + LOGGER.info("Advancement Event: " + event); + Advancement advancement = event.getAdvancement(); + if (advancement == null) return; + FrameType type = advancement.getDisplay().getFrame(); + int duration = 0; + + switch (type) { + case TASK: + duration = 5; + break; + case GOAL: + duration = 7; + break; + case CHALLENGE: + duration = 10; + break; + }; + + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("advancement") + 20); + else if (vibrationCountdown > 0) + return getIntensity("advancement"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java new file mode 100644 index 0000000..acd0375 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAttack extends AbstractVibrationState +{ + public VibrationStateAttack() + { + super(3); + } + + public void onAttack() + { + if (getIntensity("attack") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * 0; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("attack") + 20); + else if (vibrationCountdown > 0) + return getIntensity("attack"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java new file mode 100644 index 0000000..c952b68 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java @@ -0,0 +1,24 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateClient extends AbstractVibrationState +{ + public VibrationStateClient() + { + super(0); + } + + public void setVibration(int intensity, int durationSeconds) + { + intensity = intensity; + vibrationCountdown = durationSeconds * MinegasmConfig.ticksPerSecond; + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return Math.toIntExact(Math.round(intensity)); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java new file mode 100644 index 0000000..ccff7d1 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.vector.Vector3d; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateFish extends AbstractVibrationState +{ + public VibrationStateFish() + { + super(0); + } + + public void onTick(PlayerEntity player) + { + if (player.fishing != null) + { + Vector3d vector = player.fishing.getDeltaMovement(); + double x = vector.x(); + double y = vector.y(); + double z = vector.z(); + if (y < -0.075 && !player.level.getFluidState(player.fishing.blockPosition()).isEmpty() && x == 0 && z == 0) + { + vibrationCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + LOGGER.info("Fishing!"); + } + } + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return getIntensity("fishing"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java new file mode 100644 index 0000000..a7254ab --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java @@ -0,0 +1,30 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHarvest extends AbstractVibrationState +{ + private VibrationStateMine mineState; + + public VibrationStateHarvest(VibrationStateMine state) + { + super(0); + mineState = state; + } + + public void onHarvest() { + vibrationCountdown = 3; + mineState.onHarvest(); + } + + public int getIntensity() + { + if (vibrationCountdown > 0){ + if (accumulationEnabled()) + return Math.min(100, mineState.getIntensity() + 20); + else + return getIntensity("harvest"); + } + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java new file mode 100644 index 0000000..7219c5e --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java @@ -0,0 +1,36 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHurt extends AbstractVibrationState +{ + public VibrationStateHurt() + { + super(3); + } + + public void onHurt() { + if (getIntensity("hurt") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 10); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("hurt") + 20); + else if (vibrationCountdown > 0) + return getIntensity("hurt"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java new file mode 100644 index 0000000..477f80b --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.block.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateMine extends AbstractVibrationState +{ + public VibrationStateMine() + { + super(5); + } + + public void onBreak(BlockState block) { + if (getIntensity("mine") == 0) return; + + String blockName = block.getBlock().getName().getString(); + if (accumulationEnabled()) + { + if (blockName.contains("Ore")) { + intensity = Math.min(100, intensity + 1); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + intensity = Math.min(100, intensity + .25f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + if (blockName.contains("Ore")) { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public void onHarvest() { + if (accumulationEnabled()){ + vibrationCountdown = Math.max(3, vibrationCountdown); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("mine") + 20); + else if (vibrationCountdown > 0) + return getIntensity("mine"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java new file mode 100644 index 0000000..aee4ebf --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java @@ -0,0 +1,35 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStatePlace extends AbstractVibrationState +{ + public VibrationStatePlace() + { + super(5); + } + + public void onPlace() { + if (getIntensity("place") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + .5f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("place") + 20); + else if (vibrationCountdown > 0) + return getIntensity("place"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java new file mode 100644 index 0000000..20c13d9 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java @@ -0,0 +1,62 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.entity.player.PlayerEntity; + +import com.therainbowville.minegasm.config.MinegasmConfig; +import com.therainbowville.minegasm.config.ClientConfig; + +public class VibrationStateVitality extends AbstractVibrationState +{ + private int intensityCooldown; + private boolean targetMet; + + public VibrationStateVitality() + { + super(1); + intensityCooldown = 0; + targetMet = false; + } + + public void onTick(PlayerEntity player) + { + float playerHealth = player.getHealth(); + float playerFoodLevel = player.getFoodData().getFoodLevel(); + + if ((MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth > 0 && playerHealth <= 1 ) + || (!MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth >= 20 && playerFoodLevel >= 20) ){ + + if (targetMet == false){ + targetMet = true; + vibrationFeedbackCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } else + targetMet = false; + +// if (accumulationEnabled() && targetMet) +// { +// if (intensityCooldown == 0) { +// intensity = Math.min(100, intensity + .1f); +// intensityCooldown = 10 * 20; +// } +// vibrationCountdown = streakCountdownAmount; +// intensityCooldown = Math.max(0, intensityCooldown - 1); +// } else + if (targetMet) { + vibrationCountdown = 1; + } + } + + public int getIntensity() + { + if (getIntensity("vitality") == 0) return 0; + + //if (accumulationEnabled()) + //return Math.toIntExact(Math.round(intensity)); + //else + if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("vitality") + 20); + else if (vibrationCountdown > 0) + return getIntensity("vitality"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java new file mode 100644 index 0000000..34b1633 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateXpChange extends AbstractVibrationState +{ + private int lastLevel; + + public VibrationStateXpChange() + { + super(1); + lastLevel = -1; + } + + // Code adapted from https://github.com/Fyustorm/mInetiface + public void onXpChange(int level, int amount) { + if (amount == 0 || getIntensity("xpChange") == 0) + return; + + if (lastLevel == -1) { + lastLevel = level; + } + + if (lastLevel != level) { + amount *= 2; + } + + lastLevel = level; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + amount / 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + int duration = Math.toIntExact( Math.round( Math.ceil( Math.log(amount + 0.5) ) ) ); + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("xpChange") + 20); + else if (vibrationCountdown > 0) + return getIntensity("xpChange"); + else return 0; + } +} + diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java index d802600..bbd310c 100644 --- a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java @@ -1,86 +1,147 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.Minecraft; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.mclanguageprovider.MinecraftModLanguageProvider; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.common.ForgeConfigSpec.IntValue; import java.util.Objects; public final class ClientConfig { final ForgeConfigSpec.ConfigValue serverUrl; - final ForgeConfigSpec.ConfigValue version; final ForgeConfigSpec.BooleanValue vibrate; final ForgeConfigSpec.EnumValue mode; + final ForgeConfigSpec.BooleanValue stealth; + final ForgeConfigSpec.EnumValue tickFrequency; + final ForgeConfigSpec.IntValue attackIntensity; final ForgeConfigSpec.IntValue hurtIntensity; final ForgeConfigSpec.IntValue mineIntensity; + final ForgeConfigSpec.IntValue placeIntensity; final ForgeConfigSpec.IntValue xpChangeIntensity; + final ForgeConfigSpec.IntValue fishingIntensity; final ForgeConfigSpec.IntValue harvestIntensity; final ForgeConfigSpec.IntValue vitalityIntensity; + final ForgeConfigSpec.IntValue advancementIntensity; + + static final String DEFAULT_SERVER_URL = "ws://localhost:12345/buttplug"; + static final boolean DEFAULT_VIBRATE = true; + static final GameplayMode DEFAULT_MODE = GameplayMode.NORMAL; + static final boolean DEFAULT_STEALTH = false; + + static final int DEFAULT_ATTACK_INTENSITY = 60; + static final int DEFAULT_HURT_INTENSITY = 0; + static final int DEFAULT_MINE_INTENSITY = 80; + static final int DEFAULT_PLACE_INTENSITY = 20; + static final int DEFAULT_XP_CHANGE_INTENSITY = 100; + static final int DEFAULT_FISHING_INTENSITY = 50; + static final int DEFAULT_HARVEST_INTENSITY = 0; + static final int DEFAULT_VITALITY_INTENSITY = 0; + static final int DEFAULT_ADVANCEMENT_INTENSITY = 100; + ClientConfig(final ForgeConfigSpec.Builder builder) { builder.push("buttplug"); serverUrl = builder .translation(Minegasm.MOD_ID + ".config.serverUrl") - .define("serverUrl", "ws://localhost:12345/buttplug"); + .define("serverUrl", DEFAULT_SERVER_URL); builder.pop(); builder.push("minegasm"); - version = builder - .translation(Minegasm.MOD_ID + ".config.version") - .define("version", "0.3"); - vibrate = builder .translation(Minegasm.MOD_ID + ".config.vibrate") - .define("vibrate", true); + .define("vibrate", DEFAULT_VIBRATE); mode = builder .translation(Minegasm.MOD_ID + ".config.mode") - .defineEnum("mode", GameplayMode.NORMAL); + .defineEnum("mode", DEFAULT_MODE); + stealth = builder + .translation(Minegasm.MOD_ID + ".config.stealth") + .define("stealth", DEFAULT_STEALTH); + + tickFrequency = builder + .translation(Minegasm.MOD_ID + ".config.mode") + .defineEnum("tickFrequency", TickFrequencyOptions.EVERY_TICK); builder.push("intensity"); attackIntensity = builder .comment("Vibration intensity when attacking on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.attack") - .defineInRange("attackIntensity", 60, 0, 100); + .defineInRange("attackIntensity", DEFAULT_ATTACK_INTENSITY, 0, 100); hurtIntensity = builder .comment("Vibration intensity when hurting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.hurt") - .defineInRange("hurtIntensity", 0, 0, 100); + .defineInRange("hurtIntensity", DEFAULT_HURT_INTENSITY, 0, 100); mineIntensity = builder .comment("Vibration intensity when mining on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.mine") - .defineInRange("mineIntensity", 80, 0, 100); + .defineInRange("mineIntensity", DEFAULT_MINE_INTENSITY, 0, 100); + + placeIntensity = builder + .comment("Vibration intensity when placing blocks on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.place") + .defineInRange("placeIntensity", DEFAULT_PLACE_INTENSITY, 0, 100); xpChangeIntensity = builder .comment("Vibration intensity when gaining XP on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.xp_change") - .defineInRange("xpChangeIntensity", 100, 0, 100); + .defineInRange("xpChangeIntensity", DEFAULT_XP_CHANGE_INTENSITY, 0, 100); + + fishingIntensity = builder + .comment("Vibration intensity when fishing on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.fishing") + .defineInRange("fishingIntensity", DEFAULT_FISHING_INTENSITY, 0, 100); harvestIntensity = builder .comment("Vibration intensity when harvesting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.harvest") - .defineInRange("harvestIntensity", 0, 0, 100); + .defineInRange("harvestIntensity", DEFAULT_HARVEST_INTENSITY, 0, 100); vitalityIntensity = builder .comment("Vibration intensity on high level of player's vitality on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.vitality") - .defineInRange("vitalityIntensity", 0, 0, 100); + .defineInRange("vitalityIntensity", DEFAULT_VITALITY_INTENSITY, 0, 100); + + advancementIntensity = builder + .comment("Vibration intensity on achieving advancement on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.advancement") + .defineInRange("advancementIntensity", DEFAULT_ADVANCEMENT_INTENSITY, 0, 100); builder.pop(); builder.pop(); } + + public void resetConfigUrl() + { + ConfigHolder.CLIENT.serverUrl.set(DEFAULT_SERVER_URL); + } + + public void resetConfigCustom() + { + ConfigHolder.CLIENT.attackIntensity.set(DEFAULT_ATTACK_INTENSITY); + ConfigHolder.CLIENT.hurtIntensity.set(DEFAULT_HURT_INTENSITY); + ConfigHolder.CLIENT.mineIntensity.set(DEFAULT_MINE_INTENSITY); + ConfigHolder.CLIENT.placeIntensity.set(DEFAULT_PLACE_INTENSITY); + ConfigHolder.CLIENT.xpChangeIntensity.set(DEFAULT_XP_CHANGE_INTENSITY); + ConfigHolder.CLIENT.fishingIntensity.set(DEFAULT_FISHING_INTENSITY); + ConfigHolder.CLIENT.harvestIntensity.set(DEFAULT_HARVEST_INTENSITY); + ConfigHolder.CLIENT.vitalityIntensity.set(DEFAULT_VITALITY_INTENSITY); + ConfigHolder.CLIENT.advancementIntensity.set(DEFAULT_ADVANCEMENT_INTENSITY); + } + public enum GameplayMode { NORMAL("gui." + Minegasm.MOD_ID + ".config.mode.normal"), MASOCHIST("gui." + Minegasm.MOD_ID + ".config.mode.masochist"), HEDONIST("gui." + Minegasm.MOD_ID + ".config.mode.hedonist"), + ACCUMULATION("gui." + Minegasm.MOD_ID + ".config.mode.accumulation"), CUSTOM("gui." + Minegasm.MOD_ID + ".config.mode.custom"); private final String translateKey; @@ -93,5 +154,65 @@ public enum GameplayMode { public String getTranslateKey() { return this.translateKey; } + + public GameplayMode next() + { + boolean foundCurrent = false; + for (GameplayMode type : values()) + { + if (foundCurrent) + return type; + else if (this == type) + foundCurrent = true; + } + return values()[0]; + } + + } + + public enum TickFrequencyOptions { + EVERY_TICK(1), + EVERY_OTHER_TICK(2), + EVERY_5_TICKS(5), + EVERY_10_TICKS(10), + EVERY_20_TICKS(20), + EVERY_30_TICKS(30), + EVERY_40_TICKS(40), + EVERY_50_TICKS(50); + + private int value; + + TickFrequencyOptions(int value) { + this.value = value; + } + + public int getInt() + { + return value; + } + + public static TickFrequencyOptions fromInt(int value) + { + for (TickFrequencyOptions type : values()) { + if (type.getInt() == value) { + return type; + } + } + return null; + } + + public TickFrequencyOptions next() + { + boolean foundCurrent = false; + for (TickFrequencyOptions type : values()) + { + if (foundCurrent) + return type; + else if (this == type) + foundCurrent = true; + } + return values()[0]; + } } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java index 4441fb2..c647c9f 100644 --- a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java @@ -1,20 +1,61 @@ package com.therainbowville.minegasm.config; +//import net.minecraftforge.fmlclient.ConfigGuiHandler; +//import net.minecraftforge.common.ForgeConfigSpec; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public final class ConfigHelper { + private static final Logger LOGGER = LogManager.getLogger(); public static void bakeClient() { MinegasmConfig.serverUrl = ConfigHolder.CLIENT.serverUrl.get(); MinegasmConfig.vibrate = ConfigHolder.CLIENT.vibrate.get(); MinegasmConfig.mode = ConfigHolder.CLIENT.mode.get(); + MinegasmConfig.stealth = ConfigHolder.CLIENT.stealth.get(); + MinegasmConfig.tickFrequency = ConfigHolder.CLIENT.tickFrequency.get().getInt(); + MinegasmConfig.ticksPerSecond = Math.max(1, Math.toIntExact(20 / MinegasmConfig.tickFrequency)); + MinegasmConfig.attackIntensity = ConfigHolder.CLIENT.attackIntensity.get(); MinegasmConfig.hurtIntensity = ConfigHolder.CLIENT.hurtIntensity.get(); MinegasmConfig.mineIntensity = ConfigHolder.CLIENT.mineIntensity.get(); + MinegasmConfig.placeIntensity = ConfigHolder.CLIENT.placeIntensity.get(); MinegasmConfig.xpChangeIntensity = ConfigHolder.CLIENT.xpChangeIntensity.get(); + MinegasmConfig.fishingIntensity = ConfigHolder.CLIENT.fishingIntensity.get(); MinegasmConfig.harvestIntensity = ConfigHolder.CLIENT.harvestIntensity.get(); MinegasmConfig.vitalityIntensity = ConfigHolder.CLIENT.vitalityIntensity.get(); + MinegasmConfig.advancementIntensity = ConfigHolder.CLIENT.advancementIntensity.get(); } public static void bakeServer() { } + + public static void saveClient() + { + try{ + + MinegasmConfigBuffer buffer = new MinegasmConfigBuffer(); + + ConfigHolder.CLIENT.serverUrl.set(buffer.serverUrl); + ConfigHolder.CLIENT.vibrate.set(buffer.vibrate); + ConfigHolder.CLIENT.mode.set(buffer.mode); + ConfigHolder.CLIENT.stealth.set(buffer.stealth); + ConfigHolder.CLIENT.tickFrequency.set(ClientConfig.TickFrequencyOptions.fromInt(buffer.tickFrequency)); + + ConfigHolder.CLIENT.attackIntensity.set(buffer.attackIntensity); + ConfigHolder.CLIENT.hurtIntensity.set(buffer.hurtIntensity); + ConfigHolder.CLIENT.mineIntensity.set(buffer.mineIntensity); + ConfigHolder.CLIENT.placeIntensity.set(buffer.placeIntensity); + ConfigHolder.CLIENT.xpChangeIntensity.set(buffer.xpChangeIntensity); + ConfigHolder.CLIENT.fishingIntensity.set(buffer.fishingIntensity); + ConfigHolder.CLIENT.harvestIntensity.set(buffer.harvestIntensity); + ConfigHolder.CLIENT.vitalityIntensity.set(buffer.vitalityIntensity); + ConfigHolder.CLIENT.advancementIntensity.set(buffer.advancementIntensity); + } catch (Throwable e) + { + LOGGER.info(e); + } + } } \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java index b2544b5..584702d 100644 --- a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java @@ -1,217 +1,349 @@ package com.therainbowville.minegasm.config; import com.mojang.blaze3d.matrix.MatrixStack; -import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.AbstractOption; -import net.minecraft.client.GameSettings; -import net.minecraft.client.gui.screen.IngameMenuScreen; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.IngameMenuScreen; +import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.client.gui.widget.list.OptionsRowList; -import net.minecraft.client.settings.BooleanOption; -import net.minecraft.client.settings.IteratableOption; -import net.minecraft.client.settings.SliderPercentageOption; -import net.minecraft.util.text.ITextComponent; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.gui.DialogTexts; +import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.StringTextComponent; -import net.minecraft.util.text.TranslationTextComponent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import java.util.Objects; +import net.minecraftforge.fml.client.gui.widget.ExtendedButton; +import net.minecraftforge.eventbus.api.SubscribeEvent; -public final class ConfigScreen extends Screen { - private static final Logger LOGGER = LogManager.getLogger(); - private static final int TITLE_HEIGHT = 8; - private static final int OPTIONS_LIST_TOP_HEIGHT = 24; // top screen to top option list - private static final int OPTIONS_LIST_BOTTOM_OFFSET = 32; // bottom screen to bottom option list - private static final int OPTIONS_LIST_ITEM_HEIGHT = 25; +import net.minecraftforge.client.gui.widget.ForgeSlider; - private static final int BUTTON_WIDTH = 200; - private static final int BUTTON_HEIGHT = 20; - private static final int DONE_BUTTON_TOP_OFFSET = 26; // bottom screen to done button top +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.client.ToyController; +import com.therainbowville.minegasm.client.ClientEventHandler; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; - private final Screen lastScreen; - private OptionsRowList optionsRowList; - private static final ClientConfig clientConfig = ConfigHolder.getClientInstance(); +import java.lang.reflect.Field; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.Objects; - public ConfigScreen(Screen parentScreen) { - super(new StringTextComponent(Minegasm.NAME)); - this.lastScreen = parentScreen; - } +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + TextFieldWidget wsHost = null; + + private ClientConfig.TickFrequencyOptions tickValue; + private PlainTextLabel connectResponse; - private static boolean vibrate = false; - private static int mode = 0; - private static int attackIntensity = 0; - private static int hurtIntensity = 0; - private static int mineIntensity = 0; - private static int xpChangeIntensity = 0; - private static int harvestIntensity = 0; - private static int vitalityIntensity = 0; + public ConfigScreen(Screen previous) { + super(new StringTextComponent("Minegasm Config")); + this.previous = previous; + pauseMenu = false; + tickValue = ClientConfig.TickFrequencyOptions.fromInt(MinegasmConfig.tickFrequency); + } + + public ConfigScreen(Screen previous, boolean pause) { + super(new StringTextComponent("Minegasm Config")); + this.previous = previous; + pauseMenu = pause; + tickValue = ClientConfig.TickFrequencyOptions.fromInt(MinegasmConfig.tickFrequency); + } @Override protected void init() { - LOGGER.debug("Initializing config screen"); - - vibrate = MinegasmConfig.vibrate; - mode = MinegasmConfig.mode.ordinal(); - attackIntensity = MinegasmConfig.attackIntensity; - hurtIntensity = MinegasmConfig.hurtIntensity; - mineIntensity = MinegasmConfig.mineIntensity; - xpChangeIntensity = MinegasmConfig.xpChangeIntensity; - harvestIntensity = MinegasmConfig.harvestIntensity; - vitalityIntensity = MinegasmConfig.vitalityIntensity; - - this.optionsRowList = createOptions(); - this.children.add(this.optionsRowList); - - this.addButton(new Button( - (this.width - BUTTON_WIDTH) / 2, - this.height - DONE_BUTTON_TOP_OFFSET, - BUTTON_WIDTH, BUTTON_HEIGHT, - new StringTextComponent("Done"), - button -> this.onClose() + wsHost = new TextFieldWidget(Minecraft.getInstance().font, this.width / 2 - 100, this.height / 6, 200, 20, null); + wsHost.setValue(MinegasmConfig.serverUrl); + this.addButton(wsHost); + + wsHost.setResponder(s -> { + LOGGER.info(s); + MinegasmConfig.serverUrl = s; + }); + + this.addButton(new ExtendedButton( + this.width / 2 - 155, this.height / 6 + 25, 150, 20, + new StringTextComponent("Reset Server Url"), button -> { + ConfigHolder.getClientInstance().resetConfigUrl(); + MinegasmConfig.serverUrl = ConfigHolder.getClientInstance().serverUrl.get(); + wsHost.setValue(MinegasmConfig.serverUrl); + } )); - } + + connectResponse = new PlainTextLabel(this.width / 2 - 155, this.height / 6 + 50, 310, 15, new StringTextComponent("" + TextFormatting.GREEN)); - private OptionsRowList createOptions() { - OptionsRowList optionsRowList = new OptionsRowList( - Objects.requireNonNull(this.minecraft), this.width, this.height, - OPTIONS_LIST_TOP_HEIGHT, - this.height - OPTIONS_LIST_BOTTOM_OFFSET, - OPTIONS_LIST_ITEM_HEIGHT + this.addButton(connectResponse); + + Button reconnectButton = new ExtendedButton( + this.width / 2 + 5, this.height / 6 + 25, 150, 20, + new StringTextComponent("Reconnect"), button -> { + button.active = false; + connectResponse.setValue("Connecting"); + new Thread(() -> { + if (ToyController.connectDevice()) { + ClientEventHandler.afterConnect(); + button.active = true; + connectResponse.setValue(String.format("Connected to " + TextFormatting.GREEN + "%s" + TextFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())); + } else { + button.active = true; + connectResponse.setValue(String.format(TextFormatting.YELLOW + "Minegasm " + TextFormatting.RESET + "failed to start: %s", ToyController.getLastErrorMessage())); + } + + }).start(); + } ); + this.addButton(reconnectButton); + + reconnectButton.active = pauseMenu; + + this.addButton(new ExtendedButton(this.width / 2 - 155, this.height / 6 + 25 * 3, 150, 20, + new StringTextComponent("Vibration: " + (MinegasmConfig.vibrate ? "True" : "False")), (button) -> { + MinegasmConfig.vibrate = !MinegasmConfig.vibrate; + button.setMessage(new StringTextComponent("Vibration: " + (MinegasmConfig.vibrate ? "True" : "False"))); + })); - String VIBRATE = "gui.minegasm.config.vibrate"; - AbstractOption vibrateOption = new BooleanOption( - VIBRATE, - (gameSettings) -> vibrate, - (gameSettings, newValue) -> vibrate = newValue - ); + this.addButton(new ExtendedButton(this.width / 2 + 5, this.height / 6 + 25 * 3, 150, 20, + new StringTextComponent("Stealth: " + (MinegasmConfig.stealth ? "True" : "False")), (button) -> { + MinegasmConfig.stealth = !MinegasmConfig.stealth; + button.setMessage(new StringTextComponent("Stealth: " + (MinegasmConfig.stealth ? "True" : "False"))); + })); - String MODE = "gui.minegasm.config.mode"; - AbstractOption modeOption = new IteratableOption( - MODE, - (gameSettings, newValue) -> mode = (mode + newValue) % ClientConfig.GameplayMode.values().length, - (gameSettings, option) -> - new TranslationTextComponent(MODE).append(": ") - .append(new TranslationTextComponent( - ClientConfig.GameplayMode.values()[mode].getTranslateKey()))); - - // Intensity - String ATTACK_INTENSITY = "gui.minegasm.config.intensity.attack"; - AbstractOption attackIntensityOption = new SliderPercentageOption( - ATTACK_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) attackIntensity, - (gameSettings, newValue) -> { - attackIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(ATTACK_INTENSITY, gameSettings, option) - ); - String HURT_INTENSITY = "gui.minegasm.config.intensity.hurt"; - AbstractOption hurtIntensityOption = new SliderPercentageOption( - HURT_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) hurtIntensity, - (gameSettings, newValue) -> { - hurtIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(HURT_INTENSITY, gameSettings, option) - ); + this.addButton(new ExtendedButton(this.width / 2 - 155, this.height / 6 + 25 * 4, 150, 20, + new StringTextComponent("Mode: " + gameplayModeToString(MinegasmConfig.mode)), (button) -> { + MinegasmConfig.mode = MinegasmConfig.mode.next(); + button.setMessage(new StringTextComponent("Mode: " + gameplayModeToString(MinegasmConfig.mode))); + } + )); - String MINE_INTENSITY = "gui.minegasm.config.intensity.mine"; - AbstractOption mineIntensityOption = new SliderPercentageOption( - MINE_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) mineIntensity, - (gameSettings, newValue) -> { - mineIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(MINE_INTENSITY, gameSettings, option) - ); + this.addButton(new ExtendedButton( + this.width / 2 + 5, this.height / 6 + 25 * 4, 150, 20, + new StringTextComponent("Edit Custom Settings"), button -> minecraft.setScreen(new CustomModeConfigScreen(this, pauseMenu)))); - String XP_CHANGE_INTENSITY = "gui.minegasm.config.intensity.xp"; - AbstractOption xpChangeIntensityOption = new SliderPercentageOption( - XP_CHANGE_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) xpChangeIntensity, - (gameSettings, newValue) -> { - xpChangeIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(XP_CHANGE_INTENSITY, gameSettings, option) + this.addButton(new ExtendedButton(this.width / 2 - 100, this.height / 6 + 25 * 5, 200, 20, + new StringTextComponent("Tick Frequency: " + tickFrequencyToString(MinegasmConfig.tickFrequency)), (button) -> { + tickValue = tickValue.next(); + MinegasmConfig.tickFrequency = tickValue.getInt(); + MinegasmConfig.ticksPerSecond = Math.max(1, Math.toIntExact(20 / MinegasmConfig.tickFrequency)); + button.setMessage(new StringTextComponent("Tick Frequency: " + tickFrequencyToString(MinegasmConfig.tickFrequency))); + } + ) ); - String HARVEST_INTENSITY = "gui.minegasm.config.intensity.harvest"; - AbstractOption harvestIntensityOption = new SliderPercentageOption( - HARVEST_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) harvestIntensity, - (gameSettings, newValue) -> { - harvestIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(HARVEST_INTENSITY, gameSettings, option) - ); + this.addButton(new ExtendedButton( + this.width / 2 - 100, this.height - 27, 200, 20, + DialogTexts.GUI_DONE, button -> this.onClose())); + - String VITALITY_INTENSITY = "gui.minegasm.config.intensity.vitality"; - AbstractOption vitalityIntensityOption = new SliderPercentageOption( - VITALITY_INTENSITY, - 0.0, 100, 10.0F, - (gameSettings) -> (double) vitalityIntensity, - (gameSettings, newValue) -> { - vitalityIntensity = newValue.intValue(); - mode = ClientConfig.GameplayMode.CUSTOM.ordinal(); - }, - (gameSettings, option) -> getPercentValueComponent(VITALITY_INTENSITY, gameSettings, option) - ); + } + + private String gameplayModeToString(ClientConfig.GameplayMode mode){ + switch (mode) { + case NORMAL: return "Normal"; + case MASOCHIST: return "Masochist"; + case HEDONIST: return "Hedonist"; + case ACCUMULATION: return "Accumulation"; + case CUSTOM: return "Custom"; + default: return ""; + } + } + + private String tickFrequencyToString(Integer frequency){ + switch (frequency) { + case 1: return "Every Tick"; + case 2: return "Every Other Tick"; + case 5: return "Every 5 Ticks"; + case 10: return "Every 10 Ticks"; + case 20: return "Every Second"; + default: return "Every " + Float.toString(frequency / 20f)+ " Seconds"; + } + } + + @Override + public void tick() { + super.tick(); - optionsRowList.addSmall(vibrateOption, modeOption); - optionsRowList.addSmall(attackIntensityOption, hurtIntensityOption); - optionsRowList.addSmall(mineIntensityOption, xpChangeIntensityOption); - optionsRowList.addSmall(harvestIntensityOption, vitalityIntensityOption); + // Add ticking logic for TextFieldWidget in editBox + if (this.wsHost != null) + this.wsHost.tick(); + } - return optionsRowList; + @Override + public void onClose() { + connectResponse.setValue(""); + this.minecraft.setScreen(this.previous); + MinegasmConfig.save(); } - private ITextComponent getPercentValueComponent(String translationKey, GameSettings gameSettings, SliderPercentageOption option) { - return new TranslationTextComponent(translationKey).append(": ").append(option.toPct(option.get(gameSettings)) == 0.0D ? "Off" : (int) option.get(gameSettings) + "%"); + @Override + public void render(MatrixStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(0); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } + + class PlainTextLabel extends Widget { + + private StringTextComponent text = new StringTextComponent(""); + private int x; + private int y; + + public PlainTextLabel(int x, int y, int width, int height, StringTextComponent text) { + super(x, y, width, height, text); + this.x = x; + this.y = y; + } + + public void setValue(String value) + { + text = new StringTextComponent(value); + } + + @Override + public void render(MatrixStack poseStack, int i, int j, float f) { + if (text == null || text.getString().isEmpty()) + return; + + drawCenteredString(poseStack, Minecraft.getInstance().font, text.getString(), Minecraft.getInstance().screen.width / 2, this.y + this.height / 4, 0xFFFFFF); + } + } + +} + +class CustomModeConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + + public CustomModeConfigScreen(Screen previous) { + super(new StringTextComponent("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = false; + } + + public CustomModeConfigScreen(Screen previous, boolean pause) { + super(new StringTextComponent("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = pause; } - @SuppressWarnings("NullableProblems") @Override - public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { - this.renderBackground(matrixStack); - this.children.remove(this.optionsRowList); - this.optionsRowList = createOptions(); - this.children.add(this.optionsRowList); - this.optionsRowList.render(matrixStack, mouseX, mouseY, partialTicks); + protected void init() { + try{ + this.addButton(new ExtendedButton( + this.width / 2 + 5, this.height - 27, 150, 20, + DialogTexts.GUI_DONE, button -> this.onClose())); - //noinspection SuspiciousNameCombination - drawCenteredString(matrixStack, this.font, this.title, - this.width / 2, TITLE_HEIGHT, 0xFFFFFF); + IntensitiySliderBar.sliders.clear(); - super.render(matrixStack, mouseX, mouseY, partialTicks); + // Attack + this.addButton(new IntensitiySliderBar(this, "Attack: ", MinegasmConfig.class.getField("attackIntensity"))); + + // Hurt + this.addButton(new IntensitiySliderBar(this, "Hurt: ", MinegasmConfig.class.getField("hurtIntensity"))); + + // Mine + this.addButton(new IntensitiySliderBar(this, "Mine: ", MinegasmConfig.class.getField("mineIntensity"))); + + // Place + this.addButton(new IntensitiySliderBar(this, "Place: ", MinegasmConfig.class.getField("placeIntensity"))); + + // XP Change + this.addButton(new IntensitiySliderBar(this, "XP Change: ", MinegasmConfig.class.getField("xpChangeIntensity"))); + + // Fishing + this.addButton(new IntensitiySliderBar(this, "Fishing: ", MinegasmConfig.class.getField("fishingIntensity"))); + + // Harvest + this.addButton(new IntensitiySliderBar(this, "Harvest: ", MinegasmConfig.class.getField("harvestIntensity"))); + + // Vitality + this.addButton(new IntensitiySliderBar(this, "Vitality: ", MinegasmConfig.class.getField("vitalityIntensity"))); + + // Advancement + this.addButton(new IntensitiySliderBar(this, "Advancement: ", MinegasmConfig.class.getField("advancementIntensity"))); + + this.addButton(new ExtendedButton( + this.width / 2 - 155, this.height - 27, 150, 20, + new StringTextComponent("Reset Values"), button -> { + ConfigHolder.getClientInstance().resetConfigCustom(); + IntensitiySliderBar.refreshAllValues(); + } + )); + + + } catch (Throwable e) { + LOGGER.throwing(e); + } } @Override public void onClose() { - LOGGER.debug("saving..."); - clientConfig.vibrate.set(vibrate); - clientConfig.mode.set(ClientConfig.GameplayMode.values()[mode]); - clientConfig.attackIntensity.set(attackIntensity); - clientConfig.hurtIntensity.set(hurtIntensity); - clientConfig.mineIntensity.set(mineIntensity); - clientConfig.xpChangeIntensity.set(xpChangeIntensity); - clientConfig.harvestIntensity.set(harvestIntensity); - clientConfig.vitalityIntensity.set(vitalityIntensity); - ConfigHolder.CLIENT_SPEC.save(); - ConfigHelper.bakeClient(); - Objects.requireNonNull(this.minecraft).setScreen(this.lastScreen instanceof IngameMenuScreen ? null : this.lastScreen); + IntensitiySliderBar.sliders.clear(); + this.minecraft.setScreen(this.previous); + } + + @Override + public void render(MatrixStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(0); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } +} + +class IntensitiySliderBar extends ForgeSlider +{ + private static final Logger LOGGER = LogManager.getLogger(); + public static ArrayList sliders = new ArrayList(); + private Field fieldReference; + + IntensitiySliderBar(CustomModeConfigScreen parent, String prefix, Field field) throws Exception + { + super( parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155), // x pos + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2), // y pos + 150, 20, // Width, height + new StringTextComponent(prefix), // Prefix + new StringTextComponent(""), // Suffix + 0, 100, field.getInt(null), 1, 1, true); // Min, Max, Default value, stepsize, percision, drawstring + fieldReference = field; + sliders.add(this); + } + + @Override + public void applyValue() + { + try { + fieldReference.set(null, this.getValueInt()); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public static void refreshAllValues() + { + for (IntensitiySliderBar slider : sliders) + { + slider.refreshValue(); + } + } + + private void refreshValue() + { + try { + this.setValue(fieldReference.getInt(null)); + } catch (Throwable e) { + LOGGER.throwing(e); + } } } \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java index 99e0757..79b2dd9 100644 --- a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java @@ -1,6 +1,7 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; @@ -8,7 +9,7 @@ import org.apache.logging.log4j.Logger; -@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD) public class MinegasmConfig { private static final Logger LOGGER = LogManager.getLogger(); @@ -16,13 +17,20 @@ public class MinegasmConfig { public static String serverUrl; public static boolean vibrate; - public static Enum mode; + public static ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public static boolean stealth; + public static int tickFrequency; + public static int ticksPerSecond; + public static int attackIntensity; public static int hurtIntensity; public static int mineIntensity; + public static int placeIntensity; public static int xpChangeIntensity; + public static int fishingIntensity; public static int harvestIntensity; public static int vitalityIntensity; + public static int advancementIntensity; // Server // -- none at the moment @@ -39,4 +47,49 @@ public static void onModConfigEvent(final ModConfig.ModConfigEvent event) { LOGGER.debug("Baked server config"); } } + + public static void save() + { + ConfigHelper.saveClient(); + } + } + +class MinegasmConfigBuffer +{ + public String serverUrl; + + public boolean vibrate; + public ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public boolean stealth; + public int tickFrequency; + + public int attackIntensity; + public int hurtIntensity; + public int mineIntensity; + public int placeIntensity; + public int xpChangeIntensity; + public int fishingIntensity; + public int harvestIntensity; + public int vitalityIntensity; + public int advancementIntensity; + + MinegasmConfigBuffer() + { + this.serverUrl = MinegasmConfig.serverUrl; + this.vibrate = MinegasmConfig.vibrate; + this.mode = MinegasmConfig.mode; + this.stealth = MinegasmConfig.stealth; + this.tickFrequency = MinegasmConfig.tickFrequency; + + this.attackIntensity = MinegasmConfig.attackIntensity; + this.hurtIntensity = MinegasmConfig.hurtIntensity; + this.mineIntensity = MinegasmConfig.mineIntensity; + this.placeIntensity = MinegasmConfig.placeIntensity; + this.xpChangeIntensity = MinegasmConfig.xpChangeIntensity; + this.fishingIntensity = MinegasmConfig.fishingIntensity; + this.harvestIntensity = MinegasmConfig.harvestIntensity; + this.vitalityIntensity = MinegasmConfig.vitalityIntensity; + this.advancementIntensity = MinegasmConfig.advancementIntensity; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java new file mode 100644 index 0000000..7680039 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java @@ -0,0 +1,89 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.gui.widget.button.Button; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.resources.I18n; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.ResourceLocation; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Adapted from https://github.com/Creators-of-Create/Create/ +public class PauseMenuButton extends Button +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static ResourceLocation LOGO = new ResourceLocation(Minegasm.MOD_ID, "textures/logo.png"); + + int xPos; + int yPos; + + public PauseMenuButton(int x, int y) { + super(x, y, 20, 20, new StringTextComponent(""), PauseMenuButton::clicked); + xPos = x; + yPos = y; + } + + @Override + public void renderBg(MatrixStack mstack, Minecraft mc, int mouseX, int mouseY) { + mstack.pushPose(); + mstack.translate(xPos + width / 2 - (64 * 0.25f) / 2, yPos + height / 2 - (64 * 0.25f) / 2, 0); + mstack.scale(0.25f, 0.25f, 1); + Minecraft.getInstance().getTextureManager().bind(LOGO); + AbstractGui.blit(mstack, 0, 0, 0, 0, 0, 64, 64, 64, 64); + mstack.popPose(); + } + + public static void clicked(Button button) + { + Minecraft.getInstance().setScreen(new ConfigScreen(Minecraft.getInstance().screen, true)); + } + + public static class SingleMenuRow { + public final String left, right; + public SingleMenuRow(String left, String right) { + this.left = I18n.get(left); + this.right = I18n.get(right); + } + public SingleMenuRow(String center) { + this(center, center); + } + } + + public static class MenuRows { + public static final MenuRows MAIN_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.singleplayer"), + new SingleMenuRow("menu.multiplayer"), + new SingleMenuRow("fml.menu.mods", "menu.online"), + new SingleMenuRow("narrator.button.language", "narrator.button.accessibility") + )); + + public static final MenuRows INGAME_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.returnToGame"), + new SingleMenuRow("gui.advancements", "gui.stats"), + new SingleMenuRow("menu.sendFeedback", "menu.reportBugs"), + new SingleMenuRow("menu.options", "menu.shareToLan"), + new SingleMenuRow("menu.returnToMenu") + )); + + protected final List leftButtons, rightButtons; + + public MenuRows(List variants) { + leftButtons = variants.stream().map(r -> r.left).collect(Collectors.toList()); + rightButtons = variants.stream().map(r -> r.right).collect(Collectors.toList()); + } + } + +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/PauseMenuButtonScreen.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/PauseMenuButtonScreen.java new file mode 100644 index 0000000..3a5fab4 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/config/PauseMenuButtonScreen.java @@ -0,0 +1,48 @@ +package com.therainbowville.minegasm.config; + + +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.client.gui.screen.IngameMenuScreen; + +import org.apache.commons.lang3.mutable.MutableObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.therainbowville.minegasm.common.Minegasm; + +@Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class PauseMenuButtonScreen { + private static final Logger LOGGER = LogManager.getLogger(); + + @SubscribeEvent + public static void onGuiInit(GuiScreenEvent.InitGuiEvent event) { + if(event.getGui() instanceof IngameMenuScreen) { // Make sure GUI is Escape menu + PauseMenuButton.MenuRows menu = PauseMenuButton.MenuRows.INGAME_MENU; + int rowIdx = 3; + int offsetX = 4; + boolean onLeft = offsetX < 0; + String target = (onLeft ? menu.leftButtons : menu.rightButtons).get(rowIdx - 1); + LOGGER.info(target); + + int offsetX_ = offsetX; + MutableObject toAdd = new MutableObject<>(null); + event.getWidgetList() + .stream() + .filter(w -> w instanceof Widget) + .map(w -> (Widget) w) + .filter(w -> w.getMessage() + .getString() + .equals(target)) + .findFirst() + .ifPresent(w -> toAdd + .setValue(new PauseMenuButton(w.x + offsetX_ + (onLeft ? -20 : w.getWidth()), w.y))); + if (toAdd.getValue() != null) + event.addWidget(toAdd.getValue()); + } + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java new file mode 100644 index 0000000..51cc125 --- /dev/null +++ b/forge/fg-6.0/1.16.5/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui.widget; + +import net.minecraft.client.gui.widget.AbstractSlider; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.glfw.GLFW; + +import java.text.DecimalFormat; + +/** + * Slider widget implementation which allows inputting values in a certain range with optional step size. + */ +public class ForgeSlider extends AbstractSlider +{ + protected StringTextComponent prefix; + protected StringTextComponent suffix; + + protected double minValue; + protected double maxValue; + + /** Allows input of discontinuous values with a certain step */ + protected double stepSize; + + protected boolean drawString; + + private final DecimalFormat format; + + /** + * @param x x position of upper left corner + * @param y y position of upper left corner + * @param width Width of the widget + * @param height Height of the widget + * @param prefix {@link StringTextComponent} displayed before the value string + * @param suffix {@link StringTextComponent} displayed after the value string + * @param minValue Minimum (left) value of slider + * @param maxValue Maximum (right) value of slider + * @param currentValue Starting value when widget is first displayed + * @param stepSize Size of step used. Precision will automatically be calculated based on this value if this value is not 0. + * @param precision Only used when {@code stepSize} is 0. Limited to a maximum of 4 (inclusive). + * @param drawString Should text be displayed on the widget + */ + public ForgeSlider(int x, int y, int width, int height, StringTextComponent prefix, StringTextComponent suffix, double minValue, double maxValue, double currentValue, double stepSize, int precision, boolean drawString) + { + super(x, y, width, height, StringTextComponent.EMPTY, 0D); + this.prefix = prefix; + this.suffix = suffix; + this.minValue = minValue; + this.maxValue = maxValue; + this.stepSize = Math.abs(stepSize); + this.value = this.snapToNearest((currentValue - minValue) / (maxValue - minValue)); + this.drawString = drawString; + + if (stepSize == 0D) + { + precision = Math.min(precision, 4); + + StringBuilder builder = new StringBuilder("0"); + + if (precision > 0) + builder.append('.'); + + while (precision-- > 0) + builder.append('0'); + + this.format = new DecimalFormat(builder.toString()); + } + else if (MathHelper.equal(this.stepSize, Math.floor(this.stepSize))) + { + this.format = new DecimalFormat("0"); + } + else + { + this.format = new DecimalFormat(Double.toString(this.stepSize).replaceAll("\\d", "0")); + } + + this.updateMessage(); + } + + /** + * Overload with {@code stepSize} set to 1, useful for sliders with whole number values. + */ + public ForgeSlider(int x, int y, int width, int height, StringTextComponent prefix, StringTextComponent suffix, double minValue, double maxValue, double currentValue, boolean drawString) + { + this(x, y, width, height, prefix, suffix, minValue, maxValue, currentValue, 1D, 0, drawString); + } + + /** + * @return Current slider value as a double + */ + public double getValue() + { + return this.value * (maxValue - minValue) + minValue; + } + + /** + * @return Current slider value as an long + */ + public long getValueLong() + { + return Math.round(this.getValue()); + } + + /** + * @return Current slider value as an int + */ + public int getValueInt() + { + return (int) this.getValueLong(); + } + + /** + * @param value The new slider value + */ + public void setValue(double value) + { + this.value = this.snapToNearest((value - this.minValue) / (this.maxValue - this.minValue)); + this.updateMessage(); + } + + public String getValueString() + { + return this.format.format(this.getValue()); + } + + @Override + public void onClick(double mouseX, double mouseY) + { + this.setValueFromMouse(mouseX); + } + + @Override + protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) + { + super.onDrag(mouseX, mouseY, dragX, dragY); + this.setValueFromMouse(mouseX); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) + { + boolean flag = keyCode == GLFW.GLFW_KEY_LEFT; + if (flag || keyCode == GLFW.GLFW_KEY_RIGHT) + { + if (this.minValue > this.maxValue) + flag = !flag; + float f = flag ? -1F : 1F; + if (stepSize <= 0D) + this.setSliderValue(this.value + (f / (this.width - 8))); + else + this.setValue(this.getValue() + f * this.stepSize); + } + + return false; + } + + private void setValueFromMouse(double mouseX) + { + this.setSliderValue((mouseX - (this.x + 4)) / (this.width - 8)); + } + + /** + * @param value Percentage of slider range + */ + private void setSliderValue(double value) + { + double oldValue = this.value; + this.value = this.snapToNearest(value); + if (!MathHelper.equal(oldValue, this.value)) + this.applyValue(); + + this.updateMessage(); + } + + /** + * Snaps the value, so that the displayed value is the nearest multiple of {@code stepSize}. + * If {@code stepSize} is 0, no snapping occurs. + */ + private double snapToNearest(double value) + { + if(stepSize <= 0D) + return MathHelper.clamp(value, 0D, 1D); + + value = MathHelper.lerp(MathHelper.clamp(value, 0D, 1D), this.minValue, this.maxValue); + + value = (stepSize * Math.round(value / stepSize)); + + if (this.minValue > this.maxValue) + { + value = MathHelper.clamp(value, this.maxValue, this.minValue); + } + else + { + value = MathHelper.clamp(value, this.minValue, this.maxValue); + } + + return (value-this.minValue)/(this.maxValue-this.minValue) * (1D-0D) + 0D; +// return MathHelper.map(value, this.minValue, this.maxValue, 0D, 1D); + } + + @Override + protected void updateMessage() + { + if (this.drawString) + { + this.setMessage(new StringTextComponent("").append(prefix).append(this.getValueString()).append(suffix)); + } + else + { + this.setMessage(StringTextComponent.EMPTY); + } + } + + @Override + protected void applyValue() {} +} \ No newline at end of file diff --git a/forge/fg-6.0/1.16.5/src/main/resources/assets/minegasm/textures/logo.png b/forge/fg-6.0/1.16.5/src/main/resources/assets/minegasm/textures/logo.png new file mode 100644 index 0000000..63eaa64 Binary files /dev/null and b/forge/fg-6.0/1.16.5/src/main/resources/assets/minegasm/textures/logo.png differ diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java index dfa05e8..c534548 100644 --- a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java @@ -1,21 +1,22 @@ package com.therainbowville.minegasm.client; import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.common.*; import com.therainbowville.minegasm.config.ClientConfig; import com.therainbowville.minegasm.config.MinegasmConfig; + import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraftforge.common.util.FakePlayer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.network.chat.TextComponent; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.network.chat.TextComponent; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.ToolAction; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent; import net.minecraftforge.event.entity.EntityLeaveWorldEvent; @@ -26,151 +27,114 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.*; import java.util.stream.Collectors; - +import java.lang.Thread; @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ClientEventHandler { private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); - private static final int TICKS_PER_SECOND = 20; + private static int tickCounter = -1; private static int clientTickCounter = -1; - private static final double[] state = new double[1200]; private static boolean paused = false; private static UUID playerId = null; - - - private static void clearState() { - tickCounter = -1; - clientTickCounter = -1; - Arrays.fill(state, 0); - paused = false; + + private static Map vibrationStates = new HashMap(); + + static { + vibrationStates.put("advancement", new VibrationStateAdvancement()); + vibrationStates.put("attack", new VibrationStateAttack()); + vibrationStates.put("fish", new VibrationStateFish()); + vibrationStates.put("hurt", new VibrationStateHurt()); + vibrationStates.put("mine", new VibrationStateMine()); + vibrationStates.put("place", new VibrationStatePlace()); + vibrationStates.put("harvest", new VibrationStateHarvest((VibrationStateMine)vibrationStates.get("mine"))); + vibrationStates.put("vitality", new VibrationStateVitality()); + vibrationStates.put("xpChange", new VibrationStateXpChange()); + vibrationStates.put("generic", new VibrationStateClient()); } - private static int getStateCounter() { - return tickCounter / 20; + public static void afterConnect() + { + //setState(getStateCounter(), 5); + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); } - - private static void setState(int start, int duration, int intensity, boolean decay) { - if (duration <= 0) { - return; + + private static double getIntensity() + { + double intensity = 0; + for (Map.Entry state : vibrationStates.entrySet()) + { + intensity = Math.max(intensity, state.getValue().getIntensity()); +// LOGGER.info(state.getKey() + ": " + state.getValue().getIntensity()); + } - - if (decay) { - int safeDuration = Math.max(0, duration - 2); - for (int i = 0; i < safeDuration; i++) { - setState(start+i, intensity); - } - setState(start+safeDuration, intensity/2); - setState(start+safeDuration+1, intensity/4); - } else { - for (int i = 0; i < duration; i++) { - setState(start+i, intensity); - } + return intensity / 100; + } + + private static void tickAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.onTick(); } } - - private static void setState(int counter, int intensity) { - boolean accumulate = false; //XXX reserved for future use - setState(counter, intensity, accumulate); + + private static void resetAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.resetState(); + } } - private static void setState(int counter, int intensity, boolean accumulate) { - int safeCounter = counter % state.length; - if (accumulate) { - state[safeCounter] = Math.min(1.0, state[safeCounter] + (intensity / 100.0)); - } else { - state[safeCounter] = Math.min(1.0, Math.max(state[safeCounter], (intensity / 100.0))); + private static boolean isPlayer(Entity entity){ + try { + if (entity instanceof Player && !(entity instanceof FakePlayer)) { + Player player = (Player) entity;; + UUID uuid = player.getGameProfile().getId(); + return uuid.equals(playerId); } + } catch (Throwable e) { + LOGGER.throwing(e); + } + return false; } - private static int getIntensity(String type) { - Map normal = new HashMap<>(); - normal.put("attack", 60); - normal.put("hurt", 0); - normal.put("mine", 80); - normal.put("xpChange", 100); - normal.put("harvest", 0); - normal.put("vitality", 0); - - Map masochist = new HashMap<>(); - masochist.put("attack", 0); - masochist.put("hurt", 100); - masochist.put("mine", 0); - masochist.put("xpChange", 0); - masochist.put("harvest", 0); - masochist.put("vitality", 10); - - Map hedonist = new HashMap<>(); - hedonist.put("attack", 60); - hedonist.put("hurt", 10); - hedonist.put("mine", 80); - hedonist.put("xpChange", 100); - hedonist.put("harvest", 20); - hedonist.put("vitality", 10); - - Map custom = new HashMap<>(); - custom.put("attack", MinegasmConfig.attackIntensity); - custom.put("hurt", MinegasmConfig.hurtIntensity); - custom.put("mine", MinegasmConfig.mineIntensity); - custom.put("xpChange", MinegasmConfig.xpChangeIntensity); - custom.put("harvest", MinegasmConfig.harvestIntensity); - custom.put("vitality", MinegasmConfig.vitalityIntensity); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - return masochist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.HEDONIST)) { - return hedonist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.CUSTOM)) { - return custom.get(type); - } else { - return normal.get(type); - } + private static void clearState() { + tickCounter = -1; + clientTickCounter = -1; + paused = false; + resetAll(); } @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { try { - if (event.phase == TickEvent.Phase.END ) { - Player player = event.player;; - UUID uuid = player.getGameProfile().getId(); - - float playerHealth = player.getHealth(); - float playerFoodLevel = player.getFoodData().getFoodLevel(); - - tickCounter = (tickCounter + 1) % (20 * (60 * TICKS_PER_SECOND)); // 20 min day cycle - - if (tickCounter % TICKS_PER_SECOND == 0) { // every 1 sec - if (uuid.equals(playerId)) { - int stateCounter = getStateCounter(); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - if (playerHealth > 0 && playerHealth <= 1) { - setState(stateCounter, getIntensity("vitality")); - } - } else if (playerHealth >= 20 && playerFoodLevel >= 20) { - setState(stateCounter, getIntensity("vitality")); - } - - double newVibrationLevel = state[stateCounter]; - state[stateCounter] = 0; - - LOGGER.trace("Tick " + stateCounter + ": " + newVibrationLevel); - - if (ToyController.currentVibrationLevel != newVibrationLevel) { - ToyController.setVibrationLevel(newVibrationLevel); - } - } + if (event.phase == TickEvent.Phase.END && isPlayer(event.player)) { + Player player = event.player; + + tickCounter = (tickCounter + 1) % 100; + + + if (tickCounter % MinegasmConfig.tickFrequency == 0) // TODO: Add ticks per second config option (Default: Every tick) + { + tickAll(); + + ((VibrationStateVitality)vibrationStates.get("vitality")).onTick(player); + ((VibrationStateFish)vibrationStates.get("fish")).onTick(player); + + double newVibrationLevel = getIntensity(); + + if (ToyController.currentVibrationLevel != newVibrationLevel) + ToyController.setVibrationLevel(newVibrationLevel); } - if (tickCounter % (5 * TICKS_PER_SECOND) == 0) { // 5 secs - LOGGER.debug("Health: " + playerHealth); - LOGGER.debug("Food: " + playerFoodLevel); - } } } catch (Throwable e) { LOGGER.throwing(e); @@ -202,19 +166,10 @@ public static void onClientTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public static void onAttack(AttackEntityEvent event) { - try { - Entity entity = event.getEntityLiving(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("attack"), true); - } + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateAttack)vibrationStates.get("attack")).onAttack(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -226,98 +181,37 @@ public static void onCriticalHit(CriticalHitEvent event) @SubscribeEvent public static void onHurt(LivingHurtEvent event) { - try { - Entity entity = event.getEntityLiving(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("hurt"), true); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateHurt)vibrationStates.get("hurt")).onHurt(); } } @SubscribeEvent - public static void onDeath(LivingDeathEvent event) + public static void onBreak(BlockEvent.BreakEvent event) { - try { - Entity entity = event.getEntityLiving(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - ToyController.setVibrationLevel(0); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateMine)vibrationStates.get("mine")).onBreak(event.getState()); } - } catch (Throwable e) { - LOGGER.throwing(e); } - } - + + // Triggers when player starts to break block @SubscribeEvent public static void onHarvest(PlayerEvent.HarvestCheck event) { - try { - Player player = event.getPlayer();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getTargetBlock(); - Block block = blockState.getBlock(); - - // ToolType. AXE, HOE, PICKAXE, SHOVEL - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - LOGGER.debug("Harvest: tool: " + - "?" + - " can harvest? " + event.canHarvest() + " hardness: " + blockHardness); - - int intensity = Math.toIntExact(Math.round((getIntensity("harvest") / 100.0 * (blockHardness / 50.0)) * 100)); - - if (event.canHarvest()) { - setState(getStateCounter(), 1, intensity, false); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getPlayer())) + { + ((VibrationStateHarvest)vibrationStates.get("harvest")).onHarvest(); } } - + @SubscribeEvent - public static void onBreak(BlockEvent.BreakEvent event) - { - try { - Player player = event.getPlayer();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getState(); - Block block = blockState.getBlock(); - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - - LOGGER.info("Breaking: " + block.toString()); - - ItemStack mainhandItem = event.getPlayer().getMainHandItem(); - boolean usingAppropriateTool = mainhandItem.isCorrectToolForDrops(blockState); - List toolCan = ToolAction.getActions().stream().filter(a -> mainhandItem.canPerformAction(a)).collect(Collectors.toList()); - LOGGER.debug("mainhand: " + mainhandItem + " [" + toolCan + "]"); - LOGGER.debug("using pickaxe: " + mainhandItem.toString() + ", using appropriate tool: " + usingAppropriateTool); - - if (toolCan.contains(ToolAction.get("AXE")) && usingAppropriateTool) { - int duration = Math.max(1, Math.min(5, Math.toIntExact(Math.round(Math.ceil(Math.log(blockHardness + 0.5)))))); - int intensity = Math.toIntExact(Math.round((getIntensity("mine") / 100.0 * (blockHardness / 50.0)) * 100)); - setState(getStateCounter(), duration, intensity, true); - } - - LOGGER.info("XP to drop: " + event.getExpToDrop()); + public static void onPlace(BlockEvent.EntityPlaceEvent event){ + if (isPlayer(event.getEntity())) + { + ((VibrationStatePlace)vibrationStates.get("place")).onPlace(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -335,22 +229,20 @@ public static void onXpPickup(PlayerXpEvent.PickupXp event) @SubscribeEvent public static void onXpChange(PlayerXpEvent.XpChange event) { - try { - Player player = event.getPlayer();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - int xpChange = event.getAmount(); - long duration = Math.round(Math.ceil(Math.log(xpChange + 0.5))); - - LOGGER.info("XP CHANGE: " + xpChange); - LOGGER.debug("duration: " + duration); - - setState(getStateCounter(), Math.toIntExact(duration), getIntensity("xpChange"), true); + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateXpChange)vibrationStates.get("xpChange")).onXpChange(((Player)event.getEntityLiving()).totalExperience, event.getAmount()); } - } catch (Throwable e) { - LOGGER.throwing(e); } + + + @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event) + { + if (isPlayer(event.getEntityLiving())) + { + ((VibrationStateAdvancement)vibrationStates.get("advancement")).onAdvancement(event); + } } @SubscribeEvent @@ -381,7 +273,6 @@ public static void onRespawn(PlayerEvent.PlayerRespawnEvent event) } - @SubscribeEvent public static void onWorldLoaded(WorldEvent.Load event) { @@ -389,33 +280,39 @@ public static void onWorldLoaded(WorldEvent.Load event) { LOGGER.info("World loaded: " + world.toString()); } + @SubscribeEvent public static void onWorldEntry(EntityJoinWorldEvent event) { Entity entity = event.getEntity(); if( !entity.level.isClientSide() ) { return; } + + if (ToyController.isConnected) return; if (entity instanceof Player) { LOGGER.info("Player respawn world: " + entity.toString()); - - try { + + new Thread(()-> { try { Player player = (Player) entity; UUID uuid = player.getGameProfile().getId(); - + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + LOGGER.info("Stealth: " + MinegasmConfig.stealth); if (ToyController.connectDevice()) { - setState(getStateCounter(), 5); - player.displayClientMessage(new TextComponent(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); - } else { + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); + if (!MinegasmConfig.stealth){ + player.displayClientMessage(new TextComponent(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); + } + } else if (!MinegasmConfig.stealth){ player.displayClientMessage(new TextComponent(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start\n%s", ToyController.getLastErrorMessage())), false); } playerId = uuid; } } catch (Throwable e) { LOGGER.throwing(e); - } + }}).start(); } } } diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ToyController.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ToyController.java index 2e6f091..4577128 100644 --- a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ToyController.java +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/client/ToyController.java @@ -10,10 +10,16 @@ import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.Executors; public class ToyController { private static final Logger LOGGER = LogManager.getLogger(); - private static final ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); + private static ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); private static ButtplugClientDevice device = null; private static boolean shutDownHookAdded = false; public static String lastErrorMessage = ""; @@ -24,9 +30,28 @@ public static boolean connectDevice() { try { device = null; client.disconnect(); + LOGGER.info("URL: " + MinegasmConfig.serverUrl); - client.connect(new URI(MinegasmConfig.serverUrl)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new Callable() { + public Void call() throws Exception { + client.connect(new URI(MinegasmConfig.serverUrl)); + return null; + } + }); + + try + { + future.get(3, TimeUnit.SECONDS); + } catch (TimeoutException e) { + future.cancel(true); + client = new ButtplugClientWSClient("Minegasm"); + throw new TimeoutException("Could not find WebSocket"); + } finally { + executor.shutdownNow(); + } + client.startScanning(); Thread.sleep(5000); diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java new file mode 100644 index 0000000..0ae06df --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java @@ -0,0 +1,128 @@ +package com.therainbowville.minegasm.common; + +import java.util.Map; +import java.util.HashMap; + +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Architecture inspired from https://github.com/Fyustorm/mInetiface +public abstract class AbstractVibrationState +{ + + protected static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); + protected final float streakCountdownAmount; + protected float intensity; + + protected float vibrationCountdown; + protected float vibrationFeedbackCountdown; + + protected AbstractVibrationState(float streakSeconds) + { + streakCountdownAmount = streakSeconds; + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + public void onTick() + { + if (accumulationEnabled()) + { + if (vibrationCountdown > 0) + vibrationCountdown--; + else if (intensity > 0) { + intensity = Math.max(0, intensity - 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + vibrationCountdown = Math.max(0, vibrationCountdown - 1); + } + + vibrationFeedbackCountdown = Math.max(0, vibrationFeedbackCountdown - 1); + } + + public void resetState() + { + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + protected static boolean accumulationEnabled() + { + return MinegasmConfig.mode.equals(ClientConfig.GameplayMode.ACCUMULATION); + } + + public static int getIntensity(String type) { + Map normal = new HashMap<>(); + normal.put("attack", 60); + normal.put("hurt", 0); + normal.put("mine", 80); + normal.put("place", 20); + normal.put("xpChange", 100); + normal.put("harvest", 10); + normal.put("fishing", 50); + normal.put("vitality", 0); + normal.put("advancement", 100); + + Map masochist = new HashMap<>(); + masochist.put("attack", 0); + masochist.put("hurt", 100); + masochist.put("mine", 0); + masochist.put("place", 0); + masochist.put("xpChange", 0); + masochist.put("fishing", 0); + masochist.put("harvest", 0); + masochist.put("vitality", 10); + masochist.put("advancement", 0); + + Map hedonist = new HashMap<>(); + hedonist.put("attack", 60); + hedonist.put("hurt", 10); + hedonist.put("mine", 80); + hedonist.put("place", 20); + hedonist.put("xpChange", 100); + hedonist.put("fishing", 50); + hedonist.put("harvest", 20); + hedonist.put("vitality", 10); + hedonist.put("advancement", 100); + + Map accumulation = new HashMap<>(); + accumulation.put("attack", 1); + accumulation.put("hurt", 1); + accumulation.put("mine", 1); + accumulation.put("place", 1); + accumulation.put("xpChange", 1); + accumulation.put("fishing", 50); + accumulation.put("harvest", 10); + accumulation.put("vitality", 0); + accumulation.put("advancement", 1); + + Map custom = new HashMap<>(); + custom.put("attack", MinegasmConfig.attackIntensity); + custom.put("hurt", MinegasmConfig.hurtIntensity); + custom.put("mine", MinegasmConfig.mineIntensity); + custom.put("place", MinegasmConfig.placeIntensity); + custom.put("xpChange", MinegasmConfig.xpChangeIntensity); + custom.put("fishing", MinegasmConfig.fishingIntensity); + custom.put("harvest", MinegasmConfig.harvestIntensity); + custom.put("vitality", MinegasmConfig.vitalityIntensity); + custom.put("advancement", MinegasmConfig.advancementIntensity); + + + return switch (MinegasmConfig.mode) + { + case NORMAL -> normal.get(type); + case MASOCHIST -> masochist.get(type); + case HEDONIST -> hedonist.get(type); + case ACCUMULATION -> accumulation.get(type); + case CUSTOM -> custom.get(type); + }; + } + + public abstract int getIntensity(); +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/Minegasm.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/Minegasm.java index 82e8cf7..83ba741 100644 --- a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/Minegasm.java +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/Minegasm.java @@ -1,13 +1,16 @@ package com.therainbowville.minegasm.common; -import com.therainbowville.minegasm.config.ConfigHolder; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fmlclient.ConfigGuiHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.therainbowville.minegasm.config.ConfigHolder; +import com.therainbowville.minegasm.config.ConfigHelper; + @Mod(Minegasm.MOD_ID) public class Minegasm { @@ -21,5 +24,7 @@ public Minegasm() { context.registerConfig(ModConfig.Type.SERVER, ConfigHolder.SERVER_SPEC); MinecraftForge.EVENT_BUS.register(this); + + ModLoadingContext.get().registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class, ConfigHelper::createConfigGuiFactory); } } diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java new file mode 100644 index 0000000..abfa9c5 --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java @@ -0,0 +1,47 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.advancements.FrameType; +import net.minecraft.advancements.Advancement; +import net.minecraftforge.event.entity.player.AdvancementEvent; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAdvancement extends AbstractVibrationState +{ + public VibrationStateAdvancement() + { + super(0); + } + + public void onAdvancement(AdvancementEvent event) + { + if (getIntensity("advancement") == 0) return; + try { + LOGGER.info("Advancement Event: " + event); + Advancement advancement = event.getAdvancement(); + if (advancement == null) return; + FrameType type = advancement.getDisplay().getFrame(); + int duration = switch (type) { + case TASK -> 5; + case GOAL -> 7; + case CHALLENGE -> 10; + }; + + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("advancement") + 20); + else if (vibrationCountdown > 0) + return getIntensity("advancement"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java new file mode 100644 index 0000000..acd0375 --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAttack extends AbstractVibrationState +{ + public VibrationStateAttack() + { + super(3); + } + + public void onAttack() + { + if (getIntensity("attack") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * 0; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("attack") + 20); + else if (vibrationCountdown > 0) + return getIntensity("attack"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java new file mode 100644 index 0000000..c952b68 --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java @@ -0,0 +1,24 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateClient extends AbstractVibrationState +{ + public VibrationStateClient() + { + super(0); + } + + public void setVibration(int intensity, int durationSeconds) + { + intensity = intensity; + vibrationCountdown = durationSeconds * MinegasmConfig.ticksPerSecond; + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return Math.toIntExact(Math.round(intensity)); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java new file mode 100644 index 0000000..61e1866 --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateFish extends AbstractVibrationState +{ + public VibrationStateFish() + { + super(0); + } + + public void onTick(Player player) + { + if (player.fishing != null) + { + Vec3 vector = player.fishing.getDeltaMovement(); + double x = vector.x(); + double y = vector.y(); + double z = vector.z(); + if (y < -0.075 && !player.level.getFluidState(player.fishing.blockPosition()).isEmpty() && x == 0 && z == 0) + { + vibrationCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + LOGGER.info("Fishing!"); + } + } + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return getIntensity("fishing"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java new file mode 100644 index 0000000..6b373cd --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java @@ -0,0 +1,32 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHarvest extends AbstractVibrationState +{ + private VibrationStateMine mineState; + + public VibrationStateHarvest(VibrationStateMine state) + { + super(0); + mineState = state; + } + + public void onHarvest() { + vibrationCountdown = 3; + mineState.onHarvest(); + } + + public int getIntensity() + { + if (vibrationCountdown > 0){ + if (accumulationEnabled()) + return Math.min(100, mineState.getIntensity() + 20); + else + return getIntensity("harvest"); + } + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java new file mode 100644 index 0000000..7219c5e --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java @@ -0,0 +1,36 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHurt extends AbstractVibrationState +{ + public VibrationStateHurt() + { + super(3); + } + + public void onHurt() { + if (getIntensity("hurt") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 10); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("hurt") + 20); + else if (vibrationCountdown > 0) + return getIntensity("hurt"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java new file mode 100644 index 0000000..e4c467d --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateMine extends AbstractVibrationState +{ + public VibrationStateMine() + { + super(5); + } + + public void onBreak(BlockState block) { + if (getIntensity("mine") == 0) return; + + String blockName = block.getBlock().getName().getString(); + if (accumulationEnabled()) + { + if (blockName.contains("Ore")) { + intensity = Math.min(100, intensity + 1); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + intensity = Math.min(100, intensity + .25f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + if (blockName.contains("Ore")) { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public void onHarvest() { + if (accumulationEnabled()){ + vibrationCountdown = Math.max(3, vibrationCountdown); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("mine") + 20); + else if (vibrationCountdown > 0) + return getIntensity("mine"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java new file mode 100644 index 0000000..aee4ebf --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java @@ -0,0 +1,35 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStatePlace extends AbstractVibrationState +{ + public VibrationStatePlace() + { + super(5); + } + + public void onPlace() { + if (getIntensity("place") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + .5f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("place") + 20); + else if (vibrationCountdown > 0) + return getIntensity("place"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java new file mode 100644 index 0000000..5824f8f --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java @@ -0,0 +1,62 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; + +import com.therainbowville.minegasm.config.MinegasmConfig; +import com.therainbowville.minegasm.config.ClientConfig; + +public class VibrationStateVitality extends AbstractVibrationState +{ + private int intensityCooldown; + private boolean targetMet; + + public VibrationStateVitality() + { + super(1); + intensityCooldown = 0; + targetMet = false; + } + + public void onTick(Player player) + { + float playerHealth = player.getHealth(); + float playerFoodLevel = player.getFoodData().getFoodLevel(); + + if ((MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth > 0 && playerHealth <= 1 ) + || (!MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth >= 20 && playerFoodLevel >= 20) ){ + + if (targetMet == false){ + targetMet = true; + vibrationFeedbackCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } else + targetMet = false; + +// if (accumulationEnabled() && targetMet) +// { +// if (intensityCooldown == 0) { +// intensity = Math.min(100, intensity + .1f); +// intensityCooldown = 10 * 20; +// } +// vibrationCountdown = streakCountdownAmount; +// intensityCooldown = Math.max(0, intensityCooldown - 1); +// } else + if (targetMet) { + vibrationCountdown = 1; + } + } + + public int getIntensity() + { + if (getIntensity("vitality") == 0) return 0; + + //if (accumulationEnabled()) + //return Math.toIntExact(Math.round(intensity)); + //else + if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("vitality") + 20); + else if (vibrationCountdown > 0) + return getIntensity("vitality"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java new file mode 100644 index 0000000..34b1633 --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateXpChange extends AbstractVibrationState +{ + private int lastLevel; + + public VibrationStateXpChange() + { + super(1); + lastLevel = -1; + } + + // Code adapted from https://github.com/Fyustorm/mInetiface + public void onXpChange(int level, int amount) { + if (amount == 0 || getIntensity("xpChange") == 0) + return; + + if (lastLevel == -1) { + lastLevel = level; + } + + if (lastLevel != level) { + amount *= 2; + } + + lastLevel = level; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + amount / 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + int duration = Math.toIntExact( Math.round( Math.ceil( Math.log(amount + 0.5) ) ) ); + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("xpChange") + 20); + else if (vibrationCountdown > 0) + return getIntensity("xpChange"); + else return 0; + } +} + diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java index 7bc1bc2..c3ca8ff 100644 --- a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java @@ -1,9 +1,11 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.Minecraft; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.mclanguageprovider.MinecraftModLanguageProvider; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.common.ForgeConfigSpec.IntValue; import java.util.Objects; @@ -12,19 +14,41 @@ public final class ClientConfig { final ForgeConfigSpec.BooleanValue vibrate; final ForgeConfigSpec.EnumValue mode; + final ForgeConfigSpec.BooleanValue stealth; + final ForgeConfigSpec.EnumValue tickFrequency; + final ForgeConfigSpec.IntValue attackIntensity; final ForgeConfigSpec.IntValue hurtIntensity; final ForgeConfigSpec.IntValue mineIntensity; + final ForgeConfigSpec.IntValue placeIntensity; final ForgeConfigSpec.IntValue xpChangeIntensity; + final ForgeConfigSpec.IntValue fishingIntensity; final ForgeConfigSpec.IntValue harvestIntensity; final ForgeConfigSpec.IntValue vitalityIntensity; + final ForgeConfigSpec.IntValue advancementIntensity; + + static final String DEFAULT_SERVER_URL = "ws://localhost:12345/buttplug"; + static final boolean DEFAULT_VIBRATE = true; + static final GameplayMode DEFAULT_MODE = GameplayMode.NORMAL; + static final boolean DEFAULT_STEALTH = false; + + static final int DEFAULT_ATTACK_INTENSITY = 60; + static final int DEFAULT_HURT_INTENSITY = 0; + static final int DEFAULT_MINE_INTENSITY = 80; + static final int DEFAULT_PLACE_INTENSITY = 20; + static final int DEFAULT_XP_CHANGE_INTENSITY = 100; + static final int DEFAULT_FISHING_INTENSITY = 50; + static final int DEFAULT_HARVEST_INTENSITY = 0; + static final int DEFAULT_VITALITY_INTENSITY = 0; + static final int DEFAULT_ADVANCEMENT_INTENSITY = 100; + ClientConfig(final ForgeConfigSpec.Builder builder) { builder.push("buttplug"); serverUrl = builder .translation(Minegasm.MOD_ID + ".config.serverUrl") - .define("serverUrl", "ws://localhost:12345/buttplug"); + .define("serverUrl", DEFAULT_SERVER_URL); builder.pop(); @@ -32,50 +56,92 @@ public final class ClientConfig { vibrate = builder .translation(Minegasm.MOD_ID + ".config.vibrate") - .define("vibrate", true); + .define("vibrate", DEFAULT_VIBRATE); mode = builder .translation(Minegasm.MOD_ID + ".config.mode") - .defineEnum("mode", GameplayMode.NORMAL); + .defineEnum("mode", DEFAULT_MODE); + stealth = builder + .translation(Minegasm.MOD_ID + ".config.stealth") + .define("stealth", DEFAULT_STEALTH); + + tickFrequency = builder + .translation(Minegasm.MOD_ID + ".config.mode") + .defineEnum("tickFrequency", TickFrequencyOptions.EVERY_TICK); builder.push("intensity"); attackIntensity = builder .comment("Vibration intensity when attacking on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.attack") - .defineInRange("attackIntensity", 60, 0, 100); + .defineInRange("attackIntensity", DEFAULT_ATTACK_INTENSITY, 0, 100); hurtIntensity = builder .comment("Vibration intensity when hurting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.hurt") - .defineInRange("hurtIntensity", 0, 0, 100); + .defineInRange("hurtIntensity", DEFAULT_HURT_INTENSITY, 0, 100); mineIntensity = builder .comment("Vibration intensity when mining on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.mine") - .defineInRange("mineIntensity", 80, 0, 100); + .defineInRange("mineIntensity", DEFAULT_MINE_INTENSITY, 0, 100); + + placeIntensity = builder + .comment("Vibration intensity when placing blocks on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.place") + .defineInRange("placeIntensity", DEFAULT_PLACE_INTENSITY, 0, 100); xpChangeIntensity = builder .comment("Vibration intensity when gaining XP on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.xp_change") - .defineInRange("xpChangeIntensity", 100, 0, 100); + .defineInRange("xpChangeIntensity", DEFAULT_XP_CHANGE_INTENSITY, 0, 100); + + fishingIntensity = builder + .comment("Vibration intensity when fishing on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.fishing") + .defineInRange("fishingIntensity", DEFAULT_FISHING_INTENSITY, 0, 100); harvestIntensity = builder .comment("Vibration intensity when harvesting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.harvest") - .defineInRange("harvestIntensity", 0, 0, 100); + .defineInRange("harvestIntensity", DEFAULT_HARVEST_INTENSITY, 0, 100); vitalityIntensity = builder .comment("Vibration intensity on high level of player's vitality on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.vitality") - .defineInRange("vitalityIntensity", 0, 0, 100); + .defineInRange("vitalityIntensity", DEFAULT_VITALITY_INTENSITY, 0, 100); + + advancementIntensity = builder + .comment("Vibration intensity on achieving advancement on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.advancement") + .defineInRange("advancementIntensity", DEFAULT_ADVANCEMENT_INTENSITY, 0, 100); builder.pop(); builder.pop(); } + + public void resetConfigUrl() + { + ConfigHolder.CLIENT.serverUrl.set(DEFAULT_SERVER_URL); + } + + public void resetConfigCustom() + { + ConfigHolder.CLIENT.attackIntensity.set(DEFAULT_ATTACK_INTENSITY); + ConfigHolder.CLIENT.hurtIntensity.set(DEFAULT_HURT_INTENSITY); + ConfigHolder.CLIENT.mineIntensity.set(DEFAULT_MINE_INTENSITY); + ConfigHolder.CLIENT.placeIntensity.set(DEFAULT_PLACE_INTENSITY); + ConfigHolder.CLIENT.xpChangeIntensity.set(DEFAULT_XP_CHANGE_INTENSITY); + ConfigHolder.CLIENT.fishingIntensity.set(DEFAULT_FISHING_INTENSITY); + ConfigHolder.CLIENT.harvestIntensity.set(DEFAULT_HARVEST_INTENSITY); + ConfigHolder.CLIENT.vitalityIntensity.set(DEFAULT_VITALITY_INTENSITY); + ConfigHolder.CLIENT.advancementIntensity.set(DEFAULT_ADVANCEMENT_INTENSITY); + } + public enum GameplayMode { NORMAL("gui." + Minegasm.MOD_ID + ".config.mode.normal"), MASOCHIST("gui." + Minegasm.MOD_ID + ".config.mode.masochist"), HEDONIST("gui." + Minegasm.MOD_ID + ".config.mode.hedonist"), + ACCUMULATION("gui." + Minegasm.MOD_ID + ".config.mode.accumulation"), CUSTOM("gui." + Minegasm.MOD_ID + ".config.mode.custom"); private final String translateKey; @@ -89,4 +155,37 @@ public String getTranslateKey() { return this.translateKey; } } + + public enum TickFrequencyOptions { + EVERY_TICK(1), + EVERY_OTHER_TICK(2), + EVERY_5_TICKS(5), + EVERY_10_TICKS(10), + EVERY_20_TICKS(20), + EVERY_30_TICKS(30), + EVERY_40_TICKS(40), + EVERY_50_TICKS(50); + + private int value; + + TickFrequencyOptions(int value) { + this.value = value; + } + + public int getInt() + { + return value; + } + + public static TickFrequencyOptions fromInt(int value) + { + for (TickFrequencyOptions type : values()) { + if (type.getInt() == value) { + return type; + } + } + return null; + } + } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java index 4441fb2..5e46c36 100644 --- a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java @@ -1,20 +1,65 @@ package com.therainbowville.minegasm.config; +import net.minecraftforge.fmlclient.ConfigGuiHandler; +import net.minecraftforge.common.ForgeConfigSpec; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public final class ConfigHelper { + private static final Logger LOGGER = LogManager.getLogger(); public static void bakeClient() { MinegasmConfig.serverUrl = ConfigHolder.CLIENT.serverUrl.get(); MinegasmConfig.vibrate = ConfigHolder.CLIENT.vibrate.get(); MinegasmConfig.mode = ConfigHolder.CLIENT.mode.get(); + MinegasmConfig.stealth = ConfigHolder.CLIENT.stealth.get(); + MinegasmConfig.tickFrequency = ConfigHolder.CLIENT.tickFrequency.get().getInt(); + MinegasmConfig.ticksPerSecond = Math.max(1, Math.toIntExact(20 / MinegasmConfig.tickFrequency)); + MinegasmConfig.attackIntensity = ConfigHolder.CLIENT.attackIntensity.get(); MinegasmConfig.hurtIntensity = ConfigHolder.CLIENT.hurtIntensity.get(); MinegasmConfig.mineIntensity = ConfigHolder.CLIENT.mineIntensity.get(); + MinegasmConfig.placeIntensity = ConfigHolder.CLIENT.placeIntensity.get(); MinegasmConfig.xpChangeIntensity = ConfigHolder.CLIENT.xpChangeIntensity.get(); + MinegasmConfig.fishingIntensity = ConfigHolder.CLIENT.fishingIntensity.get(); MinegasmConfig.harvestIntensity = ConfigHolder.CLIENT.harvestIntensity.get(); MinegasmConfig.vitalityIntensity = ConfigHolder.CLIENT.vitalityIntensity.get(); + MinegasmConfig.advancementIntensity = ConfigHolder.CLIENT.advancementIntensity.get(); } public static void bakeServer() { } + + public static void saveClient() + { + try{ + + MinegasmConfigBuffer buffer = new MinegasmConfigBuffer(); + + ConfigHolder.CLIENT.serverUrl.set(buffer.serverUrl); + ConfigHolder.CLIENT.vibrate.set(buffer.vibrate); + ConfigHolder.CLIENT.mode.set(buffer.mode); + ConfigHolder.CLIENT.stealth.set(buffer.stealth); + ConfigHolder.CLIENT.tickFrequency.set(ClientConfig.TickFrequencyOptions.fromInt(buffer.tickFrequency)); + + ConfigHolder.CLIENT.attackIntensity.set(buffer.attackIntensity); + ConfigHolder.CLIENT.hurtIntensity.set(buffer.hurtIntensity); + ConfigHolder.CLIENT.mineIntensity.set(buffer.mineIntensity); + ConfigHolder.CLIENT.placeIntensity.set(buffer.placeIntensity); + ConfigHolder.CLIENT.xpChangeIntensity.set(buffer.xpChangeIntensity); + ConfigHolder.CLIENT.fishingIntensity.set(buffer.fishingIntensity); + ConfigHolder.CLIENT.harvestIntensity.set(buffer.harvestIntensity); + ConfigHolder.CLIENT.vitalityIntensity.set(buffer.vitalityIntensity); + ConfigHolder.CLIENT.advancementIntensity.set(buffer.advancementIntensity); + } catch (Throwable e) + { + LOGGER.info(e); + } + } + + public static ConfigGuiHandler.ConfigGuiFactory createConfigGuiFactory() { + return new ConfigGuiHandler.ConfigGuiFactory((minecraft, screen) -> new ConfigScreen(screen)); + } } \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java new file mode 100644 index 0000000..d4fb3a9 --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java @@ -0,0 +1,348 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraftforge.client.gui.widget.ForgeSlider; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.network.chat.Component; +import net.minecraftforge.event.TickEvent; +import net.minecraft.client.Minecraft; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.client.ToyController; +import com.therainbowville.minegasm.client.ClientEventHandler; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import java.lang.reflect.Field; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.function.IntConsumer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + EditBox wsHost = null; + + public ConfigScreen(Screen previous) { + super(new TextComponent("Minegasm Config")); + this.previous = previous; + pauseMenu = false; + } + + public ConfigScreen(Screen previous, boolean pause) { + super(new TextComponent("Minegasm Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + wsHost = new EditBox(Minecraft.getInstance().font, this.width / 2 - 100, this.height / 6, 200, 20, null); + wsHost.setValue(MinegasmConfig.serverUrl); + this.addRenderableWidget(wsHost); + + wsHost.setResponder(s -> { + LOGGER.info(s); + MinegasmConfig.serverUrl = s; + }); + + this.addRenderableWidget(new Button( + this.width / 2 - 155, this.height / 6 + 25, 150, 20, + new TextComponent("Reset Server Url"), button -> { + ConfigHolder.getClientInstance().resetConfigUrl(); + MinegasmConfig.serverUrl = ConfigHolder.getClientInstance().serverUrl.get(); + wsHost.setValue(MinegasmConfig.serverUrl); + } + )); + + PlainTextLabel connectResponse = new PlainTextLabel(this.width / 2 - 155, this.height / 6 + 50, 310, 15, new TextComponent("" + ChatFormatting.GREEN)); + + this.addRenderableWidget(connectResponse); + + Button reconnectButton = new Button( + this.width / 2 + 5, this.height / 6 + 25, 150, 20, + new TextComponent("Reconnect"), button -> { + button.active = false; + connectResponse.setValue("Connecting"); + new Thread(() -> { + if (ToyController.connectDevice()) { + ClientEventHandler.afterConnect(); + button.active = true; + connectResponse.setValue(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())); + } else { + button.active = true; + connectResponse.setValue(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start: %s", ToyController.getLastErrorMessage())); + } + + }).start(); + } + ); + this.addRenderableWidget(reconnectButton); + + reconnectButton.active = pauseMenu; + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.vibrate) + .create(this.width / 2 - 155, this.height / 6 + 25 * 3, 150, 20, + new TextComponent("Vibration"), (button, value) -> MinegasmConfig.vibrate = value)); + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.stealth) + .create(this.width / 2 + 5, this.height / 6 + 25 * 3, 150, 20, + new TextComponent("Stealth"), (button, value) -> MinegasmConfig.stealth = value)); + + this.addRenderableWidget( + CycleButton.builder((ClientConfig.GameplayMode mode) -> + new TextComponent(switch (mode) { + case NORMAL -> "Normal"; + case MASOCHIST -> "Masochist"; + case HEDONIST -> "Hedonist"; + case ACCUMULATION -> "Accumulation"; + case CUSTOM -> "Custom"; + })) + .withValues(ClientConfig.GameplayMode.NORMAL, ClientConfig.GameplayMode.MASOCHIST, ClientConfig.GameplayMode.HEDONIST, ClientConfig.GameplayMode.ACCUMULATION, ClientConfig.GameplayMode.CUSTOM) + .withInitialValue(MinegasmConfig.mode) + .create(this.width / 2 - 155, this.height / 6 + 25 * 4, 150, 20, + new TextComponent("Mode"), (button, value) -> { + MinegasmConfig.mode = value; + }) + ); + + this.addRenderableWidget(new Button( + this.width / 2 + 5, this.height / 6 + 25 * 4, 150, 20, + new TextComponent("Edit Custom Settings"), button -> minecraft.setScreen(new CustomModeConfigScreen(this, pauseMenu)))); + + this.addRenderableWidget( + CycleButton.builder((Integer tickFrequency) -> + new TextComponent(switch (tickFrequency) { + case 1 -> "Every Tick"; + case 2 -> "Every Other Tick"; + case 5 -> "Every 5 Ticks"; + case 10 -> "Every 10 Ticks"; + case 20 -> "Every Second"; + default -> "Every " + Float.toString(tickFrequency / 20f)+ " Seconds"; + })) + .withValues(1, 2, 5, 10, 20, 30, 40, 50) + .withInitialValue(MinegasmConfig.tickFrequency) + .create(this.width / 2 - 100, this.height / 6 + 25 * 5, 200, 20, + new TextComponent("Tick Frequency"), (button, value) -> { + MinegasmConfig.tickFrequency = value; + MinegasmConfig.ticksPerSecond = Math.max(1, Math.toIntExact(20 / MinegasmConfig.tickFrequency)); + LOGGER.info("TPS: " + MinegasmConfig.ticksPerSecond); + } + ) + ); + + this.addRenderableWidget(new Button( + this.width / 2 - 100, this.height - 27, 200, 20, + CommonComponents.GUI_DONE, button -> this.onClose())); + + + } + + @Override + public void tick() { + super.tick(); + + // Add ticking logic for EditBox in editBox + if (this.wsHost != null) + this.wsHost.tick(); + } + + @Override + public void onClose() { + PlainTextLabel.setValue(""); + this.minecraft.setScreen(previous); + MinegasmConfig.save(); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(0); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } + + class PlainTextLabel extends AbstractWidget { + + private static TextComponent text = new TextComponent(""); + private int x; + private int y; + + public PlainTextLabel(int x, int y, int width, int height, TextComponent text) { + super(x, y, width, height, text); + this.x = x; + this.y = y; + } + + public static void setValue(String value) + { + text = new TextComponent(value); + } + + @Override + public void updateNarration(NarrationElementOutput output) { + defaultButtonNarrationText(output); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (text == null || text.getString().isEmpty()) + return; + +// RenderSystem.setShaderColor(1, 1, 1, 1); +// Minecraft.getInstance().font.draw(poseStack, text.getString(), x, y, 0xFFFFFF); + drawCenteredString(poseStack, Minecraft.getInstance().font, text.getString(), Minecraft.getInstance().screen.width / 2, this.y + this.height / 4, 0xFFFFFF); + } + } + +} + +class CustomModeConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + + public CustomModeConfigScreen(Screen previous) { + super(new TextComponent("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = false; + } + + public CustomModeConfigScreen(Screen previous, boolean pause) { + super(new TextComponent("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + try{ + this.addRenderableWidget(new Button( + this.width / 2 + 5, this.height - 27, 150, 20, + CommonComponents.GUI_DONE, button -> this.onClose())); + + IntensitiySliderBar.sliders.clear(); + + // Attack + this.addRenderableWidget(new IntensitiySliderBar(this, "Attack: ", MinegasmConfig.class.getField("attackIntensity"))); + + // Hurt + this.addRenderableWidget(new IntensitiySliderBar(this, "Hurt: ", MinegasmConfig.class.getField("hurtIntensity"))); + + // Mine + this.addRenderableWidget(new IntensitiySliderBar(this, "Mine: ", MinegasmConfig.class.getField("mineIntensity"))); + + // Place + this.addRenderableWidget(new IntensitiySliderBar(this, "Place: ", MinegasmConfig.class.getField("placeIntensity"))); + + // XP Change + this.addRenderableWidget(new IntensitiySliderBar(this, "XP Change: ", MinegasmConfig.class.getField("xpChangeIntensity"))); + + // Fishing + this.addRenderableWidget(new IntensitiySliderBar(this, "Fishing: ", MinegasmConfig.class.getField("fishingIntensity"))); + + // Harvest + this.addRenderableWidget(new IntensitiySliderBar(this, "Harvest: ", MinegasmConfig.class.getField("harvestIntensity"))); + + // Vitality + this.addRenderableWidget(new IntensitiySliderBar(this, "Vitality: ", MinegasmConfig.class.getField("vitalityIntensity"))); + + // Advancement + this.addRenderableWidget(new IntensitiySliderBar(this, "Advancement: ", MinegasmConfig.class.getField("advancementIntensity"))); + + this.addRenderableWidget(new Button( + this.width / 2 - 155, this.height - 27, 150, 20, + new TextComponent("Reset Values"), button -> { + ConfigHolder.getClientInstance().resetConfigCustom(); + IntensitiySliderBar.refreshAllValues(); + } + )); + + + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + @Override + public void onClose() { + IntensitiySliderBar.sliders.clear(); + this.minecraft.setScreen(previous); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(0); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } + + private class IntensitiySliderBar extends ForgeSlider + { + public static ArrayList sliders = new ArrayList(); + private Field fieldReference; + + IntensitiySliderBar(CustomModeConfigScreen parent, String prefix, Field field) throws Exception + { + super( parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155), // x pos + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2), // y pos + 150, 20, // Width, height + new TextComponent(prefix), // Prefix + new TextComponent(""), // Suffix + 0, 100, field.getInt(null), 1, 1, true); // Min, Max, Default value, stepsize, percision, drawstring + fieldReference = field; +// LOGGER.info("S: " + sliders.size() + " X: " + parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155) + " Y: " + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2)); + sliders.add(this); + } + + @Override + public void applyValue() + { +// LOGGER.info("applyValue"); + //responder.accept(this.getValueInt()); + try { + fieldReference.set(null, this.getValueInt()); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public static void refreshAllValues() + { + for (IntensitiySliderBar slider : sliders) + { + slider.refreshValue(); + } + } + + private void refreshValue() + { + try { + this.setValue(fieldReference.getInt(null)); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java index 52965d5..b1a115a 100644 --- a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java @@ -18,13 +18,20 @@ public class MinegasmConfig { public static String serverUrl; public static boolean vibrate; - public static Enum mode = ClientConfig.GameplayMode.NORMAL; + public static ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public static boolean stealth; + public static int tickFrequency; + public static int ticksPerSecond; + public static int attackIntensity; public static int hurtIntensity; public static int mineIntensity; + public static int placeIntensity; public static int xpChangeIntensity; + public static int fishingIntensity; public static int harvestIntensity; public static int vitalityIntensity; + public static int advancementIntensity; // Server // -- none at the moment @@ -41,4 +48,49 @@ public static void onModConfigEvent(final ModConfigEvent event) { LOGGER.debug("Baked server config"); } } + + public static void save() + { + ConfigHelper.saveClient(); + } + } + +class MinegasmConfigBuffer +{ + public String serverUrl; + + public boolean vibrate; + public ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public boolean stealth; + public int tickFrequency; + + public int attackIntensity; + public int hurtIntensity; + public int mineIntensity; + public int placeIntensity; + public int xpChangeIntensity; + public int fishingIntensity; + public int harvestIntensity; + public int vitalityIntensity; + public int advancementIntensity; + + MinegasmConfigBuffer() + { + this.serverUrl = MinegasmConfig.serverUrl; + this.vibrate = MinegasmConfig.vibrate; + this.mode = MinegasmConfig.mode; + this.stealth = MinegasmConfig.stealth; + this.tickFrequency = MinegasmConfig.tickFrequency; + + this.attackIntensity = MinegasmConfig.attackIntensity; + this.hurtIntensity = MinegasmConfig.hurtIntensity; + this.mineIntensity = MinegasmConfig.mineIntensity; + this.placeIntensity = MinegasmConfig.placeIntensity; + this.xpChangeIntensity = MinegasmConfig.xpChangeIntensity; + this.fishingIntensity = MinegasmConfig.fishingIntensity; + this.harvestIntensity = MinegasmConfig.harvestIntensity; + this.vitalityIntensity = MinegasmConfig.vitalityIntensity; + this.advancementIntensity = MinegasmConfig.advancementIntensity; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java new file mode 100644 index 0000000..764246f --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java @@ -0,0 +1,131 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.PauseScreen; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.commons.lang3.mutable.MutableObject; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Adapted from https://github.com/Creators-of-Create/Create/ +public class PauseMenuButton extends Button +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static ResourceLocation LOGO = new ResourceLocation(Minegasm.MOD_ID, "textures/logo.png"); + + int xPos; + int yPos; + + public PauseMenuButton(int x, int y) { + super(x, y, 20, 20, new TextComponent(""), PauseMenuButton::clicked); + xPos = x; + yPos = y; + } + + @Override + public void renderBg(PoseStack mstack, Minecraft mc, int mouseX, int mouseY) { + mstack.pushPose(); + mstack.translate(xPos + width / 2 - (64 * 0.25f) / 2, yPos + height / 2 - (64 * 0.25f) / 2, 0); + mstack.scale(0.25f, 0.25f, 1); + RenderSystem.setShaderTexture(0, LOGO); + GuiComponent.blit(mstack, 0, 0, 0, 0, 0, 64, 64, 64, 64); + mstack.popPose(); + } + + public static void clicked(Button button) + { + Minecraft.getInstance().setScreen(new ConfigScreen(Minecraft.getInstance().screen, true)); + } + + public static class SingleMenuRow { + public final String left, right; + public SingleMenuRow(String left, String right) { + this.left = I18n.get(left); + this.right = I18n.get(right); + } + public SingleMenuRow(String center) { + this(center, center); + } + } + + public static class MenuRows { + public static final MenuRows MAIN_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.singleplayer"), + new SingleMenuRow("menu.multiplayer"), + new SingleMenuRow("fml.menu.mods", "menu.online"), + new SingleMenuRow("narrator.button.language", "narrator.button.accessibility") + )); + + public static final MenuRows INGAME_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.returnToGame"), + new SingleMenuRow("gui.advancements", "gui.stats"), + new SingleMenuRow("menu.sendFeedback", "menu.reportBugs"), + new SingleMenuRow("menu.options", "menu.shareToLan"), + new SingleMenuRow("menu.returnToMenu") + )); + + protected final List leftButtons, rightButtons; + + public MenuRows(List variants) { + leftButtons = variants.stream().map(r -> r.left).collect(Collectors.toList()); + rightButtons = variants.stream().map(r -> r.right).collect(Collectors.toList()); + } + } + + @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) + public class PauseMenuButtonScreen { + + @SubscribeEvent + public static void onGuiInit(GuiScreenEvent.InitGuiEvent event) { + if(event.getGui() instanceof PauseScreen) { // Make sure GUI is Escape menu + MenuRows menu = MenuRows.INGAME_MENU; + int rowIdx = 3; + int offsetX = 4; + boolean onLeft = offsetX < 0; + String target = (onLeft ? menu.leftButtons : menu.rightButtons).get(rowIdx - 1); + + int offsetX_ = offsetX; + MutableObject toAdd = new MutableObject<>(null); + event.getWidgetList() + .stream() + .filter(w -> w instanceof AbstractWidget) + .map(w -> (AbstractWidget) w) + .filter(w -> w.getMessage() + .getString() + .equals(target)) + .findFirst() + .ifPresent(w -> toAdd + .setValue(new PauseMenuButton(w.x + offsetX_ + (onLeft ? -20 : w.getWidth()), w.y))); + if (toAdd.getValue() != null) + event.addWidget(toAdd.getValue()); + } + } + } +} diff --git a/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java new file mode 100644 index 0000000..07f2696 --- /dev/null +++ b/forge/fg-6.0/1.17.1/src/main/java/com/therainbowville/minegasm/widgets/ForgeSlider.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.client.gui.widget; + +import net.minecraft.client.gui.components.AbstractSliderButton; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.util.Mth; +import org.lwjgl.glfw.GLFW; + +import java.text.DecimalFormat; + +/** + * Slider widget implementation which allows inputting values in a certain range with optional step size. + */ +public class ForgeSlider extends AbstractSliderButton +{ + protected Component prefix; + protected Component suffix; + + protected double minValue; + protected double maxValue; + + /** Allows input of discontinuous values with a certain step */ + protected double stepSize; + + protected boolean drawString; + + private final DecimalFormat format; + + /** + * @param x x position of upper left corner + * @param y y position of upper left corner + * @param width Width of the widget + * @param height Height of the widget + * @param prefix {@link Component} displayed before the value string + * @param suffix {@link Component} displayed after the value string + * @param minValue Minimum (left) value of slider + * @param maxValue Maximum (right) value of slider + * @param currentValue Starting value when widget is first displayed + * @param stepSize Size of step used. Precision will automatically be calculated based on this value if this value is not 0. + * @param precision Only used when {@code stepSize} is 0. Limited to a maximum of 4 (inclusive). + * @param drawString Should text be displayed on the widget + */ + public ForgeSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, double stepSize, int precision, boolean drawString) + { + super(x, y, width, height, TextComponent.EMPTY, 0D); + this.prefix = prefix; + this.suffix = suffix; + this.minValue = minValue; + this.maxValue = maxValue; + this.stepSize = Math.abs(stepSize); + this.value = this.snapToNearest((currentValue - minValue) / (maxValue - minValue)); + this.drawString = drawString; + + if (stepSize == 0D) + { + precision = Math.min(precision, 4); + + StringBuilder builder = new StringBuilder("0"); + + if (precision > 0) + builder.append('.'); + + while (precision-- > 0) + builder.append('0'); + + this.format = new DecimalFormat(builder.toString()); + } + else if (Mth.equal(this.stepSize, Math.floor(this.stepSize))) + { + this.format = new DecimalFormat("0"); + } + else + { + this.format = new DecimalFormat(Double.toString(this.stepSize).replaceAll("\\d", "0")); + } + + this.updateMessage(); + } + + /** + * Overload with {@code stepSize} set to 1, useful for sliders with whole number values. + */ + public ForgeSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, boolean drawString) + { + this(x, y, width, height, prefix, suffix, minValue, maxValue, currentValue, 1D, 0, drawString); + } + + /** + * @return Current slider value as a double + */ + public double getValue() + { + return this.value * (maxValue - minValue) + minValue; + } + + /** + * @return Current slider value as an long + */ + public long getValueLong() + { + return Math.round(this.getValue()); + } + + /** + * @return Current slider value as an int + */ + public int getValueInt() + { + return (int) this.getValueLong(); + } + + /** + * @param value The new slider value + */ + public void setValue(double value) + { + this.value = this.snapToNearest((value - this.minValue) / (this.maxValue - this.minValue)); + this.updateMessage(); + } + + public String getValueString() + { + return this.format.format(this.getValue()); + } + + @Override + public void onClick(double mouseX, double mouseY) + { + this.setValueFromMouse(mouseX); + } + + @Override + protected void onDrag(double mouseX, double mouseY, double dragX, double dragY) + { + super.onDrag(mouseX, mouseY, dragX, dragY); + this.setValueFromMouse(mouseX); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) + { + boolean flag = keyCode == GLFW.GLFW_KEY_LEFT; + if (flag || keyCode == GLFW.GLFW_KEY_RIGHT) + { + if (this.minValue > this.maxValue) + flag = !flag; + float f = flag ? -1F : 1F; + if (stepSize <= 0D) + this.setSliderValue(this.value + (f / (this.width - 8))); + else + this.setValue(this.getValue() + f * this.stepSize); + } + + return false; + } + + private void setValueFromMouse(double mouseX) + { + this.setSliderValue((mouseX - (this.x + 4)) / (this.width - 8)); + } + + /** + * @param value Percentage of slider range + */ + private void setSliderValue(double value) + { + double oldValue = this.value; + this.value = this.snapToNearest(value); + if (!Mth.equal(oldValue, this.value)) + this.applyValue(); + + this.updateMessage(); + } + + /** + * Snaps the value, so that the displayed value is the nearest multiple of {@code stepSize}. + * If {@code stepSize} is 0, no snapping occurs. + */ + private double snapToNearest(double value) + { + if(stepSize <= 0D) + return Mth.clamp(value, 0D, 1D); + + value = Mth.lerp(Mth.clamp(value, 0D, 1D), this.minValue, this.maxValue); + + value = (stepSize * Math.round(value / stepSize)); + + if (this.minValue > this.maxValue) + { + value = Mth.clamp(value, this.maxValue, this.minValue); + } + else + { + value = Mth.clamp(value, this.minValue, this.maxValue); + } + + return Mth.map(value, this.minValue, this.maxValue, 0D, 1D); + } + + @Override + protected void updateMessage() + { + if (this.drawString) + { + this.setMessage(new TextComponent("").append(prefix).append(this.getValueString()).append(suffix)); + } + else + { + this.setMessage(TextComponent.EMPTY); + } + } + + @Override + protected void applyValue() {} +} \ No newline at end of file diff --git a/forge/fg-6.0/1.17.1/src/main/resources/assets/minegasm/textures/logo.png b/forge/fg-6.0/1.17.1/src/main/resources/assets/minegasm/textures/logo.png new file mode 100644 index 0000000..63eaa64 Binary files /dev/null and b/forge/fg-6.0/1.17.1/src/main/resources/assets/minegasm/textures/logo.png differ diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java index 4b1fae4..762d3b1 100644 --- a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java @@ -1,17 +1,22 @@ package com.therainbowville.minegasm.client; import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.common.*; import com.therainbowville.minegasm.config.ClientConfig; import com.therainbowville.minegasm.config.MinegasmConfig; + import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; -import net.minecraft.network.chat.Component; +import net.minecraft.world.phys.Vec3; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.ToolAction; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.network.chat.Component; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.EntityJoinLevelEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; @@ -20,150 +25,114 @@ import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; + import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.*; import java.util.stream.Collectors; - +import java.lang.Thread; @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ClientEventHandler { private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); - private static final int TICKS_PER_SECOND = 20; + private static int tickCounter = -1; private static int clientTickCounter = -1; - private static final double[] state = new double[1200]; private static boolean paused = false; private static UUID playerId = null; - - - private static void clearState() { - tickCounter = -1; - clientTickCounter = -1; - Arrays.fill(state, 0); - paused = false; + + private static Map vibrationStates = new HashMap(); + + static { + vibrationStates.put("advancement", new VibrationStateAdvancement()); + vibrationStates.put("attack", new VibrationStateAttack()); + vibrationStates.put("fish", new VibrationStateFish()); + vibrationStates.put("hurt", new VibrationStateHurt()); + vibrationStates.put("mine", new VibrationStateMine()); + vibrationStates.put("place", new VibrationStatePlace()); + vibrationStates.put("harvest", new VibrationStateHarvest((VibrationStateMine)vibrationStates.get("mine"))); + vibrationStates.put("vitality", new VibrationStateVitality()); + vibrationStates.put("xpChange", new VibrationStateXpChange()); + vibrationStates.put("generic", new VibrationStateClient()); } - private static int getStateCounter() { - return tickCounter / 20; + public static void afterConnect() + { + //setState(getStateCounter(), 5); + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); } - - private static void setState(int start, int duration, int intensity, boolean decay) { - if (duration <= 0) { - return; + + private static double getIntensity() + { + double intensity = 0; + for (Map.Entry state : vibrationStates.entrySet()) + { + intensity = Math.max(intensity, state.getValue().getIntensity()); +// LOGGER.info(state.getKey() + ": " + state.getValue().getIntensity()); + } - - if (decay) { - int safeDuration = Math.max(0, duration - 2); - for (int i = 0; i < safeDuration; i++) { - setState(start+i, intensity); - } - setState(start+safeDuration, intensity/2); - setState(start+safeDuration+1, intensity/4); - } else { - for (int i = 0; i < duration; i++) { - setState(start+i, intensity); - } + return intensity / 100; + } + + private static void tickAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.onTick(); } } - - private static void setState(int counter, int intensity) { - boolean accumulate = false; //XXX reserved for future use - setState(counter, intensity, accumulate); + + private static void resetAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.resetState(); + } } - private static void setState(int counter, int intensity, boolean accumulate) { - int safeCounter = counter % state.length; - if (accumulate) { - state[safeCounter] = Math.min(1.0, state[safeCounter] + (intensity / 100.0)); - } else { - state[safeCounter] = Math.min(1.0, Math.max(state[safeCounter], (intensity / 100.0))); + private static boolean isPlayer(Entity entity){ + try { + if (entity instanceof Player && !(entity instanceof FakePlayer)) { + Player player = (Player) entity;; + UUID uuid = player.getGameProfile().getId(); + return uuid.equals(playerId); } + } catch (Throwable e) { + LOGGER.throwing(e); + } + return false; } - private static int getIntensity(String type) { - Map normal = new HashMap<>(); - normal.put("attack", 60); - normal.put("hurt", 0); - normal.put("mine", 80); - normal.put("xpChange", 100); - normal.put("harvest", 0); - normal.put("vitality", 0); - - Map masochist = new HashMap<>(); - masochist.put("attack", 0); - masochist.put("hurt", 100); - masochist.put("mine", 0); - masochist.put("xpChange", 0); - masochist.put("harvest", 0); - masochist.put("vitality", 10); - - Map hedonist = new HashMap<>(); - hedonist.put("attack", 60); - hedonist.put("hurt", 10); - hedonist.put("mine", 80); - hedonist.put("xpChange", 100); - hedonist.put("harvest", 20); - hedonist.put("vitality", 10); - - Map custom = new HashMap<>(); - custom.put("attack", MinegasmConfig.attackIntensity); - custom.put("hurt", MinegasmConfig.hurtIntensity); - custom.put("mine", MinegasmConfig.mineIntensity); - custom.put("xpChange", MinegasmConfig.xpChangeIntensity); - custom.put("harvest", MinegasmConfig.harvestIntensity); - custom.put("vitality", MinegasmConfig.vitalityIntensity); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - return masochist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.HEDONIST)) { - return hedonist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.CUSTOM)) { - return custom.get(type); - } else { - return normal.get(type); - } + private static void clearState() { + tickCounter = -1; + clientTickCounter = -1; + paused = false; + resetAll(); } @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { try { - if (event.phase == TickEvent.Phase.END ) { - Player player = event.player;; - UUID uuid = player.getGameProfile().getId(); - - float playerHealth = player.getHealth(); - float playerFoodLevel = player.getFoodData().getFoodLevel(); - - tickCounter = (tickCounter + 1) % (20 * (60 * TICKS_PER_SECOND)); // 20 min day cycle - - if (tickCounter % TICKS_PER_SECOND == 0) { // every 1 sec - if (uuid.equals(playerId)) { - int stateCounter = getStateCounter(); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - if (playerHealth > 0 && playerHealth <= 1) { - setState(stateCounter, getIntensity("vitality")); - } - } else if (playerHealth >= 20 && playerFoodLevel >= 20) { - setState(stateCounter, getIntensity("vitality")); - } - - double newVibrationLevel = state[stateCounter]; - state[stateCounter] = 0; - - LOGGER.trace("Tick " + stateCounter + ": " + newVibrationLevel); - - if (ToyController.currentVibrationLevel != newVibrationLevel) { - ToyController.setVibrationLevel(newVibrationLevel); - } - } + if (event.phase == TickEvent.Phase.END && isPlayer(event.player)) { + Player player = event.player; + + tickCounter = (tickCounter + 1) % 100; + + + if (tickCounter % MinegasmConfig.tickFrequency == 0) // TODO: Add ticks per second config option (Default: Every tick) + { + tickAll(); + + ((VibrationStateVitality)vibrationStates.get("vitality")).onTick(player); + ((VibrationStateFish)vibrationStates.get("fish")).onTick(player); + + double newVibrationLevel = getIntensity(); + + if (ToyController.currentVibrationLevel != newVibrationLevel) + ToyController.setVibrationLevel(newVibrationLevel); } - if (tickCounter % (5 * TICKS_PER_SECOND) == 0) { // 5 secs - LOGGER.debug("Health: " + playerHealth); - LOGGER.debug("Food: " + playerFoodLevel); - } } } catch (Throwable e) { LOGGER.throwing(e); @@ -195,19 +164,10 @@ public static void onClientTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public static void onAttack(AttackEntityEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("attack"), true); - } + if (isPlayer(event.getEntity())) + { + ((VibrationStateAttack)vibrationStates.get("attack")).onAttack(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -219,98 +179,37 @@ public static void onCriticalHit(CriticalHitEvent event) @SubscribeEvent public static void onHurt(LivingHurtEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("hurt"), true); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getEntity())) + { + ((VibrationStateHurt)vibrationStates.get("hurt")).onHurt(); } } @SubscribeEvent - public static void onDeath(LivingDeathEvent event) + public static void onBreak(BlockEvent.BreakEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - ToyController.setVibrationLevel(0); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateMine)vibrationStates.get("mine")).onBreak(event.getState()); } - } catch (Throwable e) { - LOGGER.throwing(e); } - } - + + // Triggers when player starts to break block @SubscribeEvent public static void onHarvest(PlayerEvent.HarvestCheck event) { - try { - Player player = event.getEntity();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getTargetBlock(); - Block block = blockState.getBlock(); - - // ToolType. AXE, HOE, PICKAXE, SHOVEL - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - LOGGER.debug("Harvest: tool: " + - "?" + - " can harvest? " + event.canHarvest() + " hardness: " + blockHardness); - - int intensity = Math.toIntExact(Math.round((getIntensity("harvest") / 100.0 * (blockHardness / 50.0)) * 100)); - - if (event.canHarvest()) { - setState(getStateCounter(), 1, intensity, false); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getEntity())) + { + ((VibrationStateHarvest)vibrationStates.get("harvest")).onHarvest(); } } - + @SubscribeEvent - public static void onBreak(BlockEvent.BreakEvent event) - { - try { - Player player = event.getPlayer();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getState(); - Block block = blockState.getBlock(); - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - - LOGGER.info("Breaking: " + block.toString()); - - ItemStack mainhandItem = event.getPlayer().getMainHandItem(); - boolean usingAppropriateTool = mainhandItem.isCorrectToolForDrops(blockState); - List toolCan = ToolAction.getActions().stream().filter(a -> mainhandItem.canPerformAction(a)).collect(Collectors.toList()); - LOGGER.debug("mainhand: " + mainhandItem + " [" + toolCan + "]"); - LOGGER.debug("using pickaxe: " + mainhandItem.toString() + ", using appropriate tool: " + usingAppropriateTool); - - if (toolCan.contains(ToolAction.get("AXE")) && usingAppropriateTool) { - int duration = Math.max(1, Math.min(5, Math.toIntExact(Math.round(Math.ceil(Math.log(blockHardness + 0.5)))))); - int intensity = Math.toIntExact(Math.round((getIntensity("mine") / 100.0 * (blockHardness / 50.0)) * 100)); - setState(getStateCounter(), duration, intensity, true); - } - - LOGGER.info("XP to drop: " + event.getExpToDrop()); + public static void onPlace(BlockEvent.EntityPlaceEvent event){ + if (isPlayer(event.getEntity())) + { + ((VibrationStatePlace)vibrationStates.get("place")).onPlace(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -328,22 +227,20 @@ public static void onXpPickup(PlayerXpEvent.PickupXp event) @SubscribeEvent public static void onXpChange(PlayerXpEvent.XpChange event) { - try { - Player player = event.getEntity();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - int xpChange = event.getAmount(); - long duration = Math.round(Math.ceil(Math.log(xpChange + 0.5))); - - LOGGER.info("XP CHANGE: " + xpChange); - LOGGER.debug("duration: " + duration); - - setState(getStateCounter(), Math.toIntExact(duration), getIntensity("xpChange"), true); + if (isPlayer(event.getEntity())) + { + ((VibrationStateXpChange)vibrationStates.get("xpChange")).onXpChange(((Player)event.getEntity()).totalExperience, event.getAmount()); } - } catch (Throwable e) { - LOGGER.throwing(e); } + + + @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event) + { + if (isPlayer(event.getEntity())) + { + ((VibrationStateAdvancement)vibrationStates.get("advancement")).onAdvancement(event); + } } @SubscribeEvent @@ -380,27 +277,32 @@ public static void onWorldEntry(EntityJoinLevelEvent event) { if( !entity.level.isClientSide() ) { return; } + + if (ToyController.isConnected) return; if (entity instanceof Player) { LOGGER.info("Player respawn world: " + entity.toString()); - - try { + + new Thread(()-> { try { Player player = (Player) entity; UUID uuid = player.getGameProfile().getId(); - + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + LOGGER.info("Stealth: " + MinegasmConfig.stealth); if (ToyController.connectDevice()) { - setState(getStateCounter(), 5); - player.displayClientMessage(Component.literal(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); - } else { + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); + if (!MinegasmConfig.stealth){ + player.displayClientMessage(Component.literal(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); + } + } else if (!MinegasmConfig.stealth){ player.displayClientMessage(Component.literal(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start\n%s", ToyController.getLastErrorMessage())), false); } playerId = uuid; } } catch (Throwable e) { LOGGER.throwing(e); - } + }}).start(); } } } diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java index 2e6f091..4577128 100644 --- a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/client/ToyController.java @@ -10,10 +10,16 @@ import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.Executors; public class ToyController { private static final Logger LOGGER = LogManager.getLogger(); - private static final ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); + private static ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); private static ButtplugClientDevice device = null; private static boolean shutDownHookAdded = false; public static String lastErrorMessage = ""; @@ -24,9 +30,28 @@ public static boolean connectDevice() { try { device = null; client.disconnect(); + LOGGER.info("URL: " + MinegasmConfig.serverUrl); - client.connect(new URI(MinegasmConfig.serverUrl)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new Callable() { + public Void call() throws Exception { + client.connect(new URI(MinegasmConfig.serverUrl)); + return null; + } + }); + + try + { + future.get(3, TimeUnit.SECONDS); + } catch (TimeoutException e) { + future.cancel(true); + client = new ButtplugClientWSClient("Minegasm"); + throw new TimeoutException("Could not find WebSocket"); + } finally { + executor.shutdownNow(); + } + client.startScanning(); Thread.sleep(5000); diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java new file mode 100644 index 0000000..0ae06df --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java @@ -0,0 +1,128 @@ +package com.therainbowville.minegasm.common; + +import java.util.Map; +import java.util.HashMap; + +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Architecture inspired from https://github.com/Fyustorm/mInetiface +public abstract class AbstractVibrationState +{ + + protected static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); + protected final float streakCountdownAmount; + protected float intensity; + + protected float vibrationCountdown; + protected float vibrationFeedbackCountdown; + + protected AbstractVibrationState(float streakSeconds) + { + streakCountdownAmount = streakSeconds; + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + public void onTick() + { + if (accumulationEnabled()) + { + if (vibrationCountdown > 0) + vibrationCountdown--; + else if (intensity > 0) { + intensity = Math.max(0, intensity - 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + vibrationCountdown = Math.max(0, vibrationCountdown - 1); + } + + vibrationFeedbackCountdown = Math.max(0, vibrationFeedbackCountdown - 1); + } + + public void resetState() + { + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + protected static boolean accumulationEnabled() + { + return MinegasmConfig.mode.equals(ClientConfig.GameplayMode.ACCUMULATION); + } + + public static int getIntensity(String type) { + Map normal = new HashMap<>(); + normal.put("attack", 60); + normal.put("hurt", 0); + normal.put("mine", 80); + normal.put("place", 20); + normal.put("xpChange", 100); + normal.put("harvest", 10); + normal.put("fishing", 50); + normal.put("vitality", 0); + normal.put("advancement", 100); + + Map masochist = new HashMap<>(); + masochist.put("attack", 0); + masochist.put("hurt", 100); + masochist.put("mine", 0); + masochist.put("place", 0); + masochist.put("xpChange", 0); + masochist.put("fishing", 0); + masochist.put("harvest", 0); + masochist.put("vitality", 10); + masochist.put("advancement", 0); + + Map hedonist = new HashMap<>(); + hedonist.put("attack", 60); + hedonist.put("hurt", 10); + hedonist.put("mine", 80); + hedonist.put("place", 20); + hedonist.put("xpChange", 100); + hedonist.put("fishing", 50); + hedonist.put("harvest", 20); + hedonist.put("vitality", 10); + hedonist.put("advancement", 100); + + Map accumulation = new HashMap<>(); + accumulation.put("attack", 1); + accumulation.put("hurt", 1); + accumulation.put("mine", 1); + accumulation.put("place", 1); + accumulation.put("xpChange", 1); + accumulation.put("fishing", 50); + accumulation.put("harvest", 10); + accumulation.put("vitality", 0); + accumulation.put("advancement", 1); + + Map custom = new HashMap<>(); + custom.put("attack", MinegasmConfig.attackIntensity); + custom.put("hurt", MinegasmConfig.hurtIntensity); + custom.put("mine", MinegasmConfig.mineIntensity); + custom.put("place", MinegasmConfig.placeIntensity); + custom.put("xpChange", MinegasmConfig.xpChangeIntensity); + custom.put("fishing", MinegasmConfig.fishingIntensity); + custom.put("harvest", MinegasmConfig.harvestIntensity); + custom.put("vitality", MinegasmConfig.vitalityIntensity); + custom.put("advancement", MinegasmConfig.advancementIntensity); + + + return switch (MinegasmConfig.mode) + { + case NORMAL -> normal.get(type); + case MASOCHIST -> masochist.get(type); + case HEDONIST -> hedonist.get(type); + case ACCUMULATION -> accumulation.get(type); + case CUSTOM -> custom.get(type); + }; + } + + public abstract int getIntensity(); +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/Minegasm.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/Minegasm.java index 82e8cf7..32b71ba 100644 --- a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/Minegasm.java +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/Minegasm.java @@ -1,13 +1,16 @@ package com.therainbowville.minegasm.common; -import com.therainbowville.minegasm.config.ConfigHolder; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.client.ConfigScreenHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.therainbowville.minegasm.config.ConfigHolder; +import com.therainbowville.minegasm.config.ConfigHelper; + @Mod(Minegasm.MOD_ID) public class Minegasm { @@ -21,5 +24,7 @@ public Minegasm() { context.registerConfig(ModConfig.Type.SERVER, ConfigHolder.SERVER_SPEC); MinecraftForge.EVENT_BUS.register(this); + + ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, ConfigHelper::createConfigScreenFactory); } } diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java new file mode 100644 index 0000000..abfa9c5 --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java @@ -0,0 +1,47 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.advancements.FrameType; +import net.minecraft.advancements.Advancement; +import net.minecraftforge.event.entity.player.AdvancementEvent; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAdvancement extends AbstractVibrationState +{ + public VibrationStateAdvancement() + { + super(0); + } + + public void onAdvancement(AdvancementEvent event) + { + if (getIntensity("advancement") == 0) return; + try { + LOGGER.info("Advancement Event: " + event); + Advancement advancement = event.getAdvancement(); + if (advancement == null) return; + FrameType type = advancement.getDisplay().getFrame(); + int duration = switch (type) { + case TASK -> 5; + case GOAL -> 7; + case CHALLENGE -> 10; + }; + + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("advancement") + 20); + else if (vibrationCountdown > 0) + return getIntensity("advancement"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java new file mode 100644 index 0000000..acd0375 --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAttack extends AbstractVibrationState +{ + public VibrationStateAttack() + { + super(3); + } + + public void onAttack() + { + if (getIntensity("attack") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * 0; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("attack") + 20); + else if (vibrationCountdown > 0) + return getIntensity("attack"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java new file mode 100644 index 0000000..c952b68 --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java @@ -0,0 +1,24 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateClient extends AbstractVibrationState +{ + public VibrationStateClient() + { + super(0); + } + + public void setVibration(int intensity, int durationSeconds) + { + intensity = intensity; + vibrationCountdown = durationSeconds * MinegasmConfig.ticksPerSecond; + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return Math.toIntExact(Math.round(intensity)); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java new file mode 100644 index 0000000..61e1866 --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateFish extends AbstractVibrationState +{ + public VibrationStateFish() + { + super(0); + } + + public void onTick(Player player) + { + if (player.fishing != null) + { + Vec3 vector = player.fishing.getDeltaMovement(); + double x = vector.x(); + double y = vector.y(); + double z = vector.z(); + if (y < -0.075 && !player.level.getFluidState(player.fishing.blockPosition()).isEmpty() && x == 0 && z == 0) + { + vibrationCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + LOGGER.info("Fishing!"); + } + } + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return getIntensity("fishing"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java new file mode 100644 index 0000000..6b373cd --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java @@ -0,0 +1,32 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHarvest extends AbstractVibrationState +{ + private VibrationStateMine mineState; + + public VibrationStateHarvest(VibrationStateMine state) + { + super(0); + mineState = state; + } + + public void onHarvest() { + vibrationCountdown = 3; + mineState.onHarvest(); + } + + public int getIntensity() + { + if (vibrationCountdown > 0){ + if (accumulationEnabled()) + return Math.min(100, mineState.getIntensity() + 20); + else + return getIntensity("harvest"); + } + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java new file mode 100644 index 0000000..7219c5e --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java @@ -0,0 +1,36 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHurt extends AbstractVibrationState +{ + public VibrationStateHurt() + { + super(3); + } + + public void onHurt() { + if (getIntensity("hurt") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 10); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("hurt") + 20); + else if (vibrationCountdown > 0) + return getIntensity("hurt"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java new file mode 100644 index 0000000..e4c467d --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateMine extends AbstractVibrationState +{ + public VibrationStateMine() + { + super(5); + } + + public void onBreak(BlockState block) { + if (getIntensity("mine") == 0) return; + + String blockName = block.getBlock().getName().getString(); + if (accumulationEnabled()) + { + if (blockName.contains("Ore")) { + intensity = Math.min(100, intensity + 1); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + intensity = Math.min(100, intensity + .25f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + if (blockName.contains("Ore")) { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public void onHarvest() { + if (accumulationEnabled()){ + vibrationCountdown = Math.max(3, vibrationCountdown); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("mine") + 20); + else if (vibrationCountdown > 0) + return getIntensity("mine"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java new file mode 100644 index 0000000..aee4ebf --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java @@ -0,0 +1,35 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStatePlace extends AbstractVibrationState +{ + public VibrationStatePlace() + { + super(5); + } + + public void onPlace() { + if (getIntensity("place") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + .5f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("place") + 20); + else if (vibrationCountdown > 0) + return getIntensity("place"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java new file mode 100644 index 0000000..5824f8f --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java @@ -0,0 +1,62 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; + +import com.therainbowville.minegasm.config.MinegasmConfig; +import com.therainbowville.minegasm.config.ClientConfig; + +public class VibrationStateVitality extends AbstractVibrationState +{ + private int intensityCooldown; + private boolean targetMet; + + public VibrationStateVitality() + { + super(1); + intensityCooldown = 0; + targetMet = false; + } + + public void onTick(Player player) + { + float playerHealth = player.getHealth(); + float playerFoodLevel = player.getFoodData().getFoodLevel(); + + if ((MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth > 0 && playerHealth <= 1 ) + || (!MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth >= 20 && playerFoodLevel >= 20) ){ + + if (targetMet == false){ + targetMet = true; + vibrationFeedbackCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } else + targetMet = false; + +// if (accumulationEnabled() && targetMet) +// { +// if (intensityCooldown == 0) { +// intensity = Math.min(100, intensity + .1f); +// intensityCooldown = 10 * 20; +// } +// vibrationCountdown = streakCountdownAmount; +// intensityCooldown = Math.max(0, intensityCooldown - 1); +// } else + if (targetMet) { + vibrationCountdown = 1; + } + } + + public int getIntensity() + { + if (getIntensity("vitality") == 0) return 0; + + //if (accumulationEnabled()) + //return Math.toIntExact(Math.round(intensity)); + //else + if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("vitality") + 20); + else if (vibrationCountdown > 0) + return getIntensity("vitality"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java new file mode 100644 index 0000000..34b1633 --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateXpChange extends AbstractVibrationState +{ + private int lastLevel; + + public VibrationStateXpChange() + { + super(1); + lastLevel = -1; + } + + // Code adapted from https://github.com/Fyustorm/mInetiface + public void onXpChange(int level, int amount) { + if (amount == 0 || getIntensity("xpChange") == 0) + return; + + if (lastLevel == -1) { + lastLevel = level; + } + + if (lastLevel != level) { + amount *= 2; + } + + lastLevel = level; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + amount / 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + int duration = Math.toIntExact( Math.round( Math.ceil( Math.log(amount + 0.5) ) ) ); + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("xpChange") + 20); + else if (vibrationCountdown > 0) + return getIntensity("xpChange"); + else return 0; + } +} + diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java index 7bc1bc2..c3ca8ff 100644 --- a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java @@ -1,9 +1,11 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.Minecraft; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.mclanguageprovider.MinecraftModLanguageProvider; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.common.ForgeConfigSpec.IntValue; import java.util.Objects; @@ -12,19 +14,41 @@ public final class ClientConfig { final ForgeConfigSpec.BooleanValue vibrate; final ForgeConfigSpec.EnumValue mode; + final ForgeConfigSpec.BooleanValue stealth; + final ForgeConfigSpec.EnumValue tickFrequency; + final ForgeConfigSpec.IntValue attackIntensity; final ForgeConfigSpec.IntValue hurtIntensity; final ForgeConfigSpec.IntValue mineIntensity; + final ForgeConfigSpec.IntValue placeIntensity; final ForgeConfigSpec.IntValue xpChangeIntensity; + final ForgeConfigSpec.IntValue fishingIntensity; final ForgeConfigSpec.IntValue harvestIntensity; final ForgeConfigSpec.IntValue vitalityIntensity; + final ForgeConfigSpec.IntValue advancementIntensity; + + static final String DEFAULT_SERVER_URL = "ws://localhost:12345/buttplug"; + static final boolean DEFAULT_VIBRATE = true; + static final GameplayMode DEFAULT_MODE = GameplayMode.NORMAL; + static final boolean DEFAULT_STEALTH = false; + + static final int DEFAULT_ATTACK_INTENSITY = 60; + static final int DEFAULT_HURT_INTENSITY = 0; + static final int DEFAULT_MINE_INTENSITY = 80; + static final int DEFAULT_PLACE_INTENSITY = 20; + static final int DEFAULT_XP_CHANGE_INTENSITY = 100; + static final int DEFAULT_FISHING_INTENSITY = 50; + static final int DEFAULT_HARVEST_INTENSITY = 0; + static final int DEFAULT_VITALITY_INTENSITY = 0; + static final int DEFAULT_ADVANCEMENT_INTENSITY = 100; + ClientConfig(final ForgeConfigSpec.Builder builder) { builder.push("buttplug"); serverUrl = builder .translation(Minegasm.MOD_ID + ".config.serverUrl") - .define("serverUrl", "ws://localhost:12345/buttplug"); + .define("serverUrl", DEFAULT_SERVER_URL); builder.pop(); @@ -32,50 +56,92 @@ public final class ClientConfig { vibrate = builder .translation(Minegasm.MOD_ID + ".config.vibrate") - .define("vibrate", true); + .define("vibrate", DEFAULT_VIBRATE); mode = builder .translation(Minegasm.MOD_ID + ".config.mode") - .defineEnum("mode", GameplayMode.NORMAL); + .defineEnum("mode", DEFAULT_MODE); + stealth = builder + .translation(Minegasm.MOD_ID + ".config.stealth") + .define("stealth", DEFAULT_STEALTH); + + tickFrequency = builder + .translation(Minegasm.MOD_ID + ".config.mode") + .defineEnum("tickFrequency", TickFrequencyOptions.EVERY_TICK); builder.push("intensity"); attackIntensity = builder .comment("Vibration intensity when attacking on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.attack") - .defineInRange("attackIntensity", 60, 0, 100); + .defineInRange("attackIntensity", DEFAULT_ATTACK_INTENSITY, 0, 100); hurtIntensity = builder .comment("Vibration intensity when hurting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.hurt") - .defineInRange("hurtIntensity", 0, 0, 100); + .defineInRange("hurtIntensity", DEFAULT_HURT_INTENSITY, 0, 100); mineIntensity = builder .comment("Vibration intensity when mining on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.mine") - .defineInRange("mineIntensity", 80, 0, 100); + .defineInRange("mineIntensity", DEFAULT_MINE_INTENSITY, 0, 100); + + placeIntensity = builder + .comment("Vibration intensity when placing blocks on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.place") + .defineInRange("placeIntensity", DEFAULT_PLACE_INTENSITY, 0, 100); xpChangeIntensity = builder .comment("Vibration intensity when gaining XP on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.xp_change") - .defineInRange("xpChangeIntensity", 100, 0, 100); + .defineInRange("xpChangeIntensity", DEFAULT_XP_CHANGE_INTENSITY, 0, 100); + + fishingIntensity = builder + .comment("Vibration intensity when fishing on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.fishing") + .defineInRange("fishingIntensity", DEFAULT_FISHING_INTENSITY, 0, 100); harvestIntensity = builder .comment("Vibration intensity when harvesting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.harvest") - .defineInRange("harvestIntensity", 0, 0, 100); + .defineInRange("harvestIntensity", DEFAULT_HARVEST_INTENSITY, 0, 100); vitalityIntensity = builder .comment("Vibration intensity on high level of player's vitality on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.vitality") - .defineInRange("vitalityIntensity", 0, 0, 100); + .defineInRange("vitalityIntensity", DEFAULT_VITALITY_INTENSITY, 0, 100); + + advancementIntensity = builder + .comment("Vibration intensity on achieving advancement on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.advancement") + .defineInRange("advancementIntensity", DEFAULT_ADVANCEMENT_INTENSITY, 0, 100); builder.pop(); builder.pop(); } + + public void resetConfigUrl() + { + ConfigHolder.CLIENT.serverUrl.set(DEFAULT_SERVER_URL); + } + + public void resetConfigCustom() + { + ConfigHolder.CLIENT.attackIntensity.set(DEFAULT_ATTACK_INTENSITY); + ConfigHolder.CLIENT.hurtIntensity.set(DEFAULT_HURT_INTENSITY); + ConfigHolder.CLIENT.mineIntensity.set(DEFAULT_MINE_INTENSITY); + ConfigHolder.CLIENT.placeIntensity.set(DEFAULT_PLACE_INTENSITY); + ConfigHolder.CLIENT.xpChangeIntensity.set(DEFAULT_XP_CHANGE_INTENSITY); + ConfigHolder.CLIENT.fishingIntensity.set(DEFAULT_FISHING_INTENSITY); + ConfigHolder.CLIENT.harvestIntensity.set(DEFAULT_HARVEST_INTENSITY); + ConfigHolder.CLIENT.vitalityIntensity.set(DEFAULT_VITALITY_INTENSITY); + ConfigHolder.CLIENT.advancementIntensity.set(DEFAULT_ADVANCEMENT_INTENSITY); + } + public enum GameplayMode { NORMAL("gui." + Minegasm.MOD_ID + ".config.mode.normal"), MASOCHIST("gui." + Minegasm.MOD_ID + ".config.mode.masochist"), HEDONIST("gui." + Minegasm.MOD_ID + ".config.mode.hedonist"), + ACCUMULATION("gui." + Minegasm.MOD_ID + ".config.mode.accumulation"), CUSTOM("gui." + Minegasm.MOD_ID + ".config.mode.custom"); private final String translateKey; @@ -89,4 +155,37 @@ public String getTranslateKey() { return this.translateKey; } } + + public enum TickFrequencyOptions { + EVERY_TICK(1), + EVERY_OTHER_TICK(2), + EVERY_5_TICKS(5), + EVERY_10_TICKS(10), + EVERY_20_TICKS(20), + EVERY_30_TICKS(30), + EVERY_40_TICKS(40), + EVERY_50_TICKS(50); + + private int value; + + TickFrequencyOptions(int value) { + this.value = value; + } + + public int getInt() + { + return value; + } + + public static TickFrequencyOptions fromInt(int value) + { + for (TickFrequencyOptions type : values()) { + if (type.getInt() == value) { + return type; + } + } + return null; + } + } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java index 4441fb2..e51ab15 100644 --- a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java @@ -1,20 +1,79 @@ package com.therainbowville.minegasm.config; +import net.minecraftforge.client.ConfigScreenHandler; +import net.minecraftforge.common.ForgeConfigSpec; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public final class ConfigHelper { + private static final Logger LOGGER = LogManager.getLogger(); public static void bakeClient() { MinegasmConfig.serverUrl = ConfigHolder.CLIENT.serverUrl.get(); MinegasmConfig.vibrate = ConfigHolder.CLIENT.vibrate.get(); MinegasmConfig.mode = ConfigHolder.CLIENT.mode.get(); + MinegasmConfig.stealth = ConfigHolder.CLIENT.stealth.get(); + MinegasmConfig.tickFrequency = ConfigHolder.CLIENT.tickFrequency.get().getInt(); + MinegasmConfig.ticksPerSecond = Math.max(0, 20f / MinegasmConfig.tickFrequency); + MinegasmConfig.attackIntensity = ConfigHolder.CLIENT.attackIntensity.get(); MinegasmConfig.hurtIntensity = ConfigHolder.CLIENT.hurtIntensity.get(); MinegasmConfig.mineIntensity = ConfigHolder.CLIENT.mineIntensity.get(); + MinegasmConfig.placeIntensity = ConfigHolder.CLIENT.placeIntensity.get(); MinegasmConfig.xpChangeIntensity = ConfigHolder.CLIENT.xpChangeIntensity.get(); + MinegasmConfig.fishingIntensity = ConfigHolder.CLIENT.fishingIntensity.get(); MinegasmConfig.harvestIntensity = ConfigHolder.CLIENT.harvestIntensity.get(); MinegasmConfig.vitalityIntensity = ConfigHolder.CLIENT.vitalityIntensity.get(); + MinegasmConfig.advancementIntensity = ConfigHolder.CLIENT.advancementIntensity.get(); } public static void bakeServer() { } + + public static void saveClient() + { + try{ + + MinegasmConfigBuffer buffer = new MinegasmConfigBuffer(); + +// Field[] fields = MinegasmConfigBuffer.class.getFields(); + +// for (Field field : fields) +// { +// Field configField = ConfigHolder.CLIENT.getClass().getDeclaredField(field.getName()); // Get Corisponding Field in CLIENT +// Class configFieldClass = configField.getType(); // Get the configField Class +// Method method = configFieldClass.getMethod("set", Object.class); +// LOGGER.info(method); +// method.invoke(configField.get(ConfigHolder.CLIENT), field.get(buffer)); +// } + + ConfigHolder.CLIENT.serverUrl.set(buffer.serverUrl); + ConfigHolder.CLIENT.vibrate.set(buffer.vibrate); + ConfigHolder.CLIENT.mode.set(buffer.mode); + ConfigHolder.CLIENT.stealth.set(buffer.stealth); + ConfigHolder.CLIENT.tickFrequency.set(ClientConfig.TickFrequencyOptions.fromInt(buffer.tickFrequency)); + + ConfigHolder.CLIENT.attackIntensity.set(buffer.attackIntensity); + ConfigHolder.CLIENT.hurtIntensity.set(buffer.hurtIntensity); + ConfigHolder.CLIENT.mineIntensity.set(buffer.mineIntensity); + ConfigHolder.CLIENT.placeIntensity.set(buffer.placeIntensity); + ConfigHolder.CLIENT.xpChangeIntensity.set(buffer.xpChangeIntensity); + ConfigHolder.CLIENT.fishingIntensity.set(buffer.fishingIntensity); + ConfigHolder.CLIENT.harvestIntensity.set(buffer.harvestIntensity); + ConfigHolder.CLIENT.vitalityIntensity.set(buffer.vitalityIntensity); + ConfigHolder.CLIENT.advancementIntensity.set(buffer.advancementIntensity); + } catch (Throwable e) + { + LOGGER.info(e); + } + } + + public static ConfigScreenHandler.ConfigScreenFactory createConfigScreenFactory() { + return new ConfigScreenHandler.ConfigScreenFactory((minecraft, screen) -> new ConfigScreen(screen)); + } } \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java index b422dfa..7687547 100644 --- a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java @@ -29,4 +29,5 @@ public static ClientConfig getClientInstance() { public static ServerConfig getServerInstance() { return SERVER; } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java new file mode 100644 index 0000000..d8d2b47 --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java @@ -0,0 +1,348 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraftforge.client.gui.widget.ForgeSlider; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Component; +import net.minecraftforge.event.TickEvent; +import net.minecraft.client.Minecraft; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.client.ToyController; +import com.therainbowville.minegasm.client.ClientEventHandler; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import java.lang.reflect.Field; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.function.IntConsumer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + EditBox wsHost = null; + + public ConfigScreen(Screen previous) { + super(Component.literal("Minegasm Config")); + this.previous = previous; + pauseMenu = false; + } + + public ConfigScreen(Screen previous, boolean pause) { + super(Component.literal("Minegasm Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + wsHost = new EditBox(Minecraft.getInstance().font, this.width / 2 - 100, this.height / 6, 200, 20, null); + wsHost.setValue(MinegasmConfig.serverUrl); + this.addRenderableWidget(wsHost); + + wsHost.setResponder(s -> { + LOGGER.info(s); + MinegasmConfig.serverUrl = s; + }); + + this.addRenderableWidget(new Button( + this.width / 2 - 155, this.height / 6 + 25, 150, 20, + Component.literal("Reset Server Url"), button -> { + ConfigHolder.getClientInstance().resetConfigUrl(); + MinegasmConfig.serverUrl = ConfigHolder.getClientInstance().serverUrl.get(); + wsHost.setValue(MinegasmConfig.serverUrl); + } + )); + + PlainTextLabel connectResponse = new PlainTextLabel(this.width / 2 - 155, this.height / 6 + 50, 310, 15, Component.literal("" + ChatFormatting.GREEN)); + + this.addRenderableWidget(connectResponse); + + Button reconnectButton = new Button( + this.width / 2 + 5, this.height / 6 + 25, 150, 20, + Component.literal("Reconnect"), button -> { + button.active = false; + connectResponse.setValue("Connecting"); + new Thread(() -> { + if (ToyController.connectDevice()) { + ClientEventHandler.afterConnect(); + button.active = true; + connectResponse.setValue(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())); + } else { + button.active = true; + connectResponse.setValue(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start: %s", ToyController.getLastErrorMessage())); + } + + }).start(); + } + ); + this.addRenderableWidget(reconnectButton); + + reconnectButton.active = pauseMenu; + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.vibrate) + .create(this.width / 2 - 155, this.height / 6 + 25 * 3, 150, 20, + Component.literal("Vibration"), (button, value) -> MinegasmConfig.vibrate = value)); + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.stealth) + .create(this.width / 2 + 5, this.height / 6 + 25 * 3, 150, 20, + Component.literal("Stealth"), (button, value) -> MinegasmConfig.stealth = value)); + + this.addRenderableWidget( + CycleButton.builder((ClientConfig.GameplayMode mode) -> + Component.literal(switch (mode) { + case NORMAL -> "Normal"; + case MASOCHIST -> "Masochist"; + case HEDONIST -> "Hedonist"; + case ACCUMULATION -> "Accumulation"; + case CUSTOM -> "Custom"; + })) + .withValues(ClientConfig.GameplayMode.NORMAL, ClientConfig.GameplayMode.MASOCHIST, ClientConfig.GameplayMode.HEDONIST, ClientConfig.GameplayMode.ACCUMULATION, ClientConfig.GameplayMode.CUSTOM) + .withInitialValue(MinegasmConfig.mode) + .create(this.width / 2 - 155, this.height / 6 + 25 * 4, 150, 20, + Component.literal("Mode"), (button, value) -> { + MinegasmConfig.mode = value; + }) + ); + + this.addRenderableWidget(new Button( + this.width / 2 + 5, this.height / 6 + 25 * 4, 150, 20, + Component.literal("Edit Custom Settings"), button -> minecraft.setScreen(new CustomModeConfigScreen(this, pauseMenu)))); + + this.addRenderableWidget( + CycleButton.builder((Integer tickFrequency) -> + Component.literal(switch (tickFrequency) { + case 1 -> "Every Tick"; + case 2 -> "Every Other Tick"; + case 5 -> "Every 5 Ticks"; + case 10 -> "Every 10 Ticks"; + case 20 -> "Every Second"; + default -> "Every " + Float.toString(tickFrequency / 20f)+ " Seconds"; + })) + .withValues(1, 2, 5, 10, 20, 30, 40, 50) + .withInitialValue(MinegasmConfig.tickFrequency) + .create(this.width / 2 - 100, this.height / 6 + 25 * 5, 200, 20, + Component.literal("Tick Frequency"), (button, value) -> { + MinegasmConfig.tickFrequency = value; + MinegasmConfig.ticksPerSecond = Math.max(0, 20f / MinegasmConfig.tickFrequency); + LOGGER.info("TPS: " + MinegasmConfig.ticksPerSecond); + } + ) + ); + + this.addRenderableWidget(new Button( + this.width / 2 - 100, this.height - 27, 200, 20, + CommonComponents.GUI_DONE, button -> this.onClose())); + + + } + + @Override + public void tick() { + super.tick(); + + // Add ticking logic for EditBox in editBox + if (this.wsHost != null) + this.wsHost.tick(); + } + + @Override + public void onClose() { + PlainTextLabel.setValue(""); + this.minecraft.setScreen(previous); + MinegasmConfig.save(); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(0); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } + + class PlainTextLabel extends AbstractWidget { + + private static Component text = Component.literal(""); + private int x; + private int y; + + public PlainTextLabel(int x, int y, int width, int height, Component text) { + super(x, y, width, height, text); + this.x = x; + this.y = y; + } + + public static void setValue(String value) + { + text = Component.literal(value); + } + + @Override + public void updateNarration(NarrationElementOutput output) { + defaultButtonNarrationText(output); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (text == null || text.getString().isEmpty()) + return; + +// RenderSystem.setShaderColor(1, 1, 1, 1); +// Minecraft.getInstance().font.draw(poseStack, text.getString(), x, y, 0xFFFFFF); + drawCenteredString(poseStack, Minecraft.getInstance().font, text.getString(), Minecraft.getInstance().screen.width / 2, this.y + this.height / 4, 0xFFFFFF); + } + } + +} + +class CustomModeConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + + public CustomModeConfigScreen(Screen previous) { + super(Component.literal("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = false; + } + + public CustomModeConfigScreen(Screen previous, boolean pause) { + super(Component.literal("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + try{ + this.addRenderableWidget(new Button( + this.width / 2 + 5, this.height - 27, 150, 20, + CommonComponents.GUI_DONE, button -> this.onClose())); + + IntensitiySliderBar.sliders.clear(); + + // Attack + this.addRenderableWidget(new IntensitiySliderBar(this, "Attack: ", MinegasmConfig.class.getField("attackIntensity"))); + + // Hurt + this.addRenderableWidget(new IntensitiySliderBar(this, "Hurt: ", MinegasmConfig.class.getField("hurtIntensity"))); + + // Mine + this.addRenderableWidget(new IntensitiySliderBar(this, "Mine: ", MinegasmConfig.class.getField("mineIntensity"))); + + // Place + this.addRenderableWidget(new IntensitiySliderBar(this, "Place: ", MinegasmConfig.class.getField("placeIntensity"))); + + // XP Change + this.addRenderableWidget(new IntensitiySliderBar(this, "XP Change: ", MinegasmConfig.class.getField("xpChangeIntensity"))); + + // Fishing + this.addRenderableWidget(new IntensitiySliderBar(this, "Fishing: ", MinegasmConfig.class.getField("fishingIntensity"))); + + // Harvest + this.addRenderableWidget(new IntensitiySliderBar(this, "Harvest: ", MinegasmConfig.class.getField("harvestIntensity"))); + + // Vitality + this.addRenderableWidget(new IntensitiySliderBar(this, "Vitality: ", MinegasmConfig.class.getField("vitalityIntensity"))); + + // Advancement + this.addRenderableWidget(new IntensitiySliderBar(this, "Advancement: ", MinegasmConfig.class.getField("advancementIntensity"))); + + this.addRenderableWidget(new Button( + this.width / 2 - 155, this.height - 27, 150, 20, + Component.literal("Reset Values"), button -> { + ConfigHolder.getClientInstance().resetConfigCustom(); + IntensitiySliderBar.refreshAllValues(); + } + )); + + + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + @Override + public void onClose() { + IntensitiySliderBar.sliders.clear(); + this.minecraft.setScreen(previous); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(0); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } + + private class IntensitiySliderBar extends ForgeSlider + { + public static ArrayList sliders = new ArrayList(); + private Field fieldReference; + + IntensitiySliderBar(CustomModeConfigScreen parent, String prefix, Field field) throws Exception + { + super( parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155), // x pos + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2), // y pos + 150, 20, // Width, height + Component.literal(prefix), // Prefix + Component.literal(""), // Suffix + 0, 100, field.getInt(null), 1, 1, true); // Min, Max, Default value, stepsize, percision, drawstring + fieldReference = field; +// LOGGER.info("S: " + sliders.size() + " X: " + parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155) + " Y: " + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2)); + sliders.add(this); + } + + @Override + public void applyValue() + { +// LOGGER.info("applyValue"); + //responder.accept(this.getValueInt()); + try { + fieldReference.set(null, this.getValueInt()); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public static void refreshAllValues() + { + for (IntensitiySliderBar slider : sliders) + { + slider.refreshValue(); + } + } + + private void refreshValue() + { + try { + this.setValue(fieldReference.getInt(null)); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java index 52965d5..cb0e2fd 100644 --- a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java @@ -18,13 +18,20 @@ public class MinegasmConfig { public static String serverUrl; public static boolean vibrate; - public static Enum mode = ClientConfig.GameplayMode.NORMAL; + public static ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public static boolean stealth; + public static int tickFrequency; + public static float ticksPerSecond; + public static int attackIntensity; public static int hurtIntensity; public static int mineIntensity; + public static int placeIntensity; public static int xpChangeIntensity; + public static int fishingIntensity; public static int harvestIntensity; public static int vitalityIntensity; + public static int advancementIntensity; // Server // -- none at the moment @@ -41,4 +48,49 @@ public static void onModConfigEvent(final ModConfigEvent event) { LOGGER.debug("Baked server config"); } } + + public static void save() + { + ConfigHelper.saveClient(); + } + } + +class MinegasmConfigBuffer +{ + public String serverUrl; + + public boolean vibrate; + public ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public boolean stealth; + public int tickFrequency; + + public int attackIntensity; + public int hurtIntensity; + public int mineIntensity; + public int placeIntensity; + public int xpChangeIntensity; + public int fishingIntensity; + public int harvestIntensity; + public int vitalityIntensity; + public int advancementIntensity; + + MinegasmConfigBuffer() + { + this.serverUrl = MinegasmConfig.serverUrl; + this.vibrate = MinegasmConfig.vibrate; + this.mode = MinegasmConfig.mode; + this.stealth = MinegasmConfig.stealth; + this.tickFrequency = MinegasmConfig.tickFrequency; + + this.attackIntensity = MinegasmConfig.attackIntensity; + this.hurtIntensity = MinegasmConfig.hurtIntensity; + this.mineIntensity = MinegasmConfig.mineIntensity; + this.placeIntensity = MinegasmConfig.placeIntensity; + this.xpChangeIntensity = MinegasmConfig.xpChangeIntensity; + this.fishingIntensity = MinegasmConfig.fishingIntensity; + this.harvestIntensity = MinegasmConfig.harvestIntensity; + this.vitalityIntensity = MinegasmConfig.vitalityIntensity; + this.advancementIntensity = MinegasmConfig.advancementIntensity; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java new file mode 100644 index 0000000..fd51d2b --- /dev/null +++ b/forge/fg-6.0/1.19.2/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java @@ -0,0 +1,131 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.PauseScreen; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ScreenEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.commons.lang3.mutable.MutableObject; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Adapted from https://github.com/Creators-of-Create/Create/ +public class PauseMenuButton extends Button +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static ResourceLocation LOGO = new ResourceLocation(Minegasm.MOD_ID, "textures/logo.png"); + + int xPos; + int yPos; + + public PauseMenuButton(int x, int y) { + super(x, y, 20, 20, Component.literal(""), PauseMenuButton::clicked); + xPos = x; + yPos = y; + } + + @Override + public void renderBg(PoseStack mstack, Minecraft mc, int mouseX, int mouseY) { + mstack.pushPose(); + mstack.translate(xPos + width / 2 - (64 * 0.25f) / 2, yPos + height / 2 - (64 * 0.25f) / 2, 0); + mstack.scale(0.25f, 0.25f, 1); + RenderSystem.setShaderTexture(0, LOGO); + GuiComponent.blit(mstack, 0, 0, 0, 0, 0, 64, 64, 64, 64); + mstack.popPose(); + } + + public static void clicked(Button button) + { + Minecraft.getInstance().setScreen(new ConfigScreen(Minecraft.getInstance().screen, true)); + } + + public static class SingleMenuRow { + public final String left, right; + public SingleMenuRow(String left, String right) { + this.left = I18n.get(left); + this.right = I18n.get(right); + } + public SingleMenuRow(String center) { + this(center, center); + } + } + + public static class MenuRows { + public static final MenuRows MAIN_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.singleplayer"), + new SingleMenuRow("menu.multiplayer"), + new SingleMenuRow("fml.menu.mods", "menu.online"), + new SingleMenuRow("narrator.button.language", "narrator.button.accessibility") + )); + + public static final MenuRows INGAME_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.returnToGame"), + new SingleMenuRow("gui.advancements", "gui.stats"), + new SingleMenuRow("menu.sendFeedback", "menu.reportBugs"), + new SingleMenuRow("menu.options", "menu.shareToLan"), + new SingleMenuRow("menu.returnToMenu") + )); + + protected final List leftButtons, rightButtons; + + public MenuRows(List variants) { + leftButtons = variants.stream().map(r -> r.left).collect(Collectors.toList()); + rightButtons = variants.stream().map(r -> r.right).collect(Collectors.toList()); + } + } + + @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) + public class PauseMenuButtonScreen { + + @SubscribeEvent + public static void onGuiInit(ScreenEvent.Init event) { + if(event.getScreen() instanceof PauseScreen) { // Make sure GUI is Escape menu + MenuRows menu = MenuRows.INGAME_MENU; + int rowIdx = 3; + int offsetX = 4; + boolean onLeft = offsetX < 0; + String target = (onLeft ? menu.leftButtons : menu.rightButtons).get(rowIdx - 1); + + int offsetX_ = offsetX; + MutableObject toAdd = new MutableObject<>(null); + event.getListenersList() + .stream() + .filter(w -> w instanceof AbstractWidget) + .map(w -> (AbstractWidget) w) + .filter(w -> w.getMessage() + .getString() + .equals(target)) + .findFirst() + .ifPresent(w -> toAdd + .setValue(new PauseMenuButton(w.x + offsetX_ + (onLeft ? -20 : w.getWidth()), w.y))); + if (toAdd.getValue() != null) + event.addListener(toAdd.getValue()); + } + } + } +} diff --git a/forge/fg-6.0/1.19.2/src/main/resources/assets/minegasm/textures/logo.png b/forge/fg-6.0/1.19.2/src/main/resources/assets/minegasm/textures/logo.png new file mode 100644 index 0000000..63eaa64 Binary files /dev/null and b/forge/fg-6.0/1.19.2/src/main/resources/assets/minegasm/textures/logo.png differ diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java index cd91ba6..762d3b1 100644 --- a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java @@ -1,22 +1,22 @@ package com.therainbowville.minegasm.client; import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.common.*; import com.therainbowville.minegasm.config.ClientConfig; import com.therainbowville.minegasm.config.MinegasmConfig; + import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.telemetry.events.WorldLoadEvent; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraftforge.common.util.FakePlayer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.network.chat.Component; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.network.chat.Component; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.ToolAction; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.EntityJoinLevelEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; @@ -25,151 +25,114 @@ import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.*; import java.util.stream.Collectors; - +import java.lang.Thread; @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ClientEventHandler { private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); - private static final int TICKS_PER_SECOND = 20; + private static int tickCounter = -1; private static int clientTickCounter = -1; - private static final double[] state = new double[1200]; private static boolean paused = false; private static UUID playerId = null; - - - private static void clearState() { - tickCounter = -1; - clientTickCounter = -1; - Arrays.fill(state, 0); - paused = false; + + private static Map vibrationStates = new HashMap(); + + static { + vibrationStates.put("advancement", new VibrationStateAdvancement()); + vibrationStates.put("attack", new VibrationStateAttack()); + vibrationStates.put("fish", new VibrationStateFish()); + vibrationStates.put("hurt", new VibrationStateHurt()); + vibrationStates.put("mine", new VibrationStateMine()); + vibrationStates.put("place", new VibrationStatePlace()); + vibrationStates.put("harvest", new VibrationStateHarvest((VibrationStateMine)vibrationStates.get("mine"))); + vibrationStates.put("vitality", new VibrationStateVitality()); + vibrationStates.put("xpChange", new VibrationStateXpChange()); + vibrationStates.put("generic", new VibrationStateClient()); } - private static int getStateCounter() { - return tickCounter / 20; + public static void afterConnect() + { + //setState(getStateCounter(), 5); + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); } - - private static void setState(int start, int duration, int intensity, boolean decay) { - if (duration <= 0) { - return; + + private static double getIntensity() + { + double intensity = 0; + for (Map.Entry state : vibrationStates.entrySet()) + { + intensity = Math.max(intensity, state.getValue().getIntensity()); +// LOGGER.info(state.getKey() + ": " + state.getValue().getIntensity()); + } - - if (decay) { - int safeDuration = Math.max(0, duration - 2); - for (int i = 0; i < safeDuration; i++) { - setState(start+i, intensity); - } - setState(start+safeDuration, intensity/2); - setState(start+safeDuration+1, intensity/4); - } else { - for (int i = 0; i < duration; i++) { - setState(start+i, intensity); - } + return intensity / 100; + } + + private static void tickAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.onTick(); } } - - private static void setState(int counter, int intensity) { - boolean accumulate = false; //XXX reserved for future use - setState(counter, intensity, accumulate); + + private static void resetAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.resetState(); + } } - private static void setState(int counter, int intensity, boolean accumulate) { - int safeCounter = counter % state.length; - if (accumulate) { - state[safeCounter] = Math.min(1.0, state[safeCounter] + (intensity / 100.0)); - } else { - state[safeCounter] = Math.min(1.0, Math.max(state[safeCounter], (intensity / 100.0))); + private static boolean isPlayer(Entity entity){ + try { + if (entity instanceof Player && !(entity instanceof FakePlayer)) { + Player player = (Player) entity;; + UUID uuid = player.getGameProfile().getId(); + return uuid.equals(playerId); } + } catch (Throwable e) { + LOGGER.throwing(e); + } + return false; } - private static int getIntensity(String type) { - Map normal = new HashMap<>(); - normal.put("attack", 60); - normal.put("hurt", 0); - normal.put("mine", 80); - normal.put("xpChange", 100); - normal.put("harvest", 0); - normal.put("vitality", 0); - - Map masochist = new HashMap<>(); - masochist.put("attack", 0); - masochist.put("hurt", 100); - masochist.put("mine", 0); - masochist.put("xpChange", 0); - masochist.put("harvest", 0); - masochist.put("vitality", 10); - - Map hedonist = new HashMap<>(); - hedonist.put("attack", 60); - hedonist.put("hurt", 10); - hedonist.put("mine", 80); - hedonist.put("xpChange", 100); - hedonist.put("harvest", 20); - hedonist.put("vitality", 10); - - Map custom = new HashMap<>(); - custom.put("attack", MinegasmConfig.attackIntensity); - custom.put("hurt", MinegasmConfig.hurtIntensity); - custom.put("mine", MinegasmConfig.mineIntensity); - custom.put("xpChange", MinegasmConfig.xpChangeIntensity); - custom.put("harvest", MinegasmConfig.harvestIntensity); - custom.put("vitality", MinegasmConfig.vitalityIntensity); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - return masochist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.HEDONIST)) { - return hedonist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.CUSTOM)) { - return custom.get(type); - } else { - return normal.get(type); - } + private static void clearState() { + tickCounter = -1; + clientTickCounter = -1; + paused = false; + resetAll(); } @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { try { - if (event.phase == TickEvent.Phase.END ) { - Player player = event.player;; - UUID uuid = player.getGameProfile().getId(); - - float playerHealth = player.getHealth(); - float playerFoodLevel = player.getFoodData().getFoodLevel(); - - tickCounter = (tickCounter + 1) % (20 * (60 * TICKS_PER_SECOND)); // 20 min day cycle - - if (tickCounter % TICKS_PER_SECOND == 0) { // every 1 sec - if (uuid.equals(playerId)) { - int stateCounter = getStateCounter(); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - if (playerHealth > 0 && playerHealth <= 1) { - setState(stateCounter, getIntensity("vitality")); - } - } else if (playerHealth >= 20 && playerFoodLevel >= 20) { - setState(stateCounter, getIntensity("vitality")); - } - - double newVibrationLevel = state[stateCounter]; - state[stateCounter] = 0; - - LOGGER.trace("Tick " + stateCounter + ": " + newVibrationLevel); - - if (ToyController.currentVibrationLevel != newVibrationLevel) { - ToyController.setVibrationLevel(newVibrationLevel); - } - } + if (event.phase == TickEvent.Phase.END && isPlayer(event.player)) { + Player player = event.player; + + tickCounter = (tickCounter + 1) % 100; + + + if (tickCounter % MinegasmConfig.tickFrequency == 0) // TODO: Add ticks per second config option (Default: Every tick) + { + tickAll(); + + ((VibrationStateVitality)vibrationStates.get("vitality")).onTick(player); + ((VibrationStateFish)vibrationStates.get("fish")).onTick(player); + + double newVibrationLevel = getIntensity(); + + if (ToyController.currentVibrationLevel != newVibrationLevel) + ToyController.setVibrationLevel(newVibrationLevel); } - if (tickCounter % (5 * TICKS_PER_SECOND) == 0) { // 5 secs - LOGGER.debug("Health: " + playerHealth); - LOGGER.debug("Food: " + playerFoodLevel); - } } } catch (Throwable e) { LOGGER.throwing(e); @@ -201,19 +164,10 @@ public static void onClientTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public static void onAttack(AttackEntityEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("attack"), true); - } + if (isPlayer(event.getEntity())) + { + ((VibrationStateAttack)vibrationStates.get("attack")).onAttack(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -225,98 +179,37 @@ public static void onCriticalHit(CriticalHitEvent event) @SubscribeEvent public static void onHurt(LivingHurtEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("hurt"), true); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getEntity())) + { + ((VibrationStateHurt)vibrationStates.get("hurt")).onHurt(); } } @SubscribeEvent - public static void onDeath(LivingDeathEvent event) + public static void onBreak(BlockEvent.BreakEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - ToyController.setVibrationLevel(0); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateMine)vibrationStates.get("mine")).onBreak(event.getState()); } - } catch (Throwable e) { - LOGGER.throwing(e); } - } - + + // Triggers when player starts to break block @SubscribeEvent public static void onHarvest(PlayerEvent.HarvestCheck event) { - try { - Player player = event.getEntity();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getTargetBlock(); - Block block = blockState.getBlock(); - - // ToolType. AXE, HOE, PICKAXE, SHOVEL - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - LOGGER.debug("Harvest: tool: " + - "?" + - " can harvest? " + event.canHarvest() + " hardness: " + blockHardness); - - int intensity = Math.toIntExact(Math.round((getIntensity("harvest") / 100.0 * (blockHardness / 50.0)) * 100)); - - if (event.canHarvest()) { - setState(getStateCounter(), 1, intensity, false); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getEntity())) + { + ((VibrationStateHarvest)vibrationStates.get("harvest")).onHarvest(); } } - + @SubscribeEvent - public static void onBreak(BlockEvent.BreakEvent event) - { - try { - Player player = event.getPlayer();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getState(); - Block block = blockState.getBlock(); - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - - LOGGER.info("Breaking: " + block.toString()); - - ItemStack mainhandItem = event.getPlayer().getMainHandItem(); - boolean usingAppropriateTool = mainhandItem.isCorrectToolForDrops(blockState); - List toolCan = ToolAction.getActions().stream().filter(a -> mainhandItem.canPerformAction(a)).collect(Collectors.toList()); - LOGGER.debug("mainhand: " + mainhandItem + " [" + toolCan + "]"); - LOGGER.debug("using pickaxe: " + mainhandItem.toString() + ", using appropriate tool: " + usingAppropriateTool); - - if (toolCan.contains(ToolAction.get("AXE")) && usingAppropriateTool) { - int duration = Math.max(1, Math.min(5, Math.toIntExact(Math.round(Math.ceil(Math.log(blockHardness + 0.5)))))); - int intensity = Math.toIntExact(Math.round((getIntensity("mine") / 100.0 * (blockHardness / 50.0)) * 100)); - setState(getStateCounter(), duration, intensity, true); - } - - LOGGER.info("XP to drop: " + event.getExpToDrop()); + public static void onPlace(BlockEvent.EntityPlaceEvent event){ + if (isPlayer(event.getEntity())) + { + ((VibrationStatePlace)vibrationStates.get("place")).onPlace(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -334,22 +227,20 @@ public static void onXpPickup(PlayerXpEvent.PickupXp event) @SubscribeEvent public static void onXpChange(PlayerXpEvent.XpChange event) { - try { - Player player = event.getEntity();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - int xpChange = event.getAmount(); - long duration = Math.round(Math.ceil(Math.log(xpChange + 0.5))); - - LOGGER.info("XP CHANGE: " + xpChange); - LOGGER.debug("duration: " + duration); - - setState(getStateCounter(), Math.toIntExact(duration), getIntensity("xpChange"), true); + if (isPlayer(event.getEntity())) + { + ((VibrationStateXpChange)vibrationStates.get("xpChange")).onXpChange(((Player)event.getEntity()).totalExperience, event.getAmount()); } - } catch (Throwable e) { - LOGGER.throwing(e); } + + + @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event) + { + if (isPlayer(event.getEntity())) + { + ((VibrationStateAdvancement)vibrationStates.get("advancement")).onAdvancement(event); + } } @SubscribeEvent @@ -386,27 +277,32 @@ public static void onWorldEntry(EntityJoinLevelEvent event) { if( !entity.level.isClientSide() ) { return; } + + if (ToyController.isConnected) return; if (entity instanceof Player) { LOGGER.info("Player respawn world: " + entity.toString()); - - try { + + new Thread(()-> { try { Player player = (Player) entity; UUID uuid = player.getGameProfile().getId(); - + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + LOGGER.info("Stealth: " + MinegasmConfig.stealth); if (ToyController.connectDevice()) { - setState(getStateCounter(), 5); - player.displayClientMessage(Component.literal(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); - } else { + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); + if (!MinegasmConfig.stealth){ + player.displayClientMessage(Component.literal(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); + } + } else if (!MinegasmConfig.stealth){ player.displayClientMessage(Component.literal(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start\n%s", ToyController.getLastErrorMessage())), false); } playerId = uuid; } } catch (Throwable e) { LOGGER.throwing(e); - } + }}).start(); } } } diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java index 2e6f091..4577128 100644 --- a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java @@ -10,10 +10,16 @@ import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.Executors; public class ToyController { private static final Logger LOGGER = LogManager.getLogger(); - private static final ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); + private static ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); private static ButtplugClientDevice device = null; private static boolean shutDownHookAdded = false; public static String lastErrorMessage = ""; @@ -24,9 +30,28 @@ public static boolean connectDevice() { try { device = null; client.disconnect(); + LOGGER.info("URL: " + MinegasmConfig.serverUrl); - client.connect(new URI(MinegasmConfig.serverUrl)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new Callable() { + public Void call() throws Exception { + client.connect(new URI(MinegasmConfig.serverUrl)); + return null; + } + }); + + try + { + future.get(3, TimeUnit.SECONDS); + } catch (TimeoutException e) { + future.cancel(true); + client = new ButtplugClientWSClient("Minegasm"); + throw new TimeoutException("Could not find WebSocket"); + } finally { + executor.shutdownNow(); + } + client.startScanning(); Thread.sleep(5000); diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java new file mode 100644 index 0000000..0ae06df --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java @@ -0,0 +1,128 @@ +package com.therainbowville.minegasm.common; + +import java.util.Map; +import java.util.HashMap; + +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Architecture inspired from https://github.com/Fyustorm/mInetiface +public abstract class AbstractVibrationState +{ + + protected static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); + protected final float streakCountdownAmount; + protected float intensity; + + protected float vibrationCountdown; + protected float vibrationFeedbackCountdown; + + protected AbstractVibrationState(float streakSeconds) + { + streakCountdownAmount = streakSeconds; + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + public void onTick() + { + if (accumulationEnabled()) + { + if (vibrationCountdown > 0) + vibrationCountdown--; + else if (intensity > 0) { + intensity = Math.max(0, intensity - 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + vibrationCountdown = Math.max(0, vibrationCountdown - 1); + } + + vibrationFeedbackCountdown = Math.max(0, vibrationFeedbackCountdown - 1); + } + + public void resetState() + { + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + protected static boolean accumulationEnabled() + { + return MinegasmConfig.mode.equals(ClientConfig.GameplayMode.ACCUMULATION); + } + + public static int getIntensity(String type) { + Map normal = new HashMap<>(); + normal.put("attack", 60); + normal.put("hurt", 0); + normal.put("mine", 80); + normal.put("place", 20); + normal.put("xpChange", 100); + normal.put("harvest", 10); + normal.put("fishing", 50); + normal.put("vitality", 0); + normal.put("advancement", 100); + + Map masochist = new HashMap<>(); + masochist.put("attack", 0); + masochist.put("hurt", 100); + masochist.put("mine", 0); + masochist.put("place", 0); + masochist.put("xpChange", 0); + masochist.put("fishing", 0); + masochist.put("harvest", 0); + masochist.put("vitality", 10); + masochist.put("advancement", 0); + + Map hedonist = new HashMap<>(); + hedonist.put("attack", 60); + hedonist.put("hurt", 10); + hedonist.put("mine", 80); + hedonist.put("place", 20); + hedonist.put("xpChange", 100); + hedonist.put("fishing", 50); + hedonist.put("harvest", 20); + hedonist.put("vitality", 10); + hedonist.put("advancement", 100); + + Map accumulation = new HashMap<>(); + accumulation.put("attack", 1); + accumulation.put("hurt", 1); + accumulation.put("mine", 1); + accumulation.put("place", 1); + accumulation.put("xpChange", 1); + accumulation.put("fishing", 50); + accumulation.put("harvest", 10); + accumulation.put("vitality", 0); + accumulation.put("advancement", 1); + + Map custom = new HashMap<>(); + custom.put("attack", MinegasmConfig.attackIntensity); + custom.put("hurt", MinegasmConfig.hurtIntensity); + custom.put("mine", MinegasmConfig.mineIntensity); + custom.put("place", MinegasmConfig.placeIntensity); + custom.put("xpChange", MinegasmConfig.xpChangeIntensity); + custom.put("fishing", MinegasmConfig.fishingIntensity); + custom.put("harvest", MinegasmConfig.harvestIntensity); + custom.put("vitality", MinegasmConfig.vitalityIntensity); + custom.put("advancement", MinegasmConfig.advancementIntensity); + + + return switch (MinegasmConfig.mode) + { + case NORMAL -> normal.get(type); + case MASOCHIST -> masochist.get(type); + case HEDONIST -> hedonist.get(type); + case ACCUMULATION -> accumulation.get(type); + case CUSTOM -> custom.get(type); + }; + } + + public abstract int getIntensity(); +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java index 82e8cf7..32b71ba 100644 --- a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java @@ -1,13 +1,16 @@ package com.therainbowville.minegasm.common; -import com.therainbowville.minegasm.config.ConfigHolder; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.client.ConfigScreenHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.therainbowville.minegasm.config.ConfigHolder; +import com.therainbowville.minegasm.config.ConfigHelper; + @Mod(Minegasm.MOD_ID) public class Minegasm { @@ -21,5 +24,7 @@ public Minegasm() { context.registerConfig(ModConfig.Type.SERVER, ConfigHolder.SERVER_SPEC); MinecraftForge.EVENT_BUS.register(this); + + ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, ConfigHelper::createConfigScreenFactory); } } diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java new file mode 100644 index 0000000..abfa9c5 --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java @@ -0,0 +1,47 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.advancements.FrameType; +import net.minecraft.advancements.Advancement; +import net.minecraftforge.event.entity.player.AdvancementEvent; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAdvancement extends AbstractVibrationState +{ + public VibrationStateAdvancement() + { + super(0); + } + + public void onAdvancement(AdvancementEvent event) + { + if (getIntensity("advancement") == 0) return; + try { + LOGGER.info("Advancement Event: " + event); + Advancement advancement = event.getAdvancement(); + if (advancement == null) return; + FrameType type = advancement.getDisplay().getFrame(); + int duration = switch (type) { + case TASK -> 5; + case GOAL -> 7; + case CHALLENGE -> 10; + }; + + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("advancement") + 20); + else if (vibrationCountdown > 0) + return getIntensity("advancement"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java new file mode 100644 index 0000000..acd0375 --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAttack extends AbstractVibrationState +{ + public VibrationStateAttack() + { + super(3); + } + + public void onAttack() + { + if (getIntensity("attack") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * 0; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("attack") + 20); + else if (vibrationCountdown > 0) + return getIntensity("attack"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java new file mode 100644 index 0000000..c952b68 --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java @@ -0,0 +1,24 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateClient extends AbstractVibrationState +{ + public VibrationStateClient() + { + super(0); + } + + public void setVibration(int intensity, int durationSeconds) + { + intensity = intensity; + vibrationCountdown = durationSeconds * MinegasmConfig.ticksPerSecond; + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return Math.toIntExact(Math.round(intensity)); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java new file mode 100644 index 0000000..61e1866 --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateFish extends AbstractVibrationState +{ + public VibrationStateFish() + { + super(0); + } + + public void onTick(Player player) + { + if (player.fishing != null) + { + Vec3 vector = player.fishing.getDeltaMovement(); + double x = vector.x(); + double y = vector.y(); + double z = vector.z(); + if (y < -0.075 && !player.level.getFluidState(player.fishing.blockPosition()).isEmpty() && x == 0 && z == 0) + { + vibrationCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + LOGGER.info("Fishing!"); + } + } + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return getIntensity("fishing"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java new file mode 100644 index 0000000..6b373cd --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java @@ -0,0 +1,32 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHarvest extends AbstractVibrationState +{ + private VibrationStateMine mineState; + + public VibrationStateHarvest(VibrationStateMine state) + { + super(0); + mineState = state; + } + + public void onHarvest() { + vibrationCountdown = 3; + mineState.onHarvest(); + } + + public int getIntensity() + { + if (vibrationCountdown > 0){ + if (accumulationEnabled()) + return Math.min(100, mineState.getIntensity() + 20); + else + return getIntensity("harvest"); + } + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java new file mode 100644 index 0000000..7219c5e --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java @@ -0,0 +1,36 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHurt extends AbstractVibrationState +{ + public VibrationStateHurt() + { + super(3); + } + + public void onHurt() { + if (getIntensity("hurt") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 10); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("hurt") + 20); + else if (vibrationCountdown > 0) + return getIntensity("hurt"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java new file mode 100644 index 0000000..e4c467d --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateMine extends AbstractVibrationState +{ + public VibrationStateMine() + { + super(5); + } + + public void onBreak(BlockState block) { + if (getIntensity("mine") == 0) return; + + String blockName = block.getBlock().getName().getString(); + if (accumulationEnabled()) + { + if (blockName.contains("Ore")) { + intensity = Math.min(100, intensity + 1); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + intensity = Math.min(100, intensity + .25f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + if (blockName.contains("Ore")) { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public void onHarvest() { + if (accumulationEnabled()){ + vibrationCountdown = Math.max(3, vibrationCountdown); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("mine") + 20); + else if (vibrationCountdown > 0) + return getIntensity("mine"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java new file mode 100644 index 0000000..aee4ebf --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java @@ -0,0 +1,35 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStatePlace extends AbstractVibrationState +{ + public VibrationStatePlace() + { + super(5); + } + + public void onPlace() { + if (getIntensity("place") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + .5f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("place") + 20); + else if (vibrationCountdown > 0) + return getIntensity("place"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java new file mode 100644 index 0000000..5824f8f --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java @@ -0,0 +1,62 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; + +import com.therainbowville.minegasm.config.MinegasmConfig; +import com.therainbowville.minegasm.config.ClientConfig; + +public class VibrationStateVitality extends AbstractVibrationState +{ + private int intensityCooldown; + private boolean targetMet; + + public VibrationStateVitality() + { + super(1); + intensityCooldown = 0; + targetMet = false; + } + + public void onTick(Player player) + { + float playerHealth = player.getHealth(); + float playerFoodLevel = player.getFoodData().getFoodLevel(); + + if ((MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth > 0 && playerHealth <= 1 ) + || (!MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth >= 20 && playerFoodLevel >= 20) ){ + + if (targetMet == false){ + targetMet = true; + vibrationFeedbackCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } else + targetMet = false; + +// if (accumulationEnabled() && targetMet) +// { +// if (intensityCooldown == 0) { +// intensity = Math.min(100, intensity + .1f); +// intensityCooldown = 10 * 20; +// } +// vibrationCountdown = streakCountdownAmount; +// intensityCooldown = Math.max(0, intensityCooldown - 1); +// } else + if (targetMet) { + vibrationCountdown = 1; + } + } + + public int getIntensity() + { + if (getIntensity("vitality") == 0) return 0; + + //if (accumulationEnabled()) + //return Math.toIntExact(Math.round(intensity)); + //else + if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("vitality") + 20); + else if (vibrationCountdown > 0) + return getIntensity("vitality"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java new file mode 100644 index 0000000..34b1633 --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateXpChange extends AbstractVibrationState +{ + private int lastLevel; + + public VibrationStateXpChange() + { + super(1); + lastLevel = -1; + } + + // Code adapted from https://github.com/Fyustorm/mInetiface + public void onXpChange(int level, int amount) { + if (amount == 0 || getIntensity("xpChange") == 0) + return; + + if (lastLevel == -1) { + lastLevel = level; + } + + if (lastLevel != level) { + amount *= 2; + } + + lastLevel = level; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + amount / 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + int duration = Math.toIntExact( Math.round( Math.ceil( Math.log(amount + 0.5) ) ) ); + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("xpChange") + 20); + else if (vibrationCountdown > 0) + return getIntensity("xpChange"); + else return 0; + } +} + diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java index 7bc1bc2..c3ca8ff 100644 --- a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java @@ -1,9 +1,11 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.Minecraft; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.mclanguageprovider.MinecraftModLanguageProvider; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.common.ForgeConfigSpec.IntValue; import java.util.Objects; @@ -12,19 +14,41 @@ public final class ClientConfig { final ForgeConfigSpec.BooleanValue vibrate; final ForgeConfigSpec.EnumValue mode; + final ForgeConfigSpec.BooleanValue stealth; + final ForgeConfigSpec.EnumValue tickFrequency; + final ForgeConfigSpec.IntValue attackIntensity; final ForgeConfigSpec.IntValue hurtIntensity; final ForgeConfigSpec.IntValue mineIntensity; + final ForgeConfigSpec.IntValue placeIntensity; final ForgeConfigSpec.IntValue xpChangeIntensity; + final ForgeConfigSpec.IntValue fishingIntensity; final ForgeConfigSpec.IntValue harvestIntensity; final ForgeConfigSpec.IntValue vitalityIntensity; + final ForgeConfigSpec.IntValue advancementIntensity; + + static final String DEFAULT_SERVER_URL = "ws://localhost:12345/buttplug"; + static final boolean DEFAULT_VIBRATE = true; + static final GameplayMode DEFAULT_MODE = GameplayMode.NORMAL; + static final boolean DEFAULT_STEALTH = false; + + static final int DEFAULT_ATTACK_INTENSITY = 60; + static final int DEFAULT_HURT_INTENSITY = 0; + static final int DEFAULT_MINE_INTENSITY = 80; + static final int DEFAULT_PLACE_INTENSITY = 20; + static final int DEFAULT_XP_CHANGE_INTENSITY = 100; + static final int DEFAULT_FISHING_INTENSITY = 50; + static final int DEFAULT_HARVEST_INTENSITY = 0; + static final int DEFAULT_VITALITY_INTENSITY = 0; + static final int DEFAULT_ADVANCEMENT_INTENSITY = 100; + ClientConfig(final ForgeConfigSpec.Builder builder) { builder.push("buttplug"); serverUrl = builder .translation(Minegasm.MOD_ID + ".config.serverUrl") - .define("serverUrl", "ws://localhost:12345/buttplug"); + .define("serverUrl", DEFAULT_SERVER_URL); builder.pop(); @@ -32,50 +56,92 @@ public final class ClientConfig { vibrate = builder .translation(Minegasm.MOD_ID + ".config.vibrate") - .define("vibrate", true); + .define("vibrate", DEFAULT_VIBRATE); mode = builder .translation(Minegasm.MOD_ID + ".config.mode") - .defineEnum("mode", GameplayMode.NORMAL); + .defineEnum("mode", DEFAULT_MODE); + stealth = builder + .translation(Minegasm.MOD_ID + ".config.stealth") + .define("stealth", DEFAULT_STEALTH); + + tickFrequency = builder + .translation(Minegasm.MOD_ID + ".config.mode") + .defineEnum("tickFrequency", TickFrequencyOptions.EVERY_TICK); builder.push("intensity"); attackIntensity = builder .comment("Vibration intensity when attacking on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.attack") - .defineInRange("attackIntensity", 60, 0, 100); + .defineInRange("attackIntensity", DEFAULT_ATTACK_INTENSITY, 0, 100); hurtIntensity = builder .comment("Vibration intensity when hurting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.hurt") - .defineInRange("hurtIntensity", 0, 0, 100); + .defineInRange("hurtIntensity", DEFAULT_HURT_INTENSITY, 0, 100); mineIntensity = builder .comment("Vibration intensity when mining on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.mine") - .defineInRange("mineIntensity", 80, 0, 100); + .defineInRange("mineIntensity", DEFAULT_MINE_INTENSITY, 0, 100); + + placeIntensity = builder + .comment("Vibration intensity when placing blocks on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.place") + .defineInRange("placeIntensity", DEFAULT_PLACE_INTENSITY, 0, 100); xpChangeIntensity = builder .comment("Vibration intensity when gaining XP on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.xp_change") - .defineInRange("xpChangeIntensity", 100, 0, 100); + .defineInRange("xpChangeIntensity", DEFAULT_XP_CHANGE_INTENSITY, 0, 100); + + fishingIntensity = builder + .comment("Vibration intensity when fishing on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.fishing") + .defineInRange("fishingIntensity", DEFAULT_FISHING_INTENSITY, 0, 100); harvestIntensity = builder .comment("Vibration intensity when harvesting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.harvest") - .defineInRange("harvestIntensity", 0, 0, 100); + .defineInRange("harvestIntensity", DEFAULT_HARVEST_INTENSITY, 0, 100); vitalityIntensity = builder .comment("Vibration intensity on high level of player's vitality on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.vitality") - .defineInRange("vitalityIntensity", 0, 0, 100); + .defineInRange("vitalityIntensity", DEFAULT_VITALITY_INTENSITY, 0, 100); + + advancementIntensity = builder + .comment("Vibration intensity on achieving advancement on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.advancement") + .defineInRange("advancementIntensity", DEFAULT_ADVANCEMENT_INTENSITY, 0, 100); builder.pop(); builder.pop(); } + + public void resetConfigUrl() + { + ConfigHolder.CLIENT.serverUrl.set(DEFAULT_SERVER_URL); + } + + public void resetConfigCustom() + { + ConfigHolder.CLIENT.attackIntensity.set(DEFAULT_ATTACK_INTENSITY); + ConfigHolder.CLIENT.hurtIntensity.set(DEFAULT_HURT_INTENSITY); + ConfigHolder.CLIENT.mineIntensity.set(DEFAULT_MINE_INTENSITY); + ConfigHolder.CLIENT.placeIntensity.set(DEFAULT_PLACE_INTENSITY); + ConfigHolder.CLIENT.xpChangeIntensity.set(DEFAULT_XP_CHANGE_INTENSITY); + ConfigHolder.CLIENT.fishingIntensity.set(DEFAULT_FISHING_INTENSITY); + ConfigHolder.CLIENT.harvestIntensity.set(DEFAULT_HARVEST_INTENSITY); + ConfigHolder.CLIENT.vitalityIntensity.set(DEFAULT_VITALITY_INTENSITY); + ConfigHolder.CLIENT.advancementIntensity.set(DEFAULT_ADVANCEMENT_INTENSITY); + } + public enum GameplayMode { NORMAL("gui." + Minegasm.MOD_ID + ".config.mode.normal"), MASOCHIST("gui." + Minegasm.MOD_ID + ".config.mode.masochist"), HEDONIST("gui." + Minegasm.MOD_ID + ".config.mode.hedonist"), + ACCUMULATION("gui." + Minegasm.MOD_ID + ".config.mode.accumulation"), CUSTOM("gui." + Minegasm.MOD_ID + ".config.mode.custom"); private final String translateKey; @@ -89,4 +155,37 @@ public String getTranslateKey() { return this.translateKey; } } + + public enum TickFrequencyOptions { + EVERY_TICK(1), + EVERY_OTHER_TICK(2), + EVERY_5_TICKS(5), + EVERY_10_TICKS(10), + EVERY_20_TICKS(20), + EVERY_30_TICKS(30), + EVERY_40_TICKS(40), + EVERY_50_TICKS(50); + + private int value; + + TickFrequencyOptions(int value) { + this.value = value; + } + + public int getInt() + { + return value; + } + + public static TickFrequencyOptions fromInt(int value) + { + for (TickFrequencyOptions type : values()) { + if (type.getInt() == value) { + return type; + } + } + return null; + } + } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java index 4441fb2..e51ab15 100644 --- a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java @@ -1,20 +1,79 @@ package com.therainbowville.minegasm.config; +import net.minecraftforge.client.ConfigScreenHandler; +import net.minecraftforge.common.ForgeConfigSpec; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public final class ConfigHelper { + private static final Logger LOGGER = LogManager.getLogger(); public static void bakeClient() { MinegasmConfig.serverUrl = ConfigHolder.CLIENT.serverUrl.get(); MinegasmConfig.vibrate = ConfigHolder.CLIENT.vibrate.get(); MinegasmConfig.mode = ConfigHolder.CLIENT.mode.get(); + MinegasmConfig.stealth = ConfigHolder.CLIENT.stealth.get(); + MinegasmConfig.tickFrequency = ConfigHolder.CLIENT.tickFrequency.get().getInt(); + MinegasmConfig.ticksPerSecond = Math.max(0, 20f / MinegasmConfig.tickFrequency); + MinegasmConfig.attackIntensity = ConfigHolder.CLIENT.attackIntensity.get(); MinegasmConfig.hurtIntensity = ConfigHolder.CLIENT.hurtIntensity.get(); MinegasmConfig.mineIntensity = ConfigHolder.CLIENT.mineIntensity.get(); + MinegasmConfig.placeIntensity = ConfigHolder.CLIENT.placeIntensity.get(); MinegasmConfig.xpChangeIntensity = ConfigHolder.CLIENT.xpChangeIntensity.get(); + MinegasmConfig.fishingIntensity = ConfigHolder.CLIENT.fishingIntensity.get(); MinegasmConfig.harvestIntensity = ConfigHolder.CLIENT.harvestIntensity.get(); MinegasmConfig.vitalityIntensity = ConfigHolder.CLIENT.vitalityIntensity.get(); + MinegasmConfig.advancementIntensity = ConfigHolder.CLIENT.advancementIntensity.get(); } public static void bakeServer() { } + + public static void saveClient() + { + try{ + + MinegasmConfigBuffer buffer = new MinegasmConfigBuffer(); + +// Field[] fields = MinegasmConfigBuffer.class.getFields(); + +// for (Field field : fields) +// { +// Field configField = ConfigHolder.CLIENT.getClass().getDeclaredField(field.getName()); // Get Corisponding Field in CLIENT +// Class configFieldClass = configField.getType(); // Get the configField Class +// Method method = configFieldClass.getMethod("set", Object.class); +// LOGGER.info(method); +// method.invoke(configField.get(ConfigHolder.CLIENT), field.get(buffer)); +// } + + ConfigHolder.CLIENT.serverUrl.set(buffer.serverUrl); + ConfigHolder.CLIENT.vibrate.set(buffer.vibrate); + ConfigHolder.CLIENT.mode.set(buffer.mode); + ConfigHolder.CLIENT.stealth.set(buffer.stealth); + ConfigHolder.CLIENT.tickFrequency.set(ClientConfig.TickFrequencyOptions.fromInt(buffer.tickFrequency)); + + ConfigHolder.CLIENT.attackIntensity.set(buffer.attackIntensity); + ConfigHolder.CLIENT.hurtIntensity.set(buffer.hurtIntensity); + ConfigHolder.CLIENT.mineIntensity.set(buffer.mineIntensity); + ConfigHolder.CLIENT.placeIntensity.set(buffer.placeIntensity); + ConfigHolder.CLIENT.xpChangeIntensity.set(buffer.xpChangeIntensity); + ConfigHolder.CLIENT.fishingIntensity.set(buffer.fishingIntensity); + ConfigHolder.CLIENT.harvestIntensity.set(buffer.harvestIntensity); + ConfigHolder.CLIENT.vitalityIntensity.set(buffer.vitalityIntensity); + ConfigHolder.CLIENT.advancementIntensity.set(buffer.advancementIntensity); + } catch (Throwable e) + { + LOGGER.info(e); + } + } + + public static ConfigScreenHandler.ConfigScreenFactory createConfigScreenFactory() { + return new ConfigScreenHandler.ConfigScreenFactory((minecraft, screen) -> new ConfigScreen(screen)); + } } \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java index b422dfa..7687547 100644 --- a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java @@ -29,4 +29,5 @@ public static ClientConfig getClientInstance() { public static ServerConfig getServerInstance() { return SERVER; } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java new file mode 100644 index 0000000..b124066 --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java @@ -0,0 +1,356 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraftforge.client.gui.widget.ForgeSlider; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Component; +import net.minecraftforge.event.TickEvent; +import net.minecraft.client.Minecraft; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.client.ToyController; +import com.therainbowville.minegasm.client.ClientEventHandler; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import java.lang.reflect.Field; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.function.IntConsumer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + EditBox wsHost = null; + + public ConfigScreen(Screen previous) { + super(Component.literal("Minegasm Config")); + this.previous = previous; + pauseMenu = false; + } + + public ConfigScreen(Screen previous, boolean pause) { + super(Component.literal("Minegasm Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + wsHost = new EditBox(Minecraft.getInstance().font, this.width / 2 - 100, this.height / 6, 200, 20, null); + wsHost.setValue(MinegasmConfig.serverUrl); + this.addRenderableWidget(wsHost); + + wsHost.setResponder(s -> { + LOGGER.info(s); + MinegasmConfig.serverUrl = s; + }); + + this.addRenderableWidget(new Button.Builder(Component.literal("Reset Server Url"), button -> { + ConfigHolder.getClientInstance().resetConfigUrl(); + MinegasmConfig.serverUrl = ConfigHolder.getClientInstance().serverUrl.get(); + wsHost.setValue(MinegasmConfig.serverUrl); + }).pos(this.width / 2 - 155, this.height / 6 + 25) + .size(150, 20) + .build() + ); + + PlainTextLabel connectResponse = new PlainTextLabel(this.width / 2 - 155, this.height / 6 + 50, 310, 15, Component.literal("" + ChatFormatting.GREEN)); + + this.addRenderableWidget(connectResponse); + + Button reconnectButton = new Button.Builder(Component.literal("Reconnect"), button -> { + button.active = false; + connectResponse.setValue("Connecting"); + new Thread(() -> { + if (ToyController.connectDevice()) { + ClientEventHandler.afterConnect(); + button.active = true; + connectResponse.setValue(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())); + } else { + button.active = true; + connectResponse.setValue(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start: %s", ToyController.getLastErrorMessage())); + } + + }).start(); + }) + .pos(this.width / 2 + 5, this.height / 6 + 25) + .size(150, 20) + .build(); + + this.addRenderableWidget(reconnectButton); + + reconnectButton.active = pauseMenu; + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.vibrate) + .create(this.width / 2 - 155, this.height / 6 + 25 * 3, 150, 20, + Component.literal("Vibration"), (button, value) -> MinegasmConfig.vibrate = value)); + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.stealth) + .create(this.width / 2 + 5, this.height / 6 + 25 * 3, 150, 20, + Component.literal("Stealth"), (button, value) -> MinegasmConfig.stealth = value)); + + this.addRenderableWidget( + CycleButton.builder((ClientConfig.GameplayMode mode) -> + Component.literal(switch (mode) { + case NORMAL -> "Normal"; + case MASOCHIST -> "Masochist"; + case HEDONIST -> "Hedonist"; + case ACCUMULATION -> "Accumulation"; + case CUSTOM -> "Custom"; + })) + .withValues(ClientConfig.GameplayMode.NORMAL, ClientConfig.GameplayMode.MASOCHIST, ClientConfig.GameplayMode.HEDONIST, ClientConfig.GameplayMode.ACCUMULATION, ClientConfig.GameplayMode.CUSTOM) + .withInitialValue(MinegasmConfig.mode) + .create(this.width / 2 - 155, this.height / 6 + 25 * 4, 150, 20, + Component.literal("Mode"), (button, value) -> { + MinegasmConfig.mode = value; + }) + ); + + this.addRenderableWidget(new Button.Builder(Component.literal("Edit Custom Settings"), button -> minecraft.setScreen(new CustomModeConfigScreen(this, pauseMenu))) + .pos(this.width / 2 + 5, this.height / 6 + 25 * 4) + .size(150, 20) + .build() + ); + + this.addRenderableWidget( + CycleButton.builder((Integer tickFrequency) -> + Component.literal(switch (tickFrequency) { + case 1 -> "Every Tick"; + case 2 -> "Every Other Tick"; + case 5 -> "Every 5 Ticks"; + case 10 -> "Every 10 Ticks"; + case 20 -> "Every Second"; + default -> "Every " + Float.toString(tickFrequency / 20f)+ " Seconds"; + })) + .withValues(1, 2, 5, 10, 20, 30, 40, 50) + .withInitialValue(MinegasmConfig.tickFrequency) + .create(this.width / 2 - 100, this.height / 6 + 25 * 5, 200, 20, + Component.literal("Tick Frequency"), (button, value) -> { + MinegasmConfig.tickFrequency = value; + MinegasmConfig.ticksPerSecond = Math.max(0, 20f / MinegasmConfig.tickFrequency); + LOGGER.info("TPS: " + MinegasmConfig.ticksPerSecond); + } + ) + ); + + this.addRenderableWidget(new Button.Builder(CommonComponents.GUI_DONE, button -> this.onClose()) + .pos(this.width / 2 - 100, this.height - 27) + .size(200, 20) + .build() + ); + + + } + + @Override + public void tick() { + super.tick(); + + // Add ticking logic for EditBox in editBox + if (this.wsHost != null) + this.wsHost.tick(); + } + + @Override + public void onClose() { + PlainTextLabel.setValue(""); + this.minecraft.setScreen(previous); + MinegasmConfig.save(); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(poseStack); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } + + class PlainTextLabel extends AbstractWidget { + + private static Component text = Component.literal(""); + private int x; + private int y; + + public PlainTextLabel(int x, int y, int width, int height, Component text) { + super(x, y, width, height, text); + this.x = x; + this.y = y; + } + + public static void setValue(String value) + { + text = Component.literal(value); + } + + @Override + public void updateWidgetNarration(NarrationElementOutput output) { + defaultButtonNarrationText(output); + } + + @Override + public void renderWidget(PoseStack poseStack, int i, int j, float f) { + if (text == null || text.getString().isEmpty()) + return; + +// RenderSystem.setShaderColor(1, 1, 1, 1); +// Minecraft.getInstance().font.draw(poseStack, text.getString(), x, y, 0xFFFFFF); + drawCenteredString(poseStack, Minecraft.getInstance().font, text.getString(), Minecraft.getInstance().screen.width / 2, this.y + this.height / 4, 0xFFFFFF); + } + } + +} + +class CustomModeConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + + public CustomModeConfigScreen(Screen previous) { + super(Component.literal("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = false; + } + + public CustomModeConfigScreen(Screen previous, boolean pause) { + super(Component.literal("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + try{ + this.addRenderableWidget(new Button.Builder(CommonComponents.GUI_DONE, button -> this.onClose()) + .pos(this.width / 2 + 5, this.height - 27) + .size(150, 20) + .build() + ); + + IntensitiySliderBar.sliders.clear(); + + // Attack + this.addRenderableWidget(new IntensitiySliderBar(this, "Attack: ", MinegasmConfig.class.getField("attackIntensity"))); + + // Hurt + this.addRenderableWidget(new IntensitiySliderBar(this, "Hurt: ", MinegasmConfig.class.getField("hurtIntensity"))); + + // Mine + this.addRenderableWidget(new IntensitiySliderBar(this, "Mine: ", MinegasmConfig.class.getField("mineIntensity"))); + + // Place + this.addRenderableWidget(new IntensitiySliderBar(this, "Place: ", MinegasmConfig.class.getField("placeIntensity"))); + + // XP Change + this.addRenderableWidget(new IntensitiySliderBar(this, "XP Change: ", MinegasmConfig.class.getField("xpChangeIntensity"))); + + // Fishing + this.addRenderableWidget(new IntensitiySliderBar(this, "Fishing: ", MinegasmConfig.class.getField("fishingIntensity"))); + + // Harvest + this.addRenderableWidget(new IntensitiySliderBar(this, "Harvest: ", MinegasmConfig.class.getField("harvestIntensity"))); + + // Vitality + this.addRenderableWidget(new IntensitiySliderBar(this, "Vitality: ", MinegasmConfig.class.getField("vitalityIntensity"))); + + // Advancement + this.addRenderableWidget(new IntensitiySliderBar(this, "Advancement: ", MinegasmConfig.class.getField("advancementIntensity"))); + + this.addRenderableWidget(new Button.Builder(Component.literal("Reset Values"), button -> { + ConfigHolder.getClientInstance().resetConfigCustom(); + IntensitiySliderBar.refreshAllValues(); + }) + .pos(this.width / 2 - 155, this.height - 27) + .size(150, 20) + .build() + ); + + + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + @Override + public void onClose() { + IntensitiySliderBar.sliders.clear(); + this.minecraft.setScreen(previous); + } + + @Override + public void render(PoseStack poseStack, int i, int j, float f) { + if (pauseMenu) + this.renderBackground(poseStack); + else + this.renderDirtBackground(poseStack); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(poseStack, i, j, f); + } + + private class IntensitiySliderBar extends ForgeSlider + { + public static ArrayList sliders = new ArrayList(); + private Field fieldReference; + + IntensitiySliderBar(CustomModeConfigScreen parent, String prefix, Field field) throws Exception + { + super( parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155), // x pos + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2), // y pos + 150, 20, // Width, height + Component.literal(prefix), // Prefix + Component.literal(""), // Suffix + 0, 100, field.getInt(null), 1, 1, true); // Min, Max, Default value, stepsize, percision, drawstring + fieldReference = field; +// LOGGER.info("S: " + sliders.size() + " X: " + parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155) + " Y: " + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2)); + sliders.add(this); + } + + @Override + public void applyValue() + { +// LOGGER.info("applyValue"); + //responder.accept(this.getValueInt()); + try { + fieldReference.set(null, this.getValueInt()); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public static void refreshAllValues() + { + for (IntensitiySliderBar slider : sliders) + { + slider.refreshValue(); + } + } + + private void refreshValue() + { + try { + this.setValue(fieldReference.getInt(null)); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java index 52965d5..cb0e2fd 100644 --- a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java @@ -18,13 +18,20 @@ public class MinegasmConfig { public static String serverUrl; public static boolean vibrate; - public static Enum mode = ClientConfig.GameplayMode.NORMAL; + public static ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public static boolean stealth; + public static int tickFrequency; + public static float ticksPerSecond; + public static int attackIntensity; public static int hurtIntensity; public static int mineIntensity; + public static int placeIntensity; public static int xpChangeIntensity; + public static int fishingIntensity; public static int harvestIntensity; public static int vitalityIntensity; + public static int advancementIntensity; // Server // -- none at the moment @@ -41,4 +48,49 @@ public static void onModConfigEvent(final ModConfigEvent event) { LOGGER.debug("Baked server config"); } } + + public static void save() + { + ConfigHelper.saveClient(); + } + } + +class MinegasmConfigBuffer +{ + public String serverUrl; + + public boolean vibrate; + public ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public boolean stealth; + public int tickFrequency; + + public int attackIntensity; + public int hurtIntensity; + public int mineIntensity; + public int placeIntensity; + public int xpChangeIntensity; + public int fishingIntensity; + public int harvestIntensity; + public int vitalityIntensity; + public int advancementIntensity; + + MinegasmConfigBuffer() + { + this.serverUrl = MinegasmConfig.serverUrl; + this.vibrate = MinegasmConfig.vibrate; + this.mode = MinegasmConfig.mode; + this.stealth = MinegasmConfig.stealth; + this.tickFrequency = MinegasmConfig.tickFrequency; + + this.attackIntensity = MinegasmConfig.attackIntensity; + this.hurtIntensity = MinegasmConfig.hurtIntensity; + this.mineIntensity = MinegasmConfig.mineIntensity; + this.placeIntensity = MinegasmConfig.placeIntensity; + this.xpChangeIntensity = MinegasmConfig.xpChangeIntensity; + this.fishingIntensity = MinegasmConfig.fishingIntensity; + this.harvestIntensity = MinegasmConfig.harvestIntensity; + this.vitalityIntensity = MinegasmConfig.vitalityIntensity; + this.advancementIntensity = MinegasmConfig.advancementIntensity; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java new file mode 100644 index 0000000..8f9300d --- /dev/null +++ b/forge/fg-6.0/1.19.4/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java @@ -0,0 +1,132 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.PauseScreen; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ScreenEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.commons.lang3.mutable.MutableObject; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Adapted from https://github.com/Creators-of-Create/Create/ +public class PauseMenuButton extends Button +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static ResourceLocation LOGO = new ResourceLocation(Minegasm.MOD_ID, "textures/logo.png"); + + int xPos; + int yPos; + + public PauseMenuButton(int x, int y) { + super(new Button.Builder(Component.literal(""), PauseMenuButton::clicked).pos(x, y).size(20, 20)); + xPos = x; + yPos = y; + } + + @Override + public void renderWidget(PoseStack mstack, int i, int j, float k) { + super.renderWidget(mstack, i, j, k); + mstack.pushPose(); + mstack.translate(xPos + width / 2 - (64 * 0.25f) / 2, yPos + height / 2 - (64 * 0.25f) / 2, 0); + mstack.scale(0.25f, 0.25f, 1); + RenderSystem.setShaderTexture(0, LOGO); + GuiComponent.blit(mstack, 0, 0, 0, 0, 0, 64, 64, 64, 64); + mstack.popPose(); + } + + public static void clicked(Button button) + { + Minecraft.getInstance().setScreen(new ConfigScreen(Minecraft.getInstance().screen, true)); + } + + public static class SingleMenuRow { + public final String left, right; + public SingleMenuRow(String left, String right) { + this.left = I18n.get(left); + this.right = I18n.get(right); + } + public SingleMenuRow(String center) { + this(center, center); + } + } + + public static class MenuRows { + public static final MenuRows MAIN_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.singleplayer"), + new SingleMenuRow("menu.multiplayer"), + new SingleMenuRow("fml.menu.mods", "menu.online"), + new SingleMenuRow("narrator.button.language", "narrator.button.accessibility") + )); + + public static final MenuRows INGAME_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.returnToGame"), + new SingleMenuRow("gui.advancements", "gui.stats"), + new SingleMenuRow("menu.sendFeedback", "menu.reportBugs"), + new SingleMenuRow("menu.options", "menu.shareToLan"), + new SingleMenuRow("menu.returnToMenu") + )); + + protected final List leftButtons, rightButtons; + + public MenuRows(List variants) { + leftButtons = variants.stream().map(r -> r.left).collect(Collectors.toList()); + rightButtons = variants.stream().map(r -> r.right).collect(Collectors.toList()); + } + } + + @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) + public class PauseMenuButtonScreen { + + @SubscribeEvent + public static void onGuiInit(ScreenEvent.Init event) { + if(event.getScreen() instanceof PauseScreen) { // Make sure GUI is Escape menu + MenuRows menu = MenuRows.INGAME_MENU; + int rowIdx = 3; + int offsetX = 4; + boolean onLeft = offsetX < 0; + String target = (onLeft ? menu.leftButtons : menu.rightButtons).get(rowIdx - 1); + + int offsetX_ = offsetX; + MutableObject toAdd = new MutableObject<>(null); + event.getListenersList() + .stream() + .filter(w -> w instanceof AbstractWidget) + .map(w -> (AbstractWidget) w) + .filter(w -> w.getMessage() + .getString() + .equals(target)) + .findFirst() + .ifPresent(w -> toAdd + .setValue(new PauseMenuButton(w.getX() + offsetX_ + (onLeft ? -20 : w.getWidth()), w.getY()))); + if (toAdd.getValue() != null) + event.addListener(toAdd.getValue()); + } + } + } +} diff --git a/forge/fg-6.0/1.19.4/src/main/resources/assets/minegasm/textures/logo.png b/forge/fg-6.0/1.19.4/src/main/resources/assets/minegasm/textures/logo.png new file mode 100644 index 0000000..63eaa64 Binary files /dev/null and b/forge/fg-6.0/1.19.4/src/main/resources/assets/minegasm/textures/logo.png differ diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java index 56f786e..9d1d426 100644 --- a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ClientEventHandler.java @@ -1,174 +1,137 @@ package com.therainbowville.minegasm.client; import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.common.*; import com.therainbowville.minegasm.config.ClientConfig; import com.therainbowville.minegasm.config.MinegasmConfig; + import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.network.chat.Component; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.network.chat.Component; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.ToolAction; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.EntityJoinLevelEvent; -import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.player.*; +import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.*; import java.util.stream.Collectors; - +import java.lang.Thread; @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public class ClientEventHandler { private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); - private static final int TICKS_PER_SECOND = 20; + private static int tickCounter = -1; private static int clientTickCounter = -1; - private static final double[] state = new double[1200]; private static boolean paused = false; private static UUID playerId = null; - - - private static void clearState() { - tickCounter = -1; - clientTickCounter = -1; - Arrays.fill(state, 0); - paused = false; + + private static Map vibrationStates = new HashMap(); + + static { + vibrationStates.put("advancement", new VibrationStateAdvancement()); + vibrationStates.put("attack", new VibrationStateAttack()); + vibrationStates.put("fish", new VibrationStateFish()); + vibrationStates.put("hurt", new VibrationStateHurt()); + vibrationStates.put("mine", new VibrationStateMine()); + vibrationStates.put("place", new VibrationStatePlace()); + vibrationStates.put("harvest", new VibrationStateHarvest((VibrationStateMine)vibrationStates.get("mine"))); + vibrationStates.put("vitality", new VibrationStateVitality()); + vibrationStates.put("xpChange", new VibrationStateXpChange()); + vibrationStates.put("generic", new VibrationStateClient()); } - private static int getStateCounter() { - return tickCounter / 20; + public static void afterConnect() + { + //setState(getStateCounter(), 5); + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); } - - private static void setState(int start, int duration, int intensity, boolean decay) { - if (duration <= 0) { - return; + + private static double getIntensity() + { + double intensity = 0; + for (Map.Entry state : vibrationStates.entrySet()) + { + intensity = Math.max(intensity, state.getValue().getIntensity()); +// LOGGER.info(state.getKey() + ": " + state.getValue().getIntensity()); + } - - if (decay) { - int safeDuration = Math.max(0, duration - 2); - for (int i = 0; i < safeDuration; i++) { - setState(start+i, intensity); - } - setState(start+safeDuration, intensity/2); - setState(start+safeDuration+1, intensity/4); - } else { - for (int i = 0; i < duration; i++) { - setState(start+i, intensity); - } + return intensity / 100; + } + + private static void tickAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.onTick(); } } - - private static void setState(int counter, int intensity) { - boolean accumulate = false; //XXX reserved for future use - setState(counter, intensity, accumulate); + + private static void resetAll() + { + for (AbstractVibrationState state : vibrationStates.values()) + { + state.resetState(); + } } - private static void setState(int counter, int intensity, boolean accumulate) { - int safeCounter = counter % state.length; - if (accumulate) { - state[safeCounter] = Math.min(1.0, state[safeCounter] + (intensity / 100.0)); - } else { - state[safeCounter] = Math.min(1.0, Math.max(state[safeCounter], (intensity / 100.0))); + private static boolean isPlayer(Entity entity){ + try { + if (entity instanceof Player) { + Player player = (Player) entity;; + UUID uuid = player.getGameProfile().getId(); + return uuid.equals(playerId); } + } catch (Throwable e) { + LOGGER.throwing(e); + } + return false; } - private static int getIntensity(String type) { - Map normal = new HashMap<>(); - normal.put("attack", 60); - normal.put("hurt", 0); - normal.put("mine", 80); - normal.put("xpChange", 100); - normal.put("harvest", 0); - normal.put("vitality", 0); - - Map masochist = new HashMap<>(); - masochist.put("attack", 0); - masochist.put("hurt", 100); - masochist.put("mine", 0); - masochist.put("xpChange", 0); - masochist.put("harvest", 0); - masochist.put("vitality", 10); - - Map hedonist = new HashMap<>(); - hedonist.put("attack", 60); - hedonist.put("hurt", 10); - hedonist.put("mine", 80); - hedonist.put("xpChange", 100); - hedonist.put("harvest", 20); - hedonist.put("vitality", 10); - - Map custom = new HashMap<>(); - custom.put("attack", MinegasmConfig.attackIntensity); - custom.put("hurt", MinegasmConfig.hurtIntensity); - custom.put("mine", MinegasmConfig.mineIntensity); - custom.put("xpChange", MinegasmConfig.xpChangeIntensity); - custom.put("harvest", MinegasmConfig.harvestIntensity); - custom.put("vitality", MinegasmConfig.vitalityIntensity); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - return masochist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.HEDONIST)) { - return hedonist.get(type); - } else if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.CUSTOM)) { - return custom.get(type); - } else { - return normal.get(type); - } + private static void clearState() { + tickCounter = -1; + clientTickCounter = -1; + paused = false; + resetAll(); } @SubscribeEvent public static void onPlayerTick(TickEvent.PlayerTickEvent event) { try { - if (event.phase == TickEvent.Phase.END ) { - Player player = event.player;; - UUID uuid = player.getGameProfile().getId(); - - float playerHealth = player.getHealth(); - float playerFoodLevel = player.getFoodData().getFoodLevel(); - - tickCounter = (tickCounter + 1) % (20 * (60 * TICKS_PER_SECOND)); // 20 min day cycle - - if (tickCounter % TICKS_PER_SECOND == 0) { // every 1 sec - if (uuid.equals(playerId)) { - int stateCounter = getStateCounter(); - - if (MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST)) { - if (playerHealth > 0 && playerHealth <= 1) { - setState(stateCounter, getIntensity("vitality")); - } - } else if (playerHealth >= 20 && playerFoodLevel >= 20) { - setState(stateCounter, getIntensity("vitality")); - } - - double newVibrationLevel = state[stateCounter]; - state[stateCounter] = 0; - - LOGGER.trace("Tick " + stateCounter + ": " + newVibrationLevel); - - if (ToyController.currentVibrationLevel != newVibrationLevel) { - ToyController.setVibrationLevel(newVibrationLevel); - } - } + if (event.phase == TickEvent.Phase.END && isPlayer(event.player)) { + Player player = event.player; + + tickCounter = (tickCounter + 1) % 100; + + + if (tickCounter % MinegasmConfig.tickFrequency == 0) // TODO: Add ticks per second config option (Default: Every tick) + { + tickAll(); + + ((VibrationStateVitality)vibrationStates.get("vitality")).onTick(player); + ((VibrationStateFish)vibrationStates.get("fish")).onTick(player); + + double newVibrationLevel = getIntensity(); + + if (ToyController.currentVibrationLevel != newVibrationLevel) + ToyController.setVibrationLevel(newVibrationLevel); } - if (tickCounter % (5 * TICKS_PER_SECOND) == 0) { // 5 secs - LOGGER.debug("Health: " + playerHealth); - LOGGER.debug("Food: " + playerFoodLevel); - } } } catch (Throwable e) { LOGGER.throwing(e); @@ -200,19 +163,10 @@ public static void onClientTick(TickEvent.ClientTickEvent event) { @SubscribeEvent public static void onAttack(AttackEntityEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("attack"), true); - } + if (isPlayer(event.getEntity())) + { + ((VibrationStateAttack)vibrationStates.get("attack")).onAttack(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -224,98 +178,37 @@ public static void onCriticalHit(CriticalHitEvent event) @SubscribeEvent public static void onHurt(LivingHurtEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - setState(getStateCounter(), 3, getIntensity("hurt"), true); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getEntity())) + { + ((VibrationStateHurt)vibrationStates.get("hurt")).onHurt(); } } @SubscribeEvent - public static void onDeath(LivingDeathEvent event) + public static void onBreak(BlockEvent.BreakEvent event) { - try { - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity;; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - ToyController.setVibrationLevel(0); - } + if (isPlayer(event.getPlayer())) + { + ((VibrationStateMine)vibrationStates.get("mine")).onBreak(event.getState()); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } - + + // Triggers when player starts to break block @SubscribeEvent public static void onHarvest(PlayerEvent.HarvestCheck event) { - try { - Player player = event.getEntity(); - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getTargetBlock(); - Block block = blockState.getBlock(); - - // ToolType. AXE, HOE, PICKAXE, SHOVEL - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - LOGGER.debug("Harvest: tool: " + - "?" + - " can harvest? " + event.canHarvest() + " hardness: " + blockHardness); - - int intensity = Math.toIntExact(Math.round((getIntensity("harvest") / 100.0 * (blockHardness / 50.0)) * 100)); - - if (event.canHarvest()) { - setState(getStateCounter(), 1, intensity, false); - } - } - } catch (Throwable e) { - LOGGER.throwing(e); + if (isPlayer(event.getEntity())) + { + ((VibrationStateHarvest)vibrationStates.get("harvest")).onHarvest(); } } - + @SubscribeEvent - public static void onBreak(BlockEvent.BreakEvent event) - { - try { - Player player = event.getPlayer();; - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - BlockState blockState = event.getState(); - Block block = blockState.getBlock(); - @SuppressWarnings("ConstantConditions") float blockHardness = block.defaultBlockState().getDestroySpeed(null, null); - - LOGGER.info("Breaking: " + block.toString()); - - ItemStack mainhandItem = event.getPlayer().getMainHandItem(); - boolean usingAppropriateTool = mainhandItem.isCorrectToolForDrops(blockState); - List toolCan = ToolAction.getActions().stream().filter(a -> mainhandItem.canPerformAction(a)).collect(Collectors.toList()); - LOGGER.debug("mainhand: " + mainhandItem + " [" + toolCan + "]"); - LOGGER.debug("using pickaxe: " + mainhandItem.toString() + ", using appropriate tool: " + usingAppropriateTool); - - if (toolCan.contains(ToolAction.get("AXE")) && usingAppropriateTool) { - int duration = Math.max(1, Math.min(5, Math.toIntExact(Math.round(Math.ceil(Math.log(blockHardness + 0.5)))))); - int intensity = Math.toIntExact(Math.round((getIntensity("mine") / 100.0 * (blockHardness / 50.0)) * 100)); - setState(getStateCounter(), duration, intensity, true); - } - - LOGGER.info("XP to drop: " + event.getExpToDrop()); + public static void onPlace(BlockEvent.EntityPlaceEvent event){ + if (isPlayer(event.getEntity())) + { + ((VibrationStatePlace)vibrationStates.get("place")).onPlace(); } - } catch (Throwable e) { - LOGGER.throwing(e); - } } @SubscribeEvent @@ -333,28 +226,29 @@ public static void onXpPickup(PlayerXpEvent.PickupXp event) @SubscribeEvent public static void onXpChange(PlayerXpEvent.XpChange event) { - try { - Player player = event.getEntity(); - UUID uuid = player.getGameProfile().getId(); - - if (uuid.equals(playerId)) { - int xpChange = event.getAmount(); - long duration = Math.round(Math.ceil(Math.log(xpChange + 0.5))); - - LOGGER.info("XP CHANGE: " + xpChange); - LOGGER.debug("duration: " + duration); - - setState(getStateCounter(), Math.toIntExact(duration), getIntensity("xpChange"), true); + if (isPlayer(event.getEntity())) + { + ((VibrationStateXpChange)vibrationStates.get("xpChange")).onXpChange(((Player)event.getEntity()).totalExperience, event.getAmount()); } - } catch (Throwable e) { - LOGGER.throwing(e); } + + + @SubscribeEvent + public static void onAdvancementEvent(AdvancementEvent event) + { + if (isPlayer(event.getEntity())) + { + ((VibrationStateAdvancement)vibrationStates.get("advancement")).onAdvancement(event); + } } @SubscribeEvent public static void onRespawn(PlayerEvent.PlayerRespawnEvent event) { Entity entity = event.getEntity(); + if( !entity.level().isClientSide() ) { + return; + } if (entity instanceof Player) { LOGGER.info("Client Entered world: " + entity.toString()); @@ -379,30 +273,35 @@ public static void onRespawn(PlayerEvent.PlayerRespawnEvent event) @SubscribeEvent public static void onWorldEntry(EntityJoinLevelEvent event) { Entity entity = event.getEntity(); - if( !event.getLevel().isClientSide() ) { + if( !entity.level().isClientSide() ) { return; } + + if (ToyController.isConnected) return; if (entity instanceof Player) { LOGGER.info("Player respawn world: " + entity.toString()); - - try { + + new Thread(()-> { try { Player player = (Player) entity; UUID uuid = player.getGameProfile().getId(); - + if (uuid.equals(Minecraft.getInstance().player.getGameProfile().getId())) { LOGGER.info("Player in: " + player.getGameProfile().getName() + " " + player.getGameProfile().getId().toString()); + LOGGER.info("Stealth: " + MinegasmConfig.stealth); if (ToyController.connectDevice()) { - setState(getStateCounter(), 5); - player.displayClientMessage(Component.literal(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); - } else { + ((VibrationStateClient)vibrationStates.get("generic")).setVibration(5, 1); + if (!MinegasmConfig.stealth){ + player.displayClientMessage(Component.literal(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())), true); + } + } else if (!MinegasmConfig.stealth){ player.displayClientMessage(Component.literal(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start\n%s", ToyController.getLastErrorMessage())), false); } playerId = uuid; } } catch (Throwable e) { LOGGER.throwing(e); - } + }}).start(); } } } diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java index 2e6f091..4577128 100644 --- a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/client/ToyController.java @@ -10,10 +10,16 @@ import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.Executors; public class ToyController { private static final Logger LOGGER = LogManager.getLogger(); - private static final ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); + private static ButtplugClientWSClient client = new ButtplugClientWSClient("Minegasm"); private static ButtplugClientDevice device = null; private static boolean shutDownHookAdded = false; public static String lastErrorMessage = ""; @@ -24,9 +30,28 @@ public static boolean connectDevice() { try { device = null; client.disconnect(); + LOGGER.info("URL: " + MinegasmConfig.serverUrl); - client.connect(new URI(MinegasmConfig.serverUrl)); + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new Callable() { + public Void call() throws Exception { + client.connect(new URI(MinegasmConfig.serverUrl)); + return null; + } + }); + + try + { + future.get(3, TimeUnit.SECONDS); + } catch (TimeoutException e) { + future.cancel(true); + client = new ButtplugClientWSClient("Minegasm"); + throw new TimeoutException("Could not find WebSocket"); + } finally { + executor.shutdownNow(); + } + client.startScanning(); Thread.sleep(5000); diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java new file mode 100644 index 0000000..0ae06df --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/AbstractVibrationState.java @@ -0,0 +1,128 @@ +package com.therainbowville.minegasm.common; + +import java.util.Map; +import java.util.HashMap; + +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Architecture inspired from https://github.com/Fyustorm/mInetiface +public abstract class AbstractVibrationState +{ + + protected static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(); + protected final float streakCountdownAmount; + protected float intensity; + + protected float vibrationCountdown; + protected float vibrationFeedbackCountdown; + + protected AbstractVibrationState(float streakSeconds) + { + streakCountdownAmount = streakSeconds; + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + public void onTick() + { + if (accumulationEnabled()) + { + if (vibrationCountdown > 0) + vibrationCountdown--; + else if (intensity > 0) { + intensity = Math.max(0, intensity - 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + vibrationCountdown = Math.max(0, vibrationCountdown - 1); + } + + vibrationFeedbackCountdown = Math.max(0, vibrationFeedbackCountdown - 1); + } + + public void resetState() + { + vibrationCountdown = 0; + vibrationFeedbackCountdown = 0; + intensity = 0; + } + + protected static boolean accumulationEnabled() + { + return MinegasmConfig.mode.equals(ClientConfig.GameplayMode.ACCUMULATION); + } + + public static int getIntensity(String type) { + Map normal = new HashMap<>(); + normal.put("attack", 60); + normal.put("hurt", 0); + normal.put("mine", 80); + normal.put("place", 20); + normal.put("xpChange", 100); + normal.put("harvest", 10); + normal.put("fishing", 50); + normal.put("vitality", 0); + normal.put("advancement", 100); + + Map masochist = new HashMap<>(); + masochist.put("attack", 0); + masochist.put("hurt", 100); + masochist.put("mine", 0); + masochist.put("place", 0); + masochist.put("xpChange", 0); + masochist.put("fishing", 0); + masochist.put("harvest", 0); + masochist.put("vitality", 10); + masochist.put("advancement", 0); + + Map hedonist = new HashMap<>(); + hedonist.put("attack", 60); + hedonist.put("hurt", 10); + hedonist.put("mine", 80); + hedonist.put("place", 20); + hedonist.put("xpChange", 100); + hedonist.put("fishing", 50); + hedonist.put("harvest", 20); + hedonist.put("vitality", 10); + hedonist.put("advancement", 100); + + Map accumulation = new HashMap<>(); + accumulation.put("attack", 1); + accumulation.put("hurt", 1); + accumulation.put("mine", 1); + accumulation.put("place", 1); + accumulation.put("xpChange", 1); + accumulation.put("fishing", 50); + accumulation.put("harvest", 10); + accumulation.put("vitality", 0); + accumulation.put("advancement", 1); + + Map custom = new HashMap<>(); + custom.put("attack", MinegasmConfig.attackIntensity); + custom.put("hurt", MinegasmConfig.hurtIntensity); + custom.put("mine", MinegasmConfig.mineIntensity); + custom.put("place", MinegasmConfig.placeIntensity); + custom.put("xpChange", MinegasmConfig.xpChangeIntensity); + custom.put("fishing", MinegasmConfig.fishingIntensity); + custom.put("harvest", MinegasmConfig.harvestIntensity); + custom.put("vitality", MinegasmConfig.vitalityIntensity); + custom.put("advancement", MinegasmConfig.advancementIntensity); + + + return switch (MinegasmConfig.mode) + { + case NORMAL -> normal.get(type); + case MASOCHIST -> masochist.get(type); + case HEDONIST -> hedonist.get(type); + case ACCUMULATION -> accumulation.get(type); + case CUSTOM -> custom.get(type); + }; + } + + public abstract int getIntensity(); +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java index 82e8cf7..32b71ba 100644 --- a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/Minegasm.java @@ -1,13 +1,16 @@ package com.therainbowville.minegasm.common; -import com.therainbowville.minegasm.config.ConfigHolder; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.client.ConfigScreenHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.therainbowville.minegasm.config.ConfigHolder; +import com.therainbowville.minegasm.config.ConfigHelper; + @Mod(Minegasm.MOD_ID) public class Minegasm { @@ -21,5 +24,7 @@ public Minegasm() { context.registerConfig(ModConfig.Type.SERVER, ConfigHolder.SERVER_SPEC); MinecraftForge.EVENT_BUS.register(this); + + ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, ConfigHelper::createConfigScreenFactory); } } diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java new file mode 100644 index 0000000..3047e6c --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAdvancement.java @@ -0,0 +1,47 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementType; +import net.minecraftforge.event.entity.player.AdvancementEvent; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAdvancement extends AbstractVibrationState +{ + public VibrationStateAdvancement() + { + super(0); + } + + public void onAdvancement(AdvancementEvent event) + { + if (getIntensity("advancement") == 0) return; + try { + LOGGER.info("Advancement Event: " + event); + Advancement advancement = event.getAdvancement().value(); + if (advancement == null) return; + AdvancementType type = advancement.display().get().getType(); + int duration = switch (type) { + case TASK -> 5; + case GOAL -> 7; + case CHALLENGE -> 10; + }; + + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("advancement") + 20); + else if (vibrationCountdown > 0) + return getIntensity("advancement"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java new file mode 100644 index 0000000..acd0375 --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateAttack.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateAttack extends AbstractVibrationState +{ + public VibrationStateAttack() + { + super(3); + } + + public void onAttack() + { + if (getIntensity("attack") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * 0; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("attack") + 20); + else if (vibrationCountdown > 0) + return getIntensity("attack"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java new file mode 100644 index 0000000..c952b68 --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateClient.java @@ -0,0 +1,24 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateClient extends AbstractVibrationState +{ + public VibrationStateClient() + { + super(0); + } + + public void setVibration(int intensity, int durationSeconds) + { + intensity = intensity; + vibrationCountdown = durationSeconds * MinegasmConfig.ticksPerSecond; + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return Math.toIntExact(Math.round(intensity)); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java new file mode 100644 index 0000000..db66ed2 --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateFish.java @@ -0,0 +1,37 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateFish extends AbstractVibrationState +{ + public VibrationStateFish() + { + super(0); + } + + public void onTick(Player player) + { + if (player.fishing != null) + { + Vec3 vector = player.fishing.getDeltaMovement(); + double x = vector.x(); + double y = vector.y(); + double z = vector.z(); + if (y < -0.075 && !player.level().getFluidState(player.fishing.blockPosition()).isEmpty() && x == 0 && z == 0) + { + vibrationCountdown = 1.5f * MinegasmConfig.ticksPerSecond; + LOGGER.info("Fishing!"); + } + } + } + + public int getIntensity() + { + if (vibrationCountdown > 0) + return getIntensity("fishing"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java new file mode 100644 index 0000000..6b373cd --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHarvest.java @@ -0,0 +1,32 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHarvest extends AbstractVibrationState +{ + private VibrationStateMine mineState; + + public VibrationStateHarvest(VibrationStateMine state) + { + super(0); + mineState = state; + } + + public void onHarvest() { + vibrationCountdown = 3; + mineState.onHarvest(); + } + + public int getIntensity() + { + if (vibrationCountdown > 0){ + if (accumulationEnabled()) + return Math.min(100, mineState.getIntensity() + 20); + else + return getIntensity("harvest"); + } + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java new file mode 100644 index 0000000..7219c5e --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateHurt.java @@ -0,0 +1,36 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateHurt extends AbstractVibrationState +{ + public VibrationStateHurt() + { + super(3); + } + + public void onHurt() { + if (getIntensity("hurt") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + 10); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("hurt") + 20); + else if (vibrationCountdown > 0) + return getIntensity("hurt"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java new file mode 100644 index 0000000..e4c467d --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateMine.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.level.block.state.BlockState; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateMine extends AbstractVibrationState +{ + public VibrationStateMine() + { + super(5); + } + + public void onBreak(BlockState block) { + if (getIntensity("mine") == 0) return; + + String blockName = block.getBlock().getName().getString(); + if (accumulationEnabled()) + { + if (blockName.contains("Ore")) { + intensity = Math.min(100, intensity + 1); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + intensity = Math.min(100, intensity + .25f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + } + } else { + if (blockName.contains("Ore")) { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public void onHarvest() { + if (accumulationEnabled()){ + vibrationCountdown = Math.max(3, vibrationCountdown); + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("mine") + 20); + else if (vibrationCountdown > 0) + return getIntensity("mine"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java new file mode 100644 index 0000000..aee4ebf --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStatePlace.java @@ -0,0 +1,35 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStatePlace extends AbstractVibrationState +{ + public VibrationStatePlace() + { + super(5); + } + + public void onPlace() { + if (getIntensity("place") == 0) return; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + .5f); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + vibrationCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("place") + 20); + else if (vibrationCountdown > 0) + return getIntensity("place"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java new file mode 100644 index 0000000..5824f8f --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateVitality.java @@ -0,0 +1,62 @@ +package com.therainbowville.minegasm.common; + +import net.minecraft.world.entity.player.Player; + +import com.therainbowville.minegasm.config.MinegasmConfig; +import com.therainbowville.minegasm.config.ClientConfig; + +public class VibrationStateVitality extends AbstractVibrationState +{ + private int intensityCooldown; + private boolean targetMet; + + public VibrationStateVitality() + { + super(1); + intensityCooldown = 0; + targetMet = false; + } + + public void onTick(Player player) + { + float playerHealth = player.getHealth(); + float playerFoodLevel = player.getFoodData().getFoodLevel(); + + if ((MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth > 0 && playerHealth <= 1 ) + || (!MinegasmConfig.mode.equals(ClientConfig.GameplayMode.MASOCHIST) && playerHealth >= 20 && playerFoodLevel >= 20) ){ + + if (targetMet == false){ + targetMet = true; + vibrationFeedbackCountdown = 3 * MinegasmConfig.ticksPerSecond; + } + } else + targetMet = false; + +// if (accumulationEnabled() && targetMet) +// { +// if (intensityCooldown == 0) { +// intensity = Math.min(100, intensity + .1f); +// intensityCooldown = 10 * 20; +// } +// vibrationCountdown = streakCountdownAmount; +// intensityCooldown = Math.max(0, intensityCooldown - 1); +// } else + if (targetMet) { + vibrationCountdown = 1; + } + } + + public int getIntensity() + { + if (getIntensity("vitality") == 0) return 0; + + //if (accumulationEnabled()) + //return Math.toIntExact(Math.round(intensity)); + //else + if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("vitality") + 20); + else if (vibrationCountdown > 0) + return getIntensity("vitality"); + else return 0; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java new file mode 100644 index 0000000..34b1633 --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/common/VibrationStateXpChange.java @@ -0,0 +1,53 @@ +package com.therainbowville.minegasm.common; + +import com.therainbowville.minegasm.config.MinegasmConfig; + +public class VibrationStateXpChange extends AbstractVibrationState +{ + private int lastLevel; + + public VibrationStateXpChange() + { + super(1); + lastLevel = -1; + } + + // Code adapted from https://github.com/Fyustorm/mInetiface + public void onXpChange(int level, int amount) { + if (amount == 0 || getIntensity("xpChange") == 0) + return; + + if (lastLevel == -1) { + lastLevel = level; + } + + if (lastLevel != level) { + amount *= 2; + } + + lastLevel = level; + + if (accumulationEnabled()) + { + intensity = Math.min(100, intensity + amount / 5); + vibrationCountdown = streakCountdownAmount * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } else { + int duration = Math.toIntExact( Math.round( Math.ceil( Math.log(amount + 0.5) ) ) ); + vibrationCountdown = duration * MinegasmConfig.ticksPerSecond; + vibrationFeedbackCountdown = 1 * MinegasmConfig.ticksPerSecond; + } + } + + public int getIntensity() + { + if (accumulationEnabled()) + return Math.toIntExact(Math.round(intensity)); + else if (vibrationFeedbackCountdown > 0) + return Math.min(100, getIntensity("xpChange") + 20); + else if (vibrationCountdown > 0) + return getIntensity("xpChange"); + else return 0; + } +} + diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java index 7bc1bc2..c3ca8ff 100644 --- a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ClientConfig.java @@ -1,9 +1,11 @@ package com.therainbowville.minegasm.config; import com.therainbowville.minegasm.common.Minegasm; -import net.minecraft.client.Minecraft; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.fml.mclanguageprovider.MinecraftModLanguageProvider; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.common.ForgeConfigSpec.IntValue; import java.util.Objects; @@ -12,19 +14,41 @@ public final class ClientConfig { final ForgeConfigSpec.BooleanValue vibrate; final ForgeConfigSpec.EnumValue mode; + final ForgeConfigSpec.BooleanValue stealth; + final ForgeConfigSpec.EnumValue tickFrequency; + final ForgeConfigSpec.IntValue attackIntensity; final ForgeConfigSpec.IntValue hurtIntensity; final ForgeConfigSpec.IntValue mineIntensity; + final ForgeConfigSpec.IntValue placeIntensity; final ForgeConfigSpec.IntValue xpChangeIntensity; + final ForgeConfigSpec.IntValue fishingIntensity; final ForgeConfigSpec.IntValue harvestIntensity; final ForgeConfigSpec.IntValue vitalityIntensity; + final ForgeConfigSpec.IntValue advancementIntensity; + + static final String DEFAULT_SERVER_URL = "ws://localhost:12345/buttplug"; + static final boolean DEFAULT_VIBRATE = true; + static final GameplayMode DEFAULT_MODE = GameplayMode.NORMAL; + static final boolean DEFAULT_STEALTH = false; + + static final int DEFAULT_ATTACK_INTENSITY = 60; + static final int DEFAULT_HURT_INTENSITY = 0; + static final int DEFAULT_MINE_INTENSITY = 80; + static final int DEFAULT_PLACE_INTENSITY = 20; + static final int DEFAULT_XP_CHANGE_INTENSITY = 100; + static final int DEFAULT_FISHING_INTENSITY = 50; + static final int DEFAULT_HARVEST_INTENSITY = 0; + static final int DEFAULT_VITALITY_INTENSITY = 0; + static final int DEFAULT_ADVANCEMENT_INTENSITY = 100; + ClientConfig(final ForgeConfigSpec.Builder builder) { builder.push("buttplug"); serverUrl = builder .translation(Minegasm.MOD_ID + ".config.serverUrl") - .define("serverUrl", "ws://localhost:12345/buttplug"); + .define("serverUrl", DEFAULT_SERVER_URL); builder.pop(); @@ -32,50 +56,92 @@ public final class ClientConfig { vibrate = builder .translation(Minegasm.MOD_ID + ".config.vibrate") - .define("vibrate", true); + .define("vibrate", DEFAULT_VIBRATE); mode = builder .translation(Minegasm.MOD_ID + ".config.mode") - .defineEnum("mode", GameplayMode.NORMAL); + .defineEnum("mode", DEFAULT_MODE); + stealth = builder + .translation(Minegasm.MOD_ID + ".config.stealth") + .define("stealth", DEFAULT_STEALTH); + + tickFrequency = builder + .translation(Minegasm.MOD_ID + ".config.mode") + .defineEnum("tickFrequency", TickFrequencyOptions.EVERY_TICK); builder.push("intensity"); attackIntensity = builder .comment("Vibration intensity when attacking on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.attack") - .defineInRange("attackIntensity", 60, 0, 100); + .defineInRange("attackIntensity", DEFAULT_ATTACK_INTENSITY, 0, 100); hurtIntensity = builder .comment("Vibration intensity when hurting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.hurt") - .defineInRange("hurtIntensity", 0, 0, 100); + .defineInRange("hurtIntensity", DEFAULT_HURT_INTENSITY, 0, 100); mineIntensity = builder .comment("Vibration intensity when mining on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.mine") - .defineInRange("mineIntensity", 80, 0, 100); + .defineInRange("mineIntensity", DEFAULT_MINE_INTENSITY, 0, 100); + + placeIntensity = builder + .comment("Vibration intensity when placing blocks on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.place") + .defineInRange("placeIntensity", DEFAULT_PLACE_INTENSITY, 0, 100); xpChangeIntensity = builder .comment("Vibration intensity when gaining XP on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.xp_change") - .defineInRange("xpChangeIntensity", 100, 0, 100); + .defineInRange("xpChangeIntensity", DEFAULT_XP_CHANGE_INTENSITY, 0, 100); + + fishingIntensity = builder + .comment("Vibration intensity when fishing on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.fishing") + .defineInRange("fishingIntensity", DEFAULT_FISHING_INTENSITY, 0, 100); harvestIntensity = builder .comment("Vibration intensity when harvesting on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.harvest") - .defineInRange("harvestIntensity", 0, 0, 100); + .defineInRange("harvestIntensity", DEFAULT_HARVEST_INTENSITY, 0, 100); vitalityIntensity = builder .comment("Vibration intensity on high level of player's vitality on custom mode") .translation(Minegasm.MOD_ID + ".config.intensity.vitality") - .defineInRange("vitalityIntensity", 0, 0, 100); + .defineInRange("vitalityIntensity", DEFAULT_VITALITY_INTENSITY, 0, 100); + + advancementIntensity = builder + .comment("Vibration intensity on achieving advancement on custom mode") + .translation(Minegasm.MOD_ID + ".config.intensity.advancement") + .defineInRange("advancementIntensity", DEFAULT_ADVANCEMENT_INTENSITY, 0, 100); builder.pop(); builder.pop(); } + + public void resetConfigUrl() + { + ConfigHolder.CLIENT.serverUrl.set(DEFAULT_SERVER_URL); + } + + public void resetConfigCustom() + { + ConfigHolder.CLIENT.attackIntensity.set(DEFAULT_ATTACK_INTENSITY); + ConfigHolder.CLIENT.hurtIntensity.set(DEFAULT_HURT_INTENSITY); + ConfigHolder.CLIENT.mineIntensity.set(DEFAULT_MINE_INTENSITY); + ConfigHolder.CLIENT.placeIntensity.set(DEFAULT_PLACE_INTENSITY); + ConfigHolder.CLIENT.xpChangeIntensity.set(DEFAULT_XP_CHANGE_INTENSITY); + ConfigHolder.CLIENT.fishingIntensity.set(DEFAULT_FISHING_INTENSITY); + ConfigHolder.CLIENT.harvestIntensity.set(DEFAULT_HARVEST_INTENSITY); + ConfigHolder.CLIENT.vitalityIntensity.set(DEFAULT_VITALITY_INTENSITY); + ConfigHolder.CLIENT.advancementIntensity.set(DEFAULT_ADVANCEMENT_INTENSITY); + } + public enum GameplayMode { NORMAL("gui." + Minegasm.MOD_ID + ".config.mode.normal"), MASOCHIST("gui." + Minegasm.MOD_ID + ".config.mode.masochist"), HEDONIST("gui." + Minegasm.MOD_ID + ".config.mode.hedonist"), + ACCUMULATION("gui." + Minegasm.MOD_ID + ".config.mode.accumulation"), CUSTOM("gui." + Minegasm.MOD_ID + ".config.mode.custom"); private final String translateKey; @@ -89,4 +155,37 @@ public String getTranslateKey() { return this.translateKey; } } + + public enum TickFrequencyOptions { + EVERY_TICK(1), + EVERY_OTHER_TICK(2), + EVERY_5_TICKS(5), + EVERY_10_TICKS(10), + EVERY_20_TICKS(20), + EVERY_30_TICKS(30), + EVERY_40_TICKS(40), + EVERY_50_TICKS(50); + + private int value; + + TickFrequencyOptions(int value) { + this.value = value; + } + + public int getInt() + { + return value; + } + + public static TickFrequencyOptions fromInt(int value) + { + for (TickFrequencyOptions type : values()) { + if (type.getInt() == value) { + return type; + } + } + return null; + } + } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java index 4441fb2..e51ab15 100644 --- a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHelper.java @@ -1,20 +1,79 @@ package com.therainbowville.minegasm.config; +import net.minecraftforge.client.ConfigScreenHandler; +import net.minecraftforge.common.ForgeConfigSpec; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public final class ConfigHelper { + private static final Logger LOGGER = LogManager.getLogger(); public static void bakeClient() { MinegasmConfig.serverUrl = ConfigHolder.CLIENT.serverUrl.get(); MinegasmConfig.vibrate = ConfigHolder.CLIENT.vibrate.get(); MinegasmConfig.mode = ConfigHolder.CLIENT.mode.get(); + MinegasmConfig.stealth = ConfigHolder.CLIENT.stealth.get(); + MinegasmConfig.tickFrequency = ConfigHolder.CLIENT.tickFrequency.get().getInt(); + MinegasmConfig.ticksPerSecond = Math.max(0, 20f / MinegasmConfig.tickFrequency); + MinegasmConfig.attackIntensity = ConfigHolder.CLIENT.attackIntensity.get(); MinegasmConfig.hurtIntensity = ConfigHolder.CLIENT.hurtIntensity.get(); MinegasmConfig.mineIntensity = ConfigHolder.CLIENT.mineIntensity.get(); + MinegasmConfig.placeIntensity = ConfigHolder.CLIENT.placeIntensity.get(); MinegasmConfig.xpChangeIntensity = ConfigHolder.CLIENT.xpChangeIntensity.get(); + MinegasmConfig.fishingIntensity = ConfigHolder.CLIENT.fishingIntensity.get(); MinegasmConfig.harvestIntensity = ConfigHolder.CLIENT.harvestIntensity.get(); MinegasmConfig.vitalityIntensity = ConfigHolder.CLIENT.vitalityIntensity.get(); + MinegasmConfig.advancementIntensity = ConfigHolder.CLIENT.advancementIntensity.get(); } public static void bakeServer() { } + + public static void saveClient() + { + try{ + + MinegasmConfigBuffer buffer = new MinegasmConfigBuffer(); + +// Field[] fields = MinegasmConfigBuffer.class.getFields(); + +// for (Field field : fields) +// { +// Field configField = ConfigHolder.CLIENT.getClass().getDeclaredField(field.getName()); // Get Corisponding Field in CLIENT +// Class configFieldClass = configField.getType(); // Get the configField Class +// Method method = configFieldClass.getMethod("set", Object.class); +// LOGGER.info(method); +// method.invoke(configField.get(ConfigHolder.CLIENT), field.get(buffer)); +// } + + ConfigHolder.CLIENT.serverUrl.set(buffer.serverUrl); + ConfigHolder.CLIENT.vibrate.set(buffer.vibrate); + ConfigHolder.CLIENT.mode.set(buffer.mode); + ConfigHolder.CLIENT.stealth.set(buffer.stealth); + ConfigHolder.CLIENT.tickFrequency.set(ClientConfig.TickFrequencyOptions.fromInt(buffer.tickFrequency)); + + ConfigHolder.CLIENT.attackIntensity.set(buffer.attackIntensity); + ConfigHolder.CLIENT.hurtIntensity.set(buffer.hurtIntensity); + ConfigHolder.CLIENT.mineIntensity.set(buffer.mineIntensity); + ConfigHolder.CLIENT.placeIntensity.set(buffer.placeIntensity); + ConfigHolder.CLIENT.xpChangeIntensity.set(buffer.xpChangeIntensity); + ConfigHolder.CLIENT.fishingIntensity.set(buffer.fishingIntensity); + ConfigHolder.CLIENT.harvestIntensity.set(buffer.harvestIntensity); + ConfigHolder.CLIENT.vitalityIntensity.set(buffer.vitalityIntensity); + ConfigHolder.CLIENT.advancementIntensity.set(buffer.advancementIntensity); + } catch (Throwable e) + { + LOGGER.info(e); + } + } + + public static ConfigScreenHandler.ConfigScreenFactory createConfigScreenFactory() { + return new ConfigScreenHandler.ConfigScreenFactory((minecraft, screen) -> new ConfigScreen(screen)); + } } \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java index b422dfa..7687547 100644 --- a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigHolder.java @@ -29,4 +29,5 @@ public static ClientConfig getClientInstance() { public static ServerConfig getServerInstance() { return SERVER; } + } \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java new file mode 100644 index 0000000..0b06af7 --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/ConfigScreen.java @@ -0,0 +1,357 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraftforge.client.gui.widget.ForgeSlider; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Component; +import net.minecraftforge.event.TickEvent; +import net.minecraft.client.Minecraft; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.client.ToyController; +import com.therainbowville.minegasm.client.ClientEventHandler; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import java.lang.reflect.Field; +import java.lang.Thread; +import java.util.ArrayList; +import java.util.function.IntConsumer; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class ConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + EditBox wsHost = null; + + public ConfigScreen(Screen previous) { + super(Component.literal("Minegasm Config")); + this.previous = previous; + pauseMenu = false; + } + + public ConfigScreen(Screen previous, boolean pause) { + super(Component.literal("Minegasm Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + wsHost = new EditBox(Minecraft.getInstance().font, this.width / 2 - 100, this.height / 6, 200, 20, null); + wsHost.setValue(MinegasmConfig.serverUrl); + this.addRenderableWidget(wsHost); + + wsHost.setResponder(s -> { + LOGGER.info(s); + MinegasmConfig.serverUrl = s; + }); + + this.addRenderableWidget(new Button.Builder(Component.literal("Reset Server Url"), button -> { + ConfigHolder.getClientInstance().resetConfigUrl(); + MinegasmConfig.serverUrl = ConfigHolder.getClientInstance().serverUrl.get(); + wsHost.setValue(MinegasmConfig.serverUrl); + }).pos(this.width / 2 - 155, this.height / 6 + 25) + .size(150, 20) + .build() + ); + + PlainTextLabel connectResponse = new PlainTextLabel(this.width / 2 - 155, this.height / 6 + 50, 310, 15, Component.literal("" + ChatFormatting.GREEN)); + + this.addRenderableWidget(connectResponse); + + Button reconnectButton = new Button.Builder(Component.literal("Reconnect"), button -> { + button.active = false; + connectResponse.setValue("Connecting"); + new Thread(() -> { + if (ToyController.connectDevice()) { + ClientEventHandler.afterConnect(); + button.active = true; + connectResponse.setValue(String.format("Connected to " + ChatFormatting.GREEN + "%s" + ChatFormatting.RESET + " [%d]", ToyController.getDeviceName(), ToyController.getDeviceId())); + } else { + button.active = true; + connectResponse.setValue(String.format(ChatFormatting.YELLOW + "Minegasm " + ChatFormatting.RESET + "failed to start: %s", ToyController.getLastErrorMessage())); + } + + }).start(); + }) + .pos(this.width / 2 + 5, this.height / 6 + 25) + .size(150, 20) + .build(); + + this.addRenderableWidget(reconnectButton); + + reconnectButton.active = pauseMenu; + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.vibrate) + .create(this.width / 2 - 155, this.height / 6 + 25 * 3, 150, 20, + Component.literal("Vibration"), (button, value) -> MinegasmConfig.vibrate = value)); + + this.addRenderableWidget(CycleButton.onOffBuilder(MinegasmConfig.stealth) + .create(this.width / 2 + 5, this.height / 6 + 25 * 3, 150, 20, + Component.literal("Stealth"), (button, value) -> MinegasmConfig.stealth = value)); + + this.addRenderableWidget( + CycleButton.builder((ClientConfig.GameplayMode mode) -> + Component.literal(switch (mode) { + case NORMAL -> "Normal"; + case MASOCHIST -> "Masochist"; + case HEDONIST -> "Hedonist"; + case ACCUMULATION -> "Accumulation"; + case CUSTOM -> "Custom"; + })) + .withValues(ClientConfig.GameplayMode.NORMAL, ClientConfig.GameplayMode.MASOCHIST, ClientConfig.GameplayMode.HEDONIST, ClientConfig.GameplayMode.ACCUMULATION, ClientConfig.GameplayMode.CUSTOM) + .withInitialValue(MinegasmConfig.mode) + .create(this.width / 2 - 155, this.height / 6 + 25 * 4, 150, 20, + Component.literal("Mode"), (button, value) -> { + MinegasmConfig.mode = value; + }) + ); + + this.addRenderableWidget(new Button.Builder(Component.literal("Edit Custom Settings"), button -> minecraft.setScreen(new CustomModeConfigScreen(this, pauseMenu))) + .pos(this.width / 2 + 5, this.height / 6 + 25 * 4) + .size(150, 20) + .build() + ); + + this.addRenderableWidget( + CycleButton.builder((Integer tickFrequency) -> + Component.literal(switch (tickFrequency) { + case 1 -> "Every Tick"; + case 2 -> "Every Other Tick"; + case 5 -> "Every 5 Ticks"; + case 10 -> "Every 10 Ticks"; + case 20 -> "Every Second"; + default -> "Every " + Float.toString(tickFrequency / 20f)+ " Seconds"; + })) + .withValues(1, 2, 5, 10, 20, 30, 40, 50) + .withInitialValue(MinegasmConfig.tickFrequency) + .create(this.width / 2 - 100, this.height / 6 + 25 * 5, 200, 20, + Component.literal("Tick Frequency"), (button, value) -> { + MinegasmConfig.tickFrequency = value; + MinegasmConfig.ticksPerSecond = Math.max(0, 20f / MinegasmConfig.tickFrequency); + LOGGER.info("TPS: " + MinegasmConfig.ticksPerSecond); + } + ) + ); + + this.addRenderableWidget(new Button.Builder(CommonComponents.GUI_DONE, button -> this.onClose()) + .pos(this.width / 2 - 100, this.height - 27) + .size(200, 20) + .build() + ); + + + } + + @Override + public void tick() { + super.tick(); + + // Add ticking logic for EditBox in editBox +// if (this.wsHost != null) +// this.wsHost.tick(); + } + + @Override + public void onClose() { + PlainTextLabel.setValue(""); + this.minecraft.setScreen(previous); + MinegasmConfig.save(); + } + + @Override + public void render(GuiGraphics graphics, int i, int j, float f) { +// if (pauseMenu) +// this.renderTransparentBackground(graphics); +// else +// this.renderDirtBackground(graphics); + graphics.drawCenteredString(this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(graphics, i, j, f); + } + + class PlainTextLabel extends AbstractWidget { + + private static Component text = Component.literal(""); + private int x; + private int y; + + public PlainTextLabel(int x, int y, int width, int height, Component text) { + super(x, y, width, height, text); + this.x = x; + this.y = y; + } + + public static void setValue(String value) + { + text = Component.literal(value); + } + + @Override + public void updateWidgetNarration(NarrationElementOutput output) { + defaultButtonNarrationText(output); + } + + @Override + public void renderWidget(GuiGraphics graphics, int i, int j, float f) { + if (text == null || text.getString().isEmpty()) + return; + +// RenderSystem.setShaderColor(1, 1, 1, 1); +// Minecraft.getInstance().font.draw(poseStack, text.getString(), x, y, 0xFFFFFF); + graphics.drawCenteredString(Minecraft.getInstance().font, text.getString(), Minecraft.getInstance().screen.width / 2, this.y + this.height / 4, 0xFFFFFF); + } + } + +} + +class CustomModeConfigScreen extends Screen { + private static final Logger LOGGER = LogManager.getLogger(); + private final Screen previous; + private boolean pauseMenu; + + public CustomModeConfigScreen(Screen previous) { + super(Component.literal("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = false; + } + + public CustomModeConfigScreen(Screen previous, boolean pause) { + super(Component.literal("Minegasm Custom Config")); + this.previous = previous; + pauseMenu = pause; + } + + @Override + protected void init() { + try{ + this.addRenderableWidget(new Button.Builder(CommonComponents.GUI_DONE, button -> this.onClose()) + .pos(this.width / 2 + 5, this.height - 27) + .size(150, 20) + .build() + ); + + IntensitiySliderBar.sliders.clear(); + + // Attack + this.addRenderableWidget(new IntensitiySliderBar(this, "Attack: ", MinegasmConfig.class.getField("attackIntensity"))); + + // Hurt + this.addRenderableWidget(new IntensitiySliderBar(this, "Hurt: ", MinegasmConfig.class.getField("hurtIntensity"))); + + // Mine + this.addRenderableWidget(new IntensitiySliderBar(this, "Mine: ", MinegasmConfig.class.getField("mineIntensity"))); + + // Place + this.addRenderableWidget(new IntensitiySliderBar(this, "Place: ", MinegasmConfig.class.getField("placeIntensity"))); + + // XP Change + this.addRenderableWidget(new IntensitiySliderBar(this, "XP Change: ", MinegasmConfig.class.getField("xpChangeIntensity"))); + + // Fishing + this.addRenderableWidget(new IntensitiySliderBar(this, "Fishing: ", MinegasmConfig.class.getField("fishingIntensity"))); + + // Harvest + this.addRenderableWidget(new IntensitiySliderBar(this, "Harvest: ", MinegasmConfig.class.getField("harvestIntensity"))); + + // Vitality + this.addRenderableWidget(new IntensitiySliderBar(this, "Vitality: ", MinegasmConfig.class.getField("vitalityIntensity"))); + + // Advancement + this.addRenderableWidget(new IntensitiySliderBar(this, "Advancement: ", MinegasmConfig.class.getField("advancementIntensity"))); + + this.addRenderableWidget(new Button.Builder(Component.literal("Reset Values"), button -> { + ConfigHolder.getClientInstance().resetConfigCustom(); + IntensitiySliderBar.refreshAllValues(); + }) + .pos(this.width / 2 - 155, this.height - 27) + .size(150, 20) + .build() + ); + + + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + @Override + public void onClose() { + IntensitiySliderBar.sliders.clear(); + this.minecraft.setScreen(previous); + } + + @Override + public void render(GuiGraphics graphics, int i, int j, float f) { +// if (pauseMenu) +// this.renderTransparentBackground(graphics); +// else +// this.renderDirtBackground(graphics); + graphics.drawCenteredString(this.font, this.title, this.width / 2, 15, 0xFFFFFF); + super.render(graphics, i, j, f); + } + + private class IntensitiySliderBar extends ForgeSlider + { + public static ArrayList sliders = new ArrayList(); + private Field fieldReference; + + IntensitiySliderBar(CustomModeConfigScreen parent, String prefix, Field field) throws Exception + { + super( parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155), // x pos + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2), // y pos + 150, 20, // Width, height + Component.literal(prefix), // Prefix + Component.literal(""), // Suffix + 0, 100, field.getInt(null), 1, 1, true); // Min, Max, Default value, stepsize, percision, drawstring + fieldReference = field; +// LOGGER.info("S: " + sliders.size() + " X: " + parent.width / 2 + (sliders.size() % 2 == 1 ? 5 : -155) + " Y: " + parent.height / 6 + 25 * (int)Math.floor(sliders.size() / 2)); + sliders.add(this); + } + + @Override + public void applyValue() + { +// LOGGER.info("applyValue"); + //responder.accept(this.getValueInt()); + try { + fieldReference.set(null, this.getValueInt()); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + public static void refreshAllValues() + { + for (IntensitiySliderBar slider : sliders) + { + slider.refreshValue(); + } + } + + private void refreshValue() + { + try { + this.setValue(fieldReference.getInt(null)); + } catch (Throwable e) { + LOGGER.throwing(e); + } + } + + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java index 52965d5..cb0e2fd 100644 --- a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/MinegasmConfig.java @@ -18,13 +18,20 @@ public class MinegasmConfig { public static String serverUrl; public static boolean vibrate; - public static Enum mode = ClientConfig.GameplayMode.NORMAL; + public static ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public static boolean stealth; + public static int tickFrequency; + public static float ticksPerSecond; + public static int attackIntensity; public static int hurtIntensity; public static int mineIntensity; + public static int placeIntensity; public static int xpChangeIntensity; + public static int fishingIntensity; public static int harvestIntensity; public static int vitalityIntensity; + public static int advancementIntensity; // Server // -- none at the moment @@ -41,4 +48,49 @@ public static void onModConfigEvent(final ModConfigEvent event) { LOGGER.debug("Baked server config"); } } + + public static void save() + { + ConfigHelper.saveClient(); + } + } + +class MinegasmConfigBuffer +{ + public String serverUrl; + + public boolean vibrate; + public ClientConfig.GameplayMode mode = ClientConfig.GameplayMode.NORMAL; + public boolean stealth; + public int tickFrequency; + + public int attackIntensity; + public int hurtIntensity; + public int mineIntensity; + public int placeIntensity; + public int xpChangeIntensity; + public int fishingIntensity; + public int harvestIntensity; + public int vitalityIntensity; + public int advancementIntensity; + + MinegasmConfigBuffer() + { + this.serverUrl = MinegasmConfig.serverUrl; + this.vibrate = MinegasmConfig.vibrate; + this.mode = MinegasmConfig.mode; + this.stealth = MinegasmConfig.stealth; + this.tickFrequency = MinegasmConfig.tickFrequency; + + this.attackIntensity = MinegasmConfig.attackIntensity; + this.hurtIntensity = MinegasmConfig.hurtIntensity; + this.mineIntensity = MinegasmConfig.mineIntensity; + this.placeIntensity = MinegasmConfig.placeIntensity; + this.xpChangeIntensity = MinegasmConfig.xpChangeIntensity; + this.fishingIntensity = MinegasmConfig.fishingIntensity; + this.harvestIntensity = MinegasmConfig.harvestIntensity; + this.vitalityIntensity = MinegasmConfig.vitalityIntensity; + this.advancementIntensity = MinegasmConfig.advancementIntensity; + } +} \ No newline at end of file diff --git a/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java new file mode 100644 index 0000000..ae74e11 --- /dev/null +++ b/forge/fg-6.0/1.20.4/src/main/java/com/therainbowville/minegasm/config/PauseMenuButton.java @@ -0,0 +1,132 @@ +package com.therainbowville.minegasm.config; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.PauseScreen; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ScreenEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.commons.lang3.mutable.MutableObject; + +import com.therainbowville.minegasm.common.Minegasm; +import com.therainbowville.minegasm.config.ClientConfig; +import com.therainbowville.minegasm.config.MinegasmConfig; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +// Adapted from https://github.com/Creators-of-Create/Create/ +public class PauseMenuButton extends Button +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static ResourceLocation LOGO = new ResourceLocation(Minegasm.MOD_ID, "textures/logo.png"); + + int xPos; + int yPos; + + public PauseMenuButton(int x, int y) { + super(new Button.Builder(Component.literal(""), PauseMenuButton::clicked).pos(x, y).size(20, 20)); + xPos = x; + yPos = y; + } + + @Override + public void renderWidget(GuiGraphics graphics, int i, int j, float k) { + super.renderWidget(graphics, i, j, k); + graphics.pose().pushPose(); + graphics.pose().translate(xPos + width / 2 - (64 * 0.25f) / 2, yPos + height / 2 - (64 * 0.25f) / 2, 0); + graphics.pose().scale(0.25f, 0.25f, 1); + RenderSystem.setShaderTexture(0, LOGO); + graphics.blit(LOGO, 0, 0, 0, 0, 64, 64, 64, 64); + graphics.pose().popPose(); + } + + public static void clicked(Button button) + { + Minecraft.getInstance().setScreen(new ConfigScreen(Minecraft.getInstance().screen, true)); + } + + public static class SingleMenuRow { + public final String left, right; + public SingleMenuRow(String left, String right) { + this.left = I18n.get(left); + this.right = I18n.get(right); + } + public SingleMenuRow(String center) { + this(center, center); + } + } + + public static class MenuRows { + public static final MenuRows MAIN_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.singleplayer"), + new SingleMenuRow("menu.multiplayer"), + new SingleMenuRow("fml.menu.mods", "menu.online"), + new SingleMenuRow("narrator.button.language", "narrator.button.accessibility") + )); + + public static final MenuRows INGAME_MENU = new MenuRows(Arrays.asList( + new SingleMenuRow("menu.returnToGame"), + new SingleMenuRow("gui.advancements", "gui.stats"), + new SingleMenuRow("menu.sendFeedback", "menu.reportBugs"), + new SingleMenuRow("menu.options", "menu.shareToLan"), + new SingleMenuRow("menu.returnToMenu") + )); + + protected final List leftButtons, rightButtons; + + public MenuRows(List variants) { + leftButtons = variants.stream().map(r -> r.left).collect(Collectors.toList()); + rightButtons = variants.stream().map(r -> r.right).collect(Collectors.toList()); + } + } + + @Mod.EventBusSubscriber(modid = Minegasm.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) + public class PauseMenuButtonScreen { + + @SubscribeEvent + public static void onGuiInit(ScreenEvent.Init event) { + if(event.getScreen() instanceof PauseScreen) { // Make sure GUI is Escape menu + MenuRows menu = MenuRows.INGAME_MENU; + int rowIdx = 3; + int offsetX = 4; + boolean onLeft = offsetX < 0; + String target = (onLeft ? menu.leftButtons : menu.rightButtons).get(rowIdx - 1); + + int offsetX_ = offsetX; + MutableObject toAdd = new MutableObject<>(null); + event.getListenersList() + .stream() + .filter(w -> w instanceof AbstractWidget) + .map(w -> (AbstractWidget) w) + .filter(w -> w.getMessage() + .getString() + .equals(target)) + .findFirst() + .ifPresent(w -> toAdd + .setValue(new PauseMenuButton(w.getX() + offsetX_ + (onLeft ? -20 : w.getWidth()), w.getY()))); + if (toAdd.getValue() != null) + event.addListener(toAdd.getValue()); + } + } + } +} diff --git a/forge/fg-6.0/1.20.4/src/main/resources/assets/minegasm/textures/logo.png b/forge/fg-6.0/1.20.4/src/main/resources/assets/minegasm/textures/logo.png new file mode 100644 index 0000000..63eaa64 Binary files /dev/null and b/forge/fg-6.0/1.20.4/src/main/resources/assets/minegasm/textures/logo.png differ