Initial commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
package net.fretux.mindmotion;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.fretux.mindmotion.event.CombatEvents;
|
||||
import net.fretux.mindmotion.event.PlayerTickHandler;
|
||||
import net.fretux.mindmotion.network.ModMessages;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@Mod(AscendMindMotion.MODID)
|
||||
public class AscendMindMotion {
|
||||
public static final String MODID = "mindmotion";
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public AscendMindMotion() {
|
||||
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
modEventBus.addListener(this::commonSetup);
|
||||
MinecraftForge.EVENT_BUS.register(PlayerTickHandler.class);
|
||||
MinecraftForge.EVENT_BUS.register(CombatEvents.class);
|
||||
LOGGER.info("Ascend: Mind and Motion initialized!");
|
||||
}
|
||||
|
||||
private void commonSetup(final FMLCommonSetupEvent event) {
|
||||
ModMessages.register();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package net.fretux.mindmotion;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.config.ModConfigEvent;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = AscendMindMotion.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class Config
|
||||
{
|
||||
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||
|
||||
private static final ForgeConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
|
||||
.comment("Whether to log the dirt block on common setup")
|
||||
.define("logDirtBlock", true);
|
||||
|
||||
private static final ForgeConfigSpec.IntValue MAGIC_NUMBER = BUILDER
|
||||
.comment("A magic number")
|
||||
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
|
||||
|
||||
public static final ForgeConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
|
||||
.comment("What you want the introduction message to be for the magic number")
|
||||
.define("magicNumberIntroduction", "The magic number is... ");
|
||||
|
||||
private static final ForgeConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
|
||||
.comment("A list of items to log on common setup.")
|
||||
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName);
|
||||
|
||||
static final ForgeConfigSpec SPEC = BUILDER.build();
|
||||
|
||||
public static boolean logDirtBlock;
|
||||
public static int magicNumber;
|
||||
public static String magicNumberIntroduction;
|
||||
public static Set<Item> items;
|
||||
|
||||
private static boolean validateItemName(final Object obj)
|
||||
{
|
||||
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(new ResourceLocation(itemName));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
static void onLoad(final ModConfigEvent event)
|
||||
{
|
||||
logDirtBlock = LOG_DIRT_BLOCK.get();
|
||||
magicNumber = MAGIC_NUMBER.get();
|
||||
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
|
||||
items = ITEM_STRINGS.get().stream()
|
||||
.map(itemName -> ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemName)))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.fretux.mindmotion.client;
|
||||
|
||||
public class ClientData {
|
||||
public static float SANITY = 80f;
|
||||
public static float INSANITY = 0f;
|
||||
public static int TEMPO = 0;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package net.fretux.mindmotion.client;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderGuiOverlayEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "mindmotion", value = Dist.CLIENT)
|
||||
public class SanityTempoOverlay {
|
||||
|
||||
private static final int BAR_WIDTH = 102;
|
||||
private static final int BAR_HEIGHT = 9;
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderOverlay(RenderGuiOverlayEvent.Post event) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.player == null || mc.options.hideGui) return;
|
||||
|
||||
GuiGraphics gui = event.getGuiGraphics();
|
||||
int width = event.getWindow().getGuiScaledWidth();
|
||||
int height = event.getWindow().getGuiScaledHeight();
|
||||
|
||||
int y = height - 48;
|
||||
int xTempo = 8;
|
||||
int xSanity = width - BAR_WIDTH - 8;
|
||||
|
||||
float sanity = ClientData.SANITY;
|
||||
float insanity = ClientData.INSANITY;
|
||||
float tempo = ClientData.TEMPO;
|
||||
|
||||
float sanityPercent = sanity / 80f;
|
||||
float insanityPercent = insanity / 80f; // same max as sanity (80)
|
||||
float tempoPercent = tempo / 120f;
|
||||
|
||||
int sanityFill = (int) (BAR_WIDTH * sanityPercent);
|
||||
int tempoFill = (int) (BAR_WIDTH * tempoPercent);
|
||||
int insanityFill = (int) (BAR_WIDTH * insanityPercent);
|
||||
|
||||
RenderSystem.enableBlend();
|
||||
|
||||
// --- TEMPO BAR ---
|
||||
drawRoundedBar(gui, xTempo, y, BAR_WIDTH, BAR_HEIGHT, 0xFF33AFFF, tempoFill);
|
||||
gui.drawString(mc.font, Component.literal("Tempo"), xTempo, y - 10, 0x66CCFF, false);
|
||||
|
||||
// --- SANITY OR INSANITY BAR ---
|
||||
boolean insaneMode = sanity <= 0;
|
||||
|
||||
if (!insaneMode) {
|
||||
// Normal sanity bar
|
||||
drawRoundedBar(gui, xSanity, y, BAR_WIDTH, BAR_HEIGHT, 0xFFFFFFFF, sanityFill);
|
||||
gui.drawString(mc.font, Component.literal("Sanity"), xSanity + BAR_WIDTH - 30, y - 10, 0xFFFFFF, false);
|
||||
} else {
|
||||
int purple = 0xFFAA33FF;
|
||||
int darkPurple = 0xFF6611AA;
|
||||
drawRoundedRect(gui, xSanity, y, BAR_WIDTH, BAR_HEIGHT, 0xDD000000);
|
||||
drawRoundedRect(gui, xSanity, y, insanityFill, BAR_HEIGHT, purple, darkPurple);
|
||||
gui.drawString(mc.font, Component.literal("Insanity"), xSanity + BAR_WIDTH - 42, y - 10, 0xCC66FF, false);
|
||||
}
|
||||
double mouseX = mc.mouseHandler.xpos() * width / (double) event.getWindow().getScreenWidth();
|
||||
double mouseY = mc.mouseHandler.ypos() * height / (double) event.getWindow().getScreenHeight();
|
||||
if (isMouseOver(mouseX, mouseY, xTempo, y, BAR_WIDTH, BAR_HEIGHT)) {
|
||||
String text = String.format("%.0f%%", tempoPercent * 100f);
|
||||
gui.drawCenteredString(mc.font, text, xTempo + BAR_WIDTH / 2, y - 12, 0x66CCFF);
|
||||
}
|
||||
if (isMouseOver(mouseX, mouseY, xSanity, y, BAR_WIDTH, BAR_HEIGHT)) {
|
||||
if (!insaneMode) {
|
||||
String text = String.format("%.0f%%", sanityPercent * 100f);
|
||||
gui.drawCenteredString(mc.font, text, xSanity + BAR_WIDTH / 2, y - 12, 0xFFFFFF);
|
||||
} else {
|
||||
String text = String.format("%.0f%%", insanityPercent * 100f);
|
||||
gui.drawCenteredString(mc.font, text, xSanity + BAR_WIDTH / 2, y - 12, 0xCC66FF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawRoundedBar(GuiGraphics gui, int x, int y, int width, int height, int color, int fillWidth) {
|
||||
int bg = 0xCC000000;
|
||||
drawRoundedRect(gui, x, y, width, height, bg);
|
||||
int top = color;
|
||||
int bottom = (color & 0x00FFFFFF) | 0xFF000000;
|
||||
drawRoundedRect(gui, x, y, fillWidth, height, top, bottom);
|
||||
}
|
||||
|
||||
private static void drawRoundedRect(GuiGraphics gui, int x, int y, int width, int height, int color) {
|
||||
gui.fill(x + 1, y, x + width - 1, y + height, color); // center
|
||||
gui.fill(x, y + 1, x + width, y + height - 1, color); // sides
|
||||
gui.fill(x + 1, y + 1, x + width - 1, y + height - 1, color);
|
||||
}
|
||||
|
||||
private static void drawRoundedRect(GuiGraphics gui, int x, int y, int width, int height, int topColor, int bottomColor) {
|
||||
gui.fillGradient(x + 1, y, x + width - 1, y + height, topColor, bottomColor);
|
||||
gui.fillGradient(x, y + 1, x + width, y + height - 1, topColor, bottomColor);
|
||||
}
|
||||
|
||||
private static boolean isMouseOver(double mx, double my, int x, int y, int w, int h) {
|
||||
return mx >= x && mx <= x + w && my >= y && my <= y + h;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package net.fretux.mindmotion.client.effects;
|
||||
|
||||
import net.fretux.mindmotion.client.ClientData;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.PostChain;
|
||||
import net.minecraft.client.renderer.PostPass;
|
||||
import net.minecraft.client.renderer.EffectInstance;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderLevelStageEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "mindmotion", value = Dist.CLIENT)
|
||||
public class SanityShaderHandler {
|
||||
|
||||
private static final ResourceLocation DESAT_EFFECT =
|
||||
new ResourceLocation("mindmotion", "shaders/post/desaturate.json");
|
||||
|
||||
private static float currentStrength = 0f;
|
||||
|
||||
// cache reflection so we don't look it up every frame
|
||||
private static Field passesField;
|
||||
|
||||
private static List<PostPass> getPasses(PostChain chain) throws IllegalAccessException, NoSuchFieldException {
|
||||
if (passesField == null) {
|
||||
passesField = PostChain.class.getDeclaredField("passes");
|
||||
passesField.setAccessible(true);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
List<PostPass> passes = (List<PostPass>) passesField.get(chain);
|
||||
return passes;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderWorld(RenderLevelStageEvent event) {
|
||||
// AFTER_LEVEL is the point where the full world image is ready
|
||||
if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_LEVEL) return;
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.player == null || mc.level == null) return;
|
||||
|
||||
float sanity = ClientData.SANITY;
|
||||
float insanity = ClientData.INSANITY;
|
||||
float maxSanity = 80f;
|
||||
|
||||
float sanityPct = sanity / maxSanity;
|
||||
float insanityPct = insanity / maxSanity;
|
||||
|
||||
float baseDesat = 0f;
|
||||
if (sanityPct < 0.70f) {
|
||||
baseDesat = 1f - (sanityPct / 0.70f);
|
||||
}
|
||||
|
||||
float insanityBoost = 0.75f * insanityPct;
|
||||
float target = Math.max(baseDesat, insanityBoost);
|
||||
if (sanity <= 0f) target = 1f;
|
||||
|
||||
// smooth to avoid popping
|
||||
currentStrength += (target - currentStrength) * 0.08f;
|
||||
|
||||
// if essentially zero, shut the effect off completely
|
||||
if (currentStrength < 0.005f) {
|
||||
if (mc.gameRenderer.currentEffect() != null) {
|
||||
mc.gameRenderer.shutdownEffect();
|
||||
}
|
||||
currentStrength = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure our effect is loaded
|
||||
if (mc.gameRenderer.currentEffect() == null) {
|
||||
try {
|
||||
mc.gameRenderer.loadEffect(DESAT_EFFECT);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PostChain chain = mc.gameRenderer.currentEffect();
|
||||
if (chain == null) return; // failed to load
|
||||
|
||||
// update the Desat uniform on all passes
|
||||
try {
|
||||
for (PostPass pass : getPasses(chain)) {
|
||||
EffectInstance effect = pass.getEffect();
|
||||
if (effect == null) continue;
|
||||
var uniform = effect.getUniform("Desat");
|
||||
if (uniform != null) {
|
||||
uniform.set(currentStrength);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) {
|
||||
if (!event.getEntity().level().isClientSide()) return;
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
currentStrength = 0f;
|
||||
|
||||
mc.execute(() -> {
|
||||
if (mc.gameRenderer.currentEffect() != null) {
|
||||
mc.gameRenderer.shutdownEffect();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.fretux.mindmotion.event;
|
||||
|
||||
import net.fretux.mindmotion.player.PlayerCapabilityProvider;
|
||||
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "mindmotion")
|
||||
public class CombatEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onEntityHurt(LivingHurtEvent event) {
|
||||
if (event.getEntity() instanceof net.minecraft.world.entity.player.Player player) {
|
||||
player.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo -> tempo.addTempo(3));
|
||||
PlayerTickHandler.markCombat(player);
|
||||
}
|
||||
|
||||
if (event.getSource().getEntity() instanceof net.minecraft.world.entity.player.Player attacker) {
|
||||
attacker.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo -> tempo.addTempo(4));
|
||||
PlayerTickHandler.markCombat(attacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.fretux.mindmotion.event;
|
||||
|
||||
import net.fretux.mindmotion.player.PlayerCapabilityProvider;
|
||||
import net.minecraftforge.event.entity.living.LivingHurtEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
public class CommonEvents {
|
||||
|
||||
@SubscribeEvent
|
||||
public void onPlayerHurt(LivingHurtEvent event) {
|
||||
if (!(event.getEntity() instanceof net.minecraft.world.entity.player.Player player)) return;
|
||||
|
||||
player.getCapability(PlayerCapabilityProvider.SANITY).ifPresent(sanity -> sanity.reduceSanity(1));
|
||||
player.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo -> tempo.addTempo(4));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onClone(PlayerEvent.Clone event) {
|
||||
event.getOriginal().reviveCaps();
|
||||
event.getEntity().getCapability(PlayerCapabilityProvider.SANITY).ifPresent(newCap ->
|
||||
event.getOriginal().getCapability(PlayerCapabilityProvider.SANITY)
|
||||
.ifPresent(oldCap -> newCap.setSanity(oldCap.getSanity()))
|
||||
);
|
||||
event.getOriginal().invalidateCaps();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package net.fretux.mindmotion.event;
|
||||
|
||||
import net.fretux.mindmotion.network.ModMessages;
|
||||
import net.fretux.mindmotion.network.SyncStatsS2CPacket;
|
||||
import net.fretux.mindmotion.player.PlayerCapabilityProvider;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "mindmotion")
|
||||
public class PlayerTickHandler {
|
||||
|
||||
private static final int SANITY_TICK_INTERVAL = 20;
|
||||
private static final int TEMPO_TICK_INTERVAL = 15;
|
||||
private static final int COMBAT_DECAY_DELAY = 100;
|
||||
private static final Map<UUID, Integer> lastCombatTick = new ConcurrentHashMap<>();
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.END) return;
|
||||
Player player = event.player;
|
||||
if (player.level().isClientSide) return;
|
||||
|
||||
int tick = player.tickCount;
|
||||
boolean sanityTick = tick % SANITY_TICK_INTERVAL == 0;
|
||||
boolean tempoTick = tick % TEMPO_TICK_INTERVAL == 0;
|
||||
|
||||
if (sanityTick) handleSanityAndInsanity(player);
|
||||
if (tempoTick) handleTempoTick(player, tick);
|
||||
|
||||
if (player instanceof ServerPlayer serverPlayer && (sanityTick || tempoTick)) {
|
||||
player.getCapability(PlayerCapabilityProvider.SANITY).ifPresent(sanity ->
|
||||
player.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo ->
|
||||
ModMessages.CHANNEL.sendTo(
|
||||
new SyncStatsS2CPacket(
|
||||
sanity.getSanity(),
|
||||
sanity.getInsanity(),
|
||||
tempo.getTempo()
|
||||
),
|
||||
serverPlayer.connection.connection,
|
||||
net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleSanityAndInsanity(Player player) {
|
||||
player.getCapability(PlayerCapabilityProvider.SANITY).ifPresent(sanity -> {
|
||||
float value = sanity.getSanity();
|
||||
float insanity = sanity.getInsanity();
|
||||
float delta = 0f;
|
||||
boolean inDark = player.level().getMaxLocalRawBrightness(player.blockPosition()) < 5;
|
||||
boolean inRain = player.level().isRainingAt(player.blockPosition());
|
||||
boolean isHungry = player.getFoodData().getFoodLevel() < 6;
|
||||
boolean nearLava = player.level().getBlockState(player.blockPosition().below()).is(Blocks.LAVA);
|
||||
boolean inWater = player.isInWater() && !player.isUnderWater();
|
||||
boolean underWater = player.isUnderWater();
|
||||
boolean sleeping = player.isSleeping();
|
||||
boolean inLight = player.level().getMaxLocalRawBrightness(player.blockPosition()) > 12;
|
||||
boolean nearTorch = player.level().getBlockState(player.blockPosition().above()).is(Blocks.TORCH);
|
||||
if (inDark) delta -= 0.02f;
|
||||
if (inRain) delta -= 0.04f;
|
||||
if (isHungry) delta -= 0.06f;
|
||||
if (nearLava) delta -= 0.05f;
|
||||
if (underWater) delta -= 0.04f;
|
||||
if (inWater && !underWater) delta -= 0.02f;
|
||||
if (inLight) delta += 0.03f;
|
||||
if (nearTorch) delta += 0.05f;
|
||||
if (sleeping) delta += 0.25f;
|
||||
if (player.getUseItem() != null && player.getUseItem().isEdible()) delta += 0.05f;
|
||||
sanity.setSanity(value + delta);
|
||||
if (sanity.getSanity() <= 0) {
|
||||
sanity.setSanity(0);
|
||||
sanity.setInsanity(Math.min(sanity.getMaxSanity(), insanity + 0.3f));
|
||||
if (sanity.getInsanity() >= sanity.getMaxSanity()) {
|
||||
player.kill();
|
||||
return;
|
||||
}
|
||||
} else if (sanity.getInsanity() > 0) {
|
||||
sanity.setInsanity(Math.max(0, insanity - 0.15f));
|
||||
}
|
||||
float percent = (value / sanity.getMaxSanity()) * 100f;
|
||||
if (percent <= 70 && percent > 50 && Math.random() < 0.03)
|
||||
player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 40, 0)); // Shiver
|
||||
if (percent <= 30 && percent > 10 && Math.random() < 0.015) {
|
||||
player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20, 1));
|
||||
player.hurt(player.damageSources().magic(), 1f);
|
||||
}
|
||||
if (percent <= 10 && percent > 0 && Math.random() < 0.02) {
|
||||
player.hurt(player.damageSources().magic(), 2f);
|
||||
player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 30, 1));
|
||||
}
|
||||
float insanityPercent = (insanity / sanity.getMaxSanity()) * 100f;
|
||||
if (insanityPercent > 0) {
|
||||
if (insanityPercent > 60 && Math.random() < 0.02) {
|
||||
player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 60, 1));
|
||||
player.hurt(player.damageSources().magic(), 1f);
|
||||
}
|
||||
if (insanityPercent > 90 && Math.random() < 0.05) {
|
||||
player.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 60, 2));
|
||||
player.hurt(player.damageSources().magic(), 2f);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void handleTempoTick(Player player, int currentTick) {
|
||||
player.getCapability(PlayerCapabilityProvider.TEMPO).ifPresent(tempo -> {
|
||||
int value = tempo.getTempo();
|
||||
int lastCombat = lastCombatTick.getOrDefault(player.getUUID(), -10000);
|
||||
int ticksSinceCombat = currentTick - lastCombat;
|
||||
|
||||
if (ticksSinceCombat > COMBAT_DECAY_DELAY && value > 0) {
|
||||
tempo.setTempo(value - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void markCombat(Player player) {
|
||||
lastCombatTick.put(player.getUUID(), player.tickCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.fretux.mindmotion.network;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
|
||||
import net.fretux.mindmotion.AscendMindMotion;
|
||||
|
||||
public class ModMessages {
|
||||
|
||||
private static final String PROTOCOL_VERSION = "1";
|
||||
public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel(
|
||||
new ResourceLocation(AscendMindMotion.MODID, "main"),
|
||||
() -> PROTOCOL_VERSION,
|
||||
PROTOCOL_VERSION::equals,
|
||||
PROTOCOL_VERSION::equals
|
||||
);
|
||||
|
||||
private static int id = 0;
|
||||
private static int nextId() { return id++; }
|
||||
|
||||
public static void register() {
|
||||
CHANNEL.messageBuilder(SyncStatsS2CPacket.class, nextId(), NetworkDirection.PLAY_TO_CLIENT)
|
||||
.encoder(SyncStatsS2CPacket::encode)
|
||||
.decoder(SyncStatsS2CPacket::decode)
|
||||
.consumerMainThread(SyncStatsS2CPacket::handle)
|
||||
.add();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.fretux.mindmotion.network;
|
||||
|
||||
import net.fretux.mindmotion.client.ClientData;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SyncStatsS2CPacket {
|
||||
private final float sanity;
|
||||
private final float insanity;
|
||||
private final int tempo;
|
||||
|
||||
public SyncStatsS2CPacket(float sanity, float insanity, int tempo) {
|
||||
this.sanity = sanity;
|
||||
this.insanity = insanity;
|
||||
this.tempo = tempo;
|
||||
}
|
||||
|
||||
public static void encode(SyncStatsS2CPacket msg, FriendlyByteBuf buf) {
|
||||
buf.writeFloat(msg.sanity);
|
||||
buf.writeFloat(msg.insanity);
|
||||
buf.writeInt(msg.tempo);
|
||||
}
|
||||
|
||||
public static SyncStatsS2CPacket decode(FriendlyByteBuf buf) {
|
||||
return new SyncStatsS2CPacket(buf.readFloat(), buf.readFloat(), buf.readInt());
|
||||
}
|
||||
|
||||
public static void handle(SyncStatsS2CPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
ClientData.SANITY = msg.sanity;
|
||||
ClientData.INSANITY = msg.insanity;
|
||||
ClientData.TEMPO = msg.tempo;
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
System.out.println("[Client] Sanity: " + msg.sanity + ", Insanity: " + msg.insanity + ", Tempo: " + msg.tempo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.fretux.mindmotion.player;
|
||||
|
||||
public interface ISanity {
|
||||
float getSanity();
|
||||
void setSanity(float sanity);
|
||||
float getInsanity();
|
||||
void setInsanity(float insanity);
|
||||
float getMaxSanity();
|
||||
void addSanity(float amount);
|
||||
void reduceSanity(float amount);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.fretux.mindmotion.player;
|
||||
|
||||
public interface ITempo {
|
||||
int getTempo();
|
||||
void setTempo(int tempo);
|
||||
int getMaxTempo();
|
||||
void addTempo(int amount);
|
||||
void reduceTempo(int amount);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package net.fretux.mindmotion.player;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.capabilities.*;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = "mindmotion")
|
||||
public class PlayerCapabilityProvider {
|
||||
public static final Capability<ISanity> SANITY = CapabilityManager.get(new CapabilityToken<>(){});
|
||||
public static final Capability<ITempo> TEMPO = CapabilityManager.get(new CapabilityToken<>(){});
|
||||
|
||||
@SubscribeEvent
|
||||
public static void attachCapabilities(AttachCapabilitiesEvent<?> event) {
|
||||
if (event.getObject() instanceof net.minecraft.world.entity.player.Player player) {
|
||||
event.addCapability(new ResourceLocation("mindmotion", "sanity"), new SanityProvider());
|
||||
event.addCapability(new ResourceLocation("mindmotion", "tempo"), new TempoProvider());
|
||||
}
|
||||
}
|
||||
|
||||
private static class SanityProvider implements ICapabilityProvider, ICapabilitySerializable<CompoundTag> {
|
||||
private final SanityCapability instance = new SanityCapability();
|
||||
private final LazyOptional<ISanity> optional = LazyOptional.of(() -> instance);
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
return cap == SANITY ? optional.cast() : LazyOptional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag serializeNBT() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putFloat("Sanity", instance.getSanity());
|
||||
tag.putFloat("Insanity", instance.getInsanity());
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeNBT(CompoundTag nbt) {
|
||||
instance.setSanity(nbt.getFloat("Sanity"));
|
||||
instance.setInsanity(nbt.getFloat("Insanity"));
|
||||
}
|
||||
}
|
||||
|
||||
private static class TempoProvider implements ICapabilityProvider, ICapabilitySerializable<CompoundTag> {
|
||||
private final TempoCapability instance = new TempoCapability();
|
||||
private final LazyOptional<ITempo> optional = LazyOptional.of(() -> instance);
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
return cap == TEMPO ? optional.cast() : LazyOptional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag serializeNBT() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putInt("Tempo", instance.getTempo());
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeNBT(CompoundTag nbt) {
|
||||
instance.setTempo(nbt.getInt("Tempo"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.fretux.mindmotion.player;
|
||||
|
||||
public class SanityCapability implements ISanity {
|
||||
private float sanity = 80f;
|
||||
private float insanity = 0f;
|
||||
private final float maxSanity = 80f;
|
||||
|
||||
@Override
|
||||
public float getSanity() { return sanity; }
|
||||
@Override
|
||||
public void setSanity(float sanity) { this.sanity = Math.max(0, Math.min(maxSanity, sanity)); }
|
||||
|
||||
@Override
|
||||
public float getInsanity() { return insanity; }
|
||||
@Override
|
||||
public void setInsanity(float insanity) { this.insanity = Math.max(0, Math.min(maxSanity, insanity)); }
|
||||
|
||||
@Override
|
||||
public float getMaxSanity() { return maxSanity; }
|
||||
|
||||
@Override
|
||||
public void addSanity(float amount) { setSanity(this.sanity + amount); }
|
||||
@Override
|
||||
public void reduceSanity(float amount) { setSanity(this.sanity - amount); }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package net.fretux.mindmotion.player;
|
||||
|
||||
public class TempoCapability implements ITempo {
|
||||
private int tempo = 0;
|
||||
private final int maxTempo = 120;
|
||||
|
||||
@Override
|
||||
public int getTempo() { return tempo; }
|
||||
@Override
|
||||
public void setTempo(int tempo) { this.tempo = Math.max(0, Math.min(maxTempo, tempo)); }
|
||||
@Override
|
||||
public int getMaxTempo() { return maxTempo; }
|
||||
@Override
|
||||
public void addTempo(int amount) { setTempo(this.tempo + amount); }
|
||||
@Override
|
||||
public void reduceTempo(int amount) { setTempo(this.tempo - amount); }
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# This is an example mods.toml file. It contains the data relating to the loading mods.
|
||||
# There are several mandatory fields (#mandatory), and many more that are optional (#optional).
|
||||
# The overall format is standard TOML format, v0.5.0.
|
||||
# Note that there are a couple of TOML lists in this file.
|
||||
# Find more information on toml format here: https://github.com/toml-lang/toml
|
||||
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
|
||||
modLoader="javafml" #mandatory
|
||||
# A version range to match for said mod loader - for regular FML @Mod it will be the forge version
|
||||
loaderVersion="${loader_version_range}" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions.
|
||||
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
|
||||
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
|
||||
license="${mod_license}"
|
||||
# A URL to refer people to when problems occur with this mod
|
||||
#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional
|
||||
# If your mod is purely client-side and has no multiplayer functionality (be it dedicated servers or Open to LAN),
|
||||
# set this to true, and Forge will set the correct displayTest for you and skip loading your mod on dedicated servers.
|
||||
#clientSideOnly=true #optional - defaults to false if absent
|
||||
# A list of mods - how many allowed here is determined by the individual mod loader
|
||||
[[mods]] #mandatory
|
||||
# The modid of the mod
|
||||
modId="${mod_id}" #mandatory
|
||||
# The version number of the mod
|
||||
version="${mod_version}" #mandatory
|
||||
# A display name for the mod
|
||||
displayName="${mod_name}" #mandatory
|
||||
# A URL to query for updates for this mod. See the JSON update specification https://docs.minecraftforge.net/en/latest/misc/updatechecker/
|
||||
#updateJSONURL="https://change.me.example.invalid/updates.json" #optional
|
||||
# A URL for the "homepage" for this mod, displayed in the mod UI
|
||||
#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional
|
||||
# A file name (in the root of the mod JAR) containing a logo for display
|
||||
#logoFile="examplemod.png" #optional
|
||||
# A text field displayed in the mod UI
|
||||
#credits="" #optional
|
||||
# A text field displayed in the mod UI
|
||||
authors="${mod_authors}" #optional
|
||||
# Display Test controls the display for your mod in the server connection screen
|
||||
# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod.
|
||||
# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod.
|
||||
# IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component.
|
||||
# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value.
|
||||
# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself.
|
||||
#displayTest="MATCH_VERSION" # if nothing is specified, MATCH_VERSION is the default when clientSideOnly=false, otherwise IGNORE_ALL_VERSION when clientSideOnly=true (#optional)
|
||||
|
||||
# The description text for the mod (multi line!) (#mandatory)
|
||||
description='''${mod_description}'''
|
||||
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
|
||||
[[dependencies.${mod_id}]] #optional
|
||||
# the modid of the dependency
|
||||
modId="forge" #mandatory
|
||||
# Does this dependency have to exist - if not, ordering below must be specified
|
||||
mandatory=true #mandatory
|
||||
# The version range of the dependency
|
||||
versionRange="${forge_version_range}" #mandatory
|
||||
# An ordering relationship for the dependency - BEFORE or AFTER required if the dependency is not mandatory
|
||||
# BEFORE - This mod is loaded BEFORE the dependency
|
||||
# AFTER - This mod is loaded AFTER the dependency
|
||||
ordering="NONE"
|
||||
# Side this dependency is applied on - BOTH, CLIENT, or SERVER
|
||||
side="BOTH"
|
||||
# Here's another dependency
|
||||
[[dependencies.${mod_id}]]
|
||||
modId="minecraft"
|
||||
mandatory=true
|
||||
# This version range declares a minimum of the current minecraft version up to but not including the next major version
|
||||
versionRange="${minecraft_version_range}"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
||||
|
||||
# Features are specific properties of the game environment, that you may want to declare you require. This example declares
|
||||
# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't
|
||||
# stop your mod loading on the server for example.
|
||||
#[features.${mod_id}]
|
||||
#openGLVersion="[3.2,)"
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"targets": [
|
||||
"swap"
|
||||
],
|
||||
"passes": [
|
||||
{
|
||||
"name": "mindmotion:desaturate",
|
||||
"intarget": "minecraft:main",
|
||||
"outtarget": "swap"
|
||||
},
|
||||
{
|
||||
"name": "minecraft:blit",
|
||||
"intarget": "swap",
|
||||
"outtarget": "minecraft:main"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#version 150
|
||||
|
||||
uniform sampler2D DiffuseSampler;
|
||||
uniform float Desat;
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec2 oneTexel; // required by sobel.vsh, even if unused
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec4 col = texture(DiffuseSampler, texCoord);
|
||||
float gray = dot(col.rgb, vec3(0.2126, 0.7152, 0.0722));
|
||||
float d = clamp(Desat, 0.0, 1.0);
|
||||
fragColor = vec4(mix(col.rgb, vec3(gray), d), col.a);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"blend": {
|
||||
"func": "add",
|
||||
"srcrgb": "one",
|
||||
"dstrgb": "zero"
|
||||
},
|
||||
"vertex": "mindmotion:desaturate",
|
||||
"fragment": "mindmotion:desaturate",
|
||||
"attributes": [
|
||||
"Position"
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"name": "DiffuseSampler"
|
||||
}
|
||||
],
|
||||
"uniforms": [
|
||||
{
|
||||
"name": "ProjMat",
|
||||
"type": "matrix4x4",
|
||||
"count": 16,
|
||||
"values": [
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OutSize",
|
||||
"type": "float",
|
||||
"count": 2,
|
||||
"values": [
|
||||
1,
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Desat",
|
||||
"type": "float",
|
||||
"count": 1,
|
||||
"values": [
|
||||
0.0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#version 150
|
||||
|
||||
in vec4 Position;
|
||||
|
||||
uniform mat4 ProjMat;
|
||||
uniform vec2 OutSize;
|
||||
|
||||
out vec2 texCoord;
|
||||
|
||||
void main() {
|
||||
vec4 outPos = ProjMat * vec4(Position.xy, 0.0, 1.0);
|
||||
gl_Position = vec4(outPos.xy, 0.0, 1.0);
|
||||
texCoord = Position.xy / OutSize;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"pack": {
|
||||
"description": {
|
||||
"text": "${mod_id} resources"
|
||||
},
|
||||
"pack_format": 15
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user