Update to 1.21.6
This commit is contained in:
@@ -73,6 +73,7 @@ Code inspired by Inferis!
|
||||
|
||||
## Client Side
|
||||
- [x] Fixed bug with too high zoom step values
|
||||
- [x] Rewrote config screen using YACL
|
||||
|
||||
## Server Side
|
||||
- [x] Telekinesis
|
||||
@@ -83,7 +84,6 @@ Code inspired by Inferis!
|
||||
# To-do
|
||||
|
||||
## General
|
||||
- Rework config system
|
||||
- Store server settings in world folder for better singleplayer use
|
||||
|
||||
## Client side
|
||||
|
@@ -15,6 +15,10 @@ repositories {
|
||||
name = "Terraformers"
|
||||
url = "https://maven.terraformersmc.com/"
|
||||
}
|
||||
maven {
|
||||
name = "Xander Maven"
|
||||
url = "https://maven.isxander.dev/releases"
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
@@ -43,6 +47,7 @@ dependencies {
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
modImplementation "dev.isxander:yet-another-config-lib:${project.yacl_version}"
|
||||
modImplementation("com.terraformersmc:modmenu:${project.modmenu_version}")
|
||||
}
|
||||
|
||||
|
@@ -4,16 +4,17 @@ org.gradle.parallel=true
|
||||
|
||||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/develop
|
||||
minecraft_version=1.21.5
|
||||
yarn_mappings=1.21.5+build.1
|
||||
loader_version=0.16.10
|
||||
minecraft_version=1.21.6
|
||||
yarn_mappings=1.21.6+build.1
|
||||
loader_version=0.16.14
|
||||
|
||||
# Mod Properties
|
||||
mod_version=1.4.1
|
||||
mod_version=1.4.2
|
||||
maven_group=wtf.hak.survivalfabric
|
||||
archives_base_name=survivalfabric
|
||||
|
||||
# Dependencies
|
||||
fabric_version=0.119.5+1.21.5
|
||||
fabric_version=0.127.0+1.21.6
|
||||
yacl_version=3.7.1+1.21.6-fabric
|
||||
|
||||
modmenu_version=14.0.0-rc.2
|
||||
modmenu_version=15.0.0-beta.1
|
@@ -32,9 +32,7 @@ public class Zoom {
|
||||
MinecraftClient.getInstance().options.smoothCameraEnabled = true;
|
||||
}
|
||||
SHOULD_ZOOM = true;
|
||||
client.gameRenderer.setRenderHand(false);
|
||||
} else if (!ZOOM_BIND.isPressed() && SHOULD_ZOOM) {
|
||||
client.gameRenderer.setRenderHand(true);
|
||||
SHOULD_ZOOM = false;
|
||||
ZOOM_STEP = 0;
|
||||
if(getConfig().smoothCamera) {
|
||||
|
@@ -1,47 +0,0 @@
|
||||
package wtf.hak.survivalfabric.mixin.client;
|
||||
|
||||
import net.minecraft.block.enums.CameraSubmersionType;
|
||||
import net.minecraft.client.render.BackgroundRenderer;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.Fog;
|
||||
import net.minecraft.client.render.FogShape;
|
||||
import net.minecraft.world.World;
|
||||
import org.joml.Vector4f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import static wtf.hak.survivalfabric.config.client.ClientConfigManager.getConfig;
|
||||
|
||||
@Mixin(value = BackgroundRenderer.class, priority = 910)
|
||||
public class BackgroundRendererMixin {
|
||||
|
||||
@Unique
|
||||
private static final Fog EMPTY_FOG = new Fog(-8.0f, 1_000_000.0F, FogShape.CYLINDER, 0, 0, 0, 0);
|
||||
|
||||
@Inject(method = "applyFog", at = @At("RETURN"), cancellable = true)
|
||||
private static void applyFog(Camera camera, BackgroundRenderer.FogType fogType, Vector4f color, float viewDistance, boolean thickenFog, float tickProgress, CallbackInfoReturnable<Fog> cir) {
|
||||
CameraSubmersionType submersion = camera.getSubmersionType();
|
||||
boolean renderFog = true;
|
||||
|
||||
switch (submersion) {
|
||||
case NONE -> {
|
||||
World world = camera.getFocusedEntity().getWorld();
|
||||
if ((world.getRegistryKey() == World.OVERWORLD && !getConfig().renderOverworldFog)
|
||||
|| (world.getRegistryKey() == World.NETHER && !getConfig().renderNetherFog)
|
||||
|| (world.getRegistryKey() == World.END && !getConfig().renderEndFog)) {
|
||||
renderFog = false;
|
||||
}
|
||||
}
|
||||
case WATER -> renderFog = getConfig().renderWaterFog;
|
||||
case LAVA -> renderFog = getConfig().renderLavaFog;
|
||||
case POWDER_SNOW -> renderFog = getConfig().renderSnowFog;
|
||||
}
|
||||
|
||||
if (!renderFog) {
|
||||
cir.setReturnValue(EMPTY_FOG);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
package wtf.hak.survivalfabric.mixin.client;
|
||||
|
||||
|
||||
import net.minecraft.client.render.RenderTickCounter;
|
||||
import net.minecraft.client.render.fog.*;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static wtf.hak.survivalfabric.config.client.ClientConfigManager.getConfig;
|
||||
|
||||
public class FogMixins {
|
||||
|
||||
@Mixin(DimensionOrBossFogModifier.class)
|
||||
static class DimensionOrBossFogModifierMixin {
|
||||
@Inject(at = @At("TAIL"), method = "applyStartEndModifier")
|
||||
public void disableDimensionFog(FogData data, Entity cameraEntity, BlockPos cameraPos, ClientWorld world, float viewDistance, RenderTickCounter tickCounter, CallbackInfo ci) {
|
||||
boolean shouldDisable = false;
|
||||
|
||||
if (world.getRegistryKey() == World.NETHER && !getConfig().renderNetherFog) {
|
||||
shouldDisable = true;
|
||||
} else if (world.getRegistryKey() == World.END && !getConfig().renderEndFog) {
|
||||
shouldDisable = true;
|
||||
} else if (world.getRegistryKey() == World.OVERWORLD && !getConfig().renderOverworldFog) {
|
||||
shouldDisable = true;
|
||||
}
|
||||
|
||||
if (shouldDisable) {
|
||||
data.environmentalStart = Float.MAX_VALUE;
|
||||
data.environmentalEnd = Float.MAX_VALUE;
|
||||
data.skyEnd = Float.MAX_VALUE;
|
||||
data.cloudEnd = Float.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Mixin(WaterFogModifier.class)
|
||||
static class WaterFogModifierMixin {
|
||||
@Inject(at = @At("TAIL"), method = "applyStartEndModifier")
|
||||
public void disableWaterFog(FogData data, Entity cameraEntity, BlockPos cameraPos, ClientWorld world, float viewDistance, RenderTickCounter tickCounter, CallbackInfo ci) {
|
||||
if (!getConfig().renderWaterFog) {
|
||||
data.environmentalStart = Float.MAX_VALUE;
|
||||
data.environmentalEnd = Float.MAX_VALUE;
|
||||
data.skyEnd = Float.MAX_VALUE;
|
||||
data.cloudEnd = Float.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Mixin(LavaFogModifier.class)
|
||||
static class LavaFogModifierMixin {
|
||||
@Inject(at = @At("TAIL"), method = "applyStartEndModifier")
|
||||
public void disableLavaFog(FogData data, Entity cameraEntity, BlockPos cameraPos, ClientWorld world, float viewDistance, RenderTickCounter tickCounter, CallbackInfo ci) {
|
||||
if (!getConfig().renderLavaFog) {
|
||||
data.environmentalStart = Float.MAX_VALUE;
|
||||
data.environmentalEnd = Float.MAX_VALUE;
|
||||
data.skyEnd = Float.MAX_VALUE;
|
||||
data.cloudEnd = Float.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Mixin(PowderSnowFogModifier.class)
|
||||
static class PowderSnowFogModifierMixin {
|
||||
@Inject(at = @At("TAIL"), method = "applyStartEndModifier")
|
||||
public void disablePowderSnowFog(FogData data, Entity cameraEntity, BlockPos cameraPos, ClientWorld world, float viewDistance, RenderTickCounter tickCounter, CallbackInfo ci) {
|
||||
if (!getConfig().renderSnowFog) {
|
||||
data.environmentalStart = Float.MAX_VALUE;
|
||||
data.environmentalEnd = Float.MAX_VALUE;
|
||||
data.skyEnd = Float.MAX_VALUE;
|
||||
data.cloudEnd = Float.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,14 @@
|
||||
package wtf.hak.survivalfabric.mixin.client;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElement;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.render.RenderTickCounter;
|
||||
import org.joml.Matrix4f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import wtf.hak.survivalfabric.features.Zoom;
|
||||
@@ -18,4 +24,13 @@ public class GameRendererMixin {
|
||||
return Zoom.isZooming() ? Math.clamp(Zoom.getZoomFov(), 1, 110) : fov;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure hand only gets rendered when NOT zooming.
|
||||
*/
|
||||
@WrapMethod(method = "renderHand")
|
||||
public void render(float tickProgress, boolean sleeping, Matrix4f positionMatrix, Operation<Void> original) {
|
||||
if(!Zoom.isZooming())
|
||||
original.call(tickProgress, sleeping, positionMatrix);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,599 +0,0 @@
|
||||
package wtf.hak.survivalfabric.modmenu;
|
||||
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import wtf.hak.survivalfabric.config.client.ClientConfig;
|
||||
import wtf.hak.survivalfabric.config.client.ClientConfigManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConfigScreen extends Screen {
|
||||
|
||||
private static final int OPTION_HEIGHT = 25;
|
||||
private static final int SCROLL_BAR_WIDTH = 6;
|
||||
private static final int TOP_PADDING = 40;
|
||||
private static final int BOTTOM_PADDING = 35;
|
||||
private static final int SIDE_PADDING = 20;
|
||||
private final Screen parent;
|
||||
private final List<ConfigOption<?>> options = new ArrayList<>();
|
||||
private TextFieldWidget activeTextField = null;
|
||||
private float scrollPosition = 0.0F;
|
||||
private boolean scrolling = false;
|
||||
private int contentHeight = 0;
|
||||
|
||||
public ConfigScreen(Screen parent) {
|
||||
super(Text.literal("Survival Fabric - Client Config"));
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
options.clear();
|
||||
|
||||
int listWidth = this.width - (SIDE_PADDING * 2);
|
||||
int listHeight = this.height - TOP_PADDING - BOTTOM_PADDING;
|
||||
int listLeft = SIDE_PADDING;
|
||||
int listTop = TOP_PADDING;
|
||||
|
||||
int index = 0;
|
||||
for (Field field : ClientConfig.class.getFields()) {
|
||||
try {
|
||||
Class<?> type = field.getType();
|
||||
String name = formatFieldName(field.getName());
|
||||
|
||||
ConfigOption<?> option = null;
|
||||
if (type == boolean.class) {
|
||||
boolean value = field.getBoolean(ClientConfigManager.getConfig());
|
||||
option = new BooleanConfigOption(
|
||||
name,
|
||||
field,
|
||||
value,
|
||||
listLeft,
|
||||
listTop + (index * OPTION_HEIGHT) - (int) scrollPosition,
|
||||
listWidth
|
||||
);
|
||||
} else if (type == int.class) {
|
||||
int value = field.getInt(ClientConfigManager.getConfig());
|
||||
option = new IntegerConfigOption(
|
||||
name,
|
||||
field,
|
||||
value,
|
||||
listLeft,
|
||||
listTop + (index * OPTION_HEIGHT) - (int) scrollPosition,
|
||||
listWidth
|
||||
);
|
||||
} else if (type == float.class) {
|
||||
float value = field.getFloat(ClientConfigManager.getConfig());
|
||||
option = new FloatConfigOption(
|
||||
name,
|
||||
field,
|
||||
value,
|
||||
listLeft,
|
||||
listTop + (index * OPTION_HEIGHT) - (int) scrollPosition,
|
||||
listWidth
|
||||
);
|
||||
} else if (type == String.class) {
|
||||
String value = (String) field.get(ClientConfigManager.getConfig());
|
||||
option = new StringConfigOption(
|
||||
name,
|
||||
field,
|
||||
value,
|
||||
listLeft,
|
||||
listTop + (index * OPTION_HEIGHT) - (int) scrollPosition,
|
||||
listWidth
|
||||
);
|
||||
}
|
||||
|
||||
if (option != null) {
|
||||
options.add(option);
|
||||
index++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
for (ConfigOption<?> option : options) {
|
||||
if (option instanceof NumericConfigOption) {
|
||||
((NumericConfigOption<?>) option).createTextField(this.client);
|
||||
}
|
||||
}
|
||||
|
||||
contentHeight = options.size() * OPTION_HEIGHT;
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(
|
||||
Text.translatable("gui.done"),
|
||||
button -> this.client.setScreen(parent)
|
||||
).dimensions(this.width / 2 - 100, this.height - 27, 200, 20).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
this.renderBackground(context, mouseX, mouseY, delta);
|
||||
|
||||
int titleX = (this.width / 2) - (this.textRenderer.getWidth(this.title) / 2);
|
||||
context.drawText(this.textRenderer, this.title, titleX, 15, 0xFFFFFF, true);
|
||||
|
||||
int listWidth = this.width - (SIDE_PADDING * 2);
|
||||
int listHeight = this.height - TOP_PADDING - BOTTOM_PADDING;
|
||||
int listLeft = SIDE_PADDING;
|
||||
int listTop = TOP_PADDING;
|
||||
|
||||
context.drawBorder(listLeft, listTop, listLeft + listWidth, listTop + listHeight, 0x00000000);
|
||||
|
||||
context.enableScissor(
|
||||
listLeft,
|
||||
listTop,
|
||||
listLeft + listWidth,
|
||||
listTop + listHeight
|
||||
);
|
||||
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
ConfigOption<?> option = options.get(i);
|
||||
option.y = listTop + (i * OPTION_HEIGHT) - (int) scrollPosition;
|
||||
|
||||
if (option instanceof NumericConfigOption) {
|
||||
((NumericConfigOption<?>) option).updateTextFieldPosition();
|
||||
}
|
||||
|
||||
if (option.y < listTop + listHeight && option.y + OPTION_HEIGHT > listTop) {
|
||||
option.render(context, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
||||
|
||||
context.disableScissor();
|
||||
|
||||
if (contentHeight > listHeight) {
|
||||
int scrollBarHeight = Math.max(20, (int) ((float) listHeight / (float) contentHeight * listHeight));
|
||||
int scrollBarY = listTop + (int) ((scrollPosition / (contentHeight - listHeight)) * (listHeight - scrollBarHeight));
|
||||
|
||||
context.fill(
|
||||
listLeft + listWidth + 2,
|
||||
listTop,
|
||||
listLeft + listWidth + 2 + SCROLL_BAR_WIDTH,
|
||||
listTop + listHeight,
|
||||
0xFF404040
|
||||
);
|
||||
|
||||
context.fill(
|
||||
listLeft + listWidth + 2,
|
||||
scrollBarY,
|
||||
listLeft + listWidth + 2 + SCROLL_BAR_WIDTH,
|
||||
scrollBarY + scrollBarHeight,
|
||||
scrolling ? 0xFFAAAAAA : 0xFF808080
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
int listWidth = this.width - (SIDE_PADDING * 2);
|
||||
int listHeight = this.height - TOP_PADDING - BOTTOM_PADDING;
|
||||
int listLeft = SIDE_PADDING;
|
||||
int listTop = TOP_PADDING;
|
||||
|
||||
boolean handledByTextField = false;
|
||||
|
||||
activeTextField = null;
|
||||
|
||||
if (mouseX >= listLeft &&
|
||||
mouseX <= listLeft + listWidth &&
|
||||
mouseY >= listTop &&
|
||||
mouseY <= listTop + listHeight) {
|
||||
|
||||
for (ConfigOption<?> option : options) {
|
||||
if (option instanceof NumericConfigOption<?> numOption &&
|
||||
option.y >= listTop &&
|
||||
option.y + OPTION_HEIGHT <= listTop + listHeight) {
|
||||
|
||||
TextFieldWidget textField = numOption.getTextField();
|
||||
|
||||
if (textField.isMouseOver(mouseX, mouseY)) {
|
||||
textField.setFocused(true);
|
||||
activeTextField = textField;
|
||||
handledByTextField = true;
|
||||
|
||||
for (ConfigOption<?> otherOption : options) {
|
||||
if (otherOption instanceof NumericConfigOption && otherOption != option) {
|
||||
((NumericConfigOption<?>) otherOption).getTextField().setFocused(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
textField.setFocused(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contentHeight > listHeight &&
|
||||
mouseX >= listLeft + listWidth + 2 &&
|
||||
mouseX <= listLeft + listWidth + 2 + SCROLL_BAR_WIDTH &&
|
||||
mouseY >= listTop &&
|
||||
mouseY <= listTop + listHeight) {
|
||||
|
||||
scrolling = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if clicked on an option
|
||||
if (mouseX >= listLeft &&
|
||||
mouseX <= listLeft + listWidth &&
|
||||
mouseY >= listTop &&
|
||||
mouseY <= listTop + listHeight) {
|
||||
|
||||
for (ConfigOption<?> option : options) {
|
||||
if (option.isMouseOver(mouseX, mouseY) && option.y >= listTop && option.y + OPTION_HEIGHT <= listTop + listHeight) {
|
||||
option.onClick(mouseX, mouseY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
if (activeTextField != null && activeTextField.isFocused()) {
|
||||
return activeTextField.keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charTyped(char chr, int modifiers) {
|
||||
if (activeTextField != null && activeTextField.isFocused()) {
|
||||
return activeTextField.charTyped(chr, modifiers);
|
||||
}
|
||||
|
||||
return super.charTyped(chr, modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||
scrolling = false;
|
||||
return super.mouseReleased(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
|
||||
int listHeight = this.height - TOP_PADDING - BOTTOM_PADDING;
|
||||
int listTop = TOP_PADDING;
|
||||
|
||||
if (scrolling && contentHeight > listHeight) {
|
||||
float scrollAmount = (float) deltaY / (listHeight - Math.max(20, (int) ((float) listHeight / (float) contentHeight * listHeight)));
|
||||
float maxScroll = contentHeight - listHeight;
|
||||
|
||||
scrollPosition = MathHelper.clamp(scrollPosition + scrollAmount * maxScroll, 0.0F, maxScroll);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double horizontalAmount, double verticalAmount) {
|
||||
int listWidth = this.width - (SIDE_PADDING * 2);
|
||||
int listHeight = this.height - TOP_PADDING - BOTTOM_PADDING;
|
||||
int listLeft = SIDE_PADDING;
|
||||
int listTop = TOP_PADDING;
|
||||
|
||||
if (mouseX >= listLeft &&
|
||||
mouseX <= listLeft + listWidth &&
|
||||
mouseY >= listTop &&
|
||||
mouseY <= listTop + listHeight &&
|
||||
contentHeight > listHeight) {
|
||||
|
||||
float maxScroll = contentHeight - listHeight;
|
||||
scrollPosition = MathHelper.clamp(scrollPosition - (float) verticalAmount * 10, 0.0F, maxScroll);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||
}
|
||||
|
||||
private String formatFieldName(String rawName) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
char[] chars = rawName.toCharArray();
|
||||
result.append(Character.toUpperCase(chars[0]));
|
||||
for (int i = 1; i < chars.length; i++) {
|
||||
if (Character.isUpperCase(chars[i])) {
|
||||
result.append(' ');
|
||||
}
|
||||
result.append(chars[i]);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for all config options
|
||||
*/
|
||||
private abstract class ConfigOption<T> {
|
||||
protected final String name;
|
||||
protected final Field field;
|
||||
protected final int width;
|
||||
protected T value;
|
||||
protected int x;
|
||||
protected int y;
|
||||
|
||||
public ConfigOption(String name, Field field, T initialValue, int x, int y, int width) {
|
||||
this.name = name;
|
||||
this.field = field;
|
||||
this.value = initialValue;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public abstract void render(DrawContext context, int mouseX, int mouseY, float delta);
|
||||
|
||||
public abstract void onClick(double mouseX, double mouseY);
|
||||
|
||||
public boolean isMouseOver(double mouseX, double mouseY) {
|
||||
return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + OPTION_HEIGHT;
|
||||
}
|
||||
|
||||
protected abstract void saveValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation for boolean config options
|
||||
*/
|
||||
private class BooleanConfigOption extends ConfigOption<Boolean> {
|
||||
private static final int BUTTON_WIDTH = 40;
|
||||
private static final int BUTTON_HEIGHT = 20;
|
||||
|
||||
public BooleanConfigOption(String name, Field field, Boolean initialValue, int x, int y, int width) {
|
||||
super(name, field, initialValue, x, y, width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
context.drawText(textRenderer, name, x + 5, y + (OPTION_HEIGHT - 8) / 2, 0xFFFFFF, true);
|
||||
|
||||
int buttonX = x + width - BUTTON_WIDTH - 5;
|
||||
int buttonY = y + (OPTION_HEIGHT - BUTTON_HEIGHT) / 2;
|
||||
|
||||
boolean hovered = isButtonHovered(mouseX, mouseY);
|
||||
int buttonColor = hovered ? 0xFF404040 : 0xFF303030;
|
||||
int buttonBorder = hovered ? 0xFFCCCCCC : 0xFF808080;
|
||||
|
||||
context.fill(buttonX, buttonY, buttonX + BUTTON_WIDTH, buttonY + BUTTON_HEIGHT, buttonBorder);
|
||||
context.fill(buttonX + 1, buttonY + 1, buttonX + BUTTON_WIDTH - 1, buttonY + BUTTON_HEIGHT - 1, buttonColor);
|
||||
|
||||
String buttonText = value ? "true" : "false";
|
||||
int textColor = value ? 0x00be00 : 0xbe0000;
|
||||
int textWidth = textRenderer.getWidth(buttonText);
|
||||
context.drawText(
|
||||
textRenderer,
|
||||
buttonText,
|
||||
buttonX + (BUTTON_WIDTH - textWidth) / 2,
|
||||
buttonY + (BUTTON_HEIGHT - 8) / 2,
|
||||
textColor,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public boolean isButtonHovered(double mouseX, double mouseY) {
|
||||
int buttonX = x + width - BUTTON_WIDTH - 5;
|
||||
int buttonY = y + (OPTION_HEIGHT - BUTTON_HEIGHT) / 2;
|
||||
return mouseX >= buttonX && mouseX <= buttonX + BUTTON_WIDTH &&
|
||||
mouseY >= buttonY && mouseY <= buttonY + BUTTON_HEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
if (isButtonHovered(mouseX, mouseY)) {
|
||||
value = !value;
|
||||
saveValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveValue() {
|
||||
try {
|
||||
// Update config and save
|
||||
field.setBoolean(ClientConfigManager.getConfig(), value);
|
||||
ClientConfigManager.save();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation for String config options
|
||||
*/
|
||||
private class StringConfigOption extends ConfigOption<String> {
|
||||
private static final int FIELD_WIDTH = 60;
|
||||
private static final int FIELD_HEIGHT = 16;
|
||||
protected TextFieldWidget textField;
|
||||
|
||||
public StringConfigOption(String name, Field field, String initialValue, int x, int y, int width) {
|
||||
super(name, field, initialValue, x, y, width);
|
||||
}
|
||||
|
||||
public void createTextField(net.minecraft.client.MinecraftClient client) {
|
||||
int fieldX = x + width - FIELD_WIDTH - 5;
|
||||
int fieldY = y + (OPTION_HEIGHT - FIELD_HEIGHT) / 2;
|
||||
|
||||
textField = new TextFieldWidget(
|
||||
textRenderer,
|
||||
fieldX,
|
||||
fieldY,
|
||||
FIELD_WIDTH,
|
||||
FIELD_HEIGHT,
|
||||
Text.literal("")
|
||||
);
|
||||
|
||||
textField.setText(value);
|
||||
textField.setMaxLength(10);
|
||||
textField.setChangedListener(this::onTextChanged);
|
||||
}
|
||||
|
||||
public TextFieldWidget getTextField() {
|
||||
return textField;
|
||||
}
|
||||
|
||||
public void updateTextFieldPosition() {
|
||||
if (textField != null) {
|
||||
int fieldX = x + width - FIELD_WIDTH - 5;
|
||||
int fieldY = y + (OPTION_HEIGHT - FIELD_HEIGHT) / 2;
|
||||
textField.setX(fieldX);
|
||||
textField.setY(fieldY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
context.drawText(textRenderer, name, x + 5, y + (OPTION_HEIGHT - 8) / 2, 0xFFFFFF, true);
|
||||
|
||||
if (textField != null) {
|
||||
textField.render(context, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {
|
||||
}
|
||||
|
||||
public void onTextChanged(String text) {
|
||||
try {
|
||||
value = text;
|
||||
saveValue();
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveValue() {
|
||||
try {
|
||||
field.set(ClientConfigManager.getConfig(), value);
|
||||
ClientConfigManager.save();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for numeric config options (int and float)
|
||||
*/
|
||||
private abstract class NumericConfigOption<T extends Number> extends ConfigOption<T> {
|
||||
private static final int FIELD_WIDTH = 60;
|
||||
private static final int FIELD_HEIGHT = 16;
|
||||
protected TextFieldWidget textField;
|
||||
|
||||
public NumericConfigOption(String name, Field field, T initialValue, int x, int y, int width) {
|
||||
super(name, field, initialValue, x, y, width);
|
||||
}
|
||||
|
||||
public void createTextField(net.minecraft.client.MinecraftClient client) {
|
||||
int fieldX = x + width - FIELD_WIDTH - 5;
|
||||
int fieldY = y + (OPTION_HEIGHT - FIELD_HEIGHT) / 2;
|
||||
|
||||
textField = new TextFieldWidget(
|
||||
textRenderer,
|
||||
fieldX,
|
||||
fieldY,
|
||||
FIELD_WIDTH,
|
||||
FIELD_HEIGHT,
|
||||
Text.literal("")
|
||||
);
|
||||
|
||||
textField.setText(value.toString());
|
||||
textField.setMaxLength(10);
|
||||
textField.setChangedListener(this::onTextChanged);
|
||||
}
|
||||
|
||||
public TextFieldWidget getTextField() {
|
||||
return textField;
|
||||
}
|
||||
|
||||
public void updateTextFieldPosition() {
|
||||
if (textField != null) {
|
||||
int fieldX = x + width - FIELD_WIDTH - 5;
|
||||
int fieldY = y + (OPTION_HEIGHT - FIELD_HEIGHT) / 2;
|
||||
textField.setX(fieldX);
|
||||
textField.setY(fieldY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
context.drawText(textRenderer, name, x + 5, y + (OPTION_HEIGHT - 8) / 2, 0xFFFFFF, true);
|
||||
|
||||
if (textField != null) {
|
||||
textField.render(context, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY) {}
|
||||
|
||||
protected abstract void onTextChanged(String text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation for integer config options
|
||||
*/
|
||||
private class IntegerConfigOption extends NumericConfigOption<Integer> {
|
||||
public IntegerConfigOption(String name, Field field, Integer initialValue, int x, int y, int width) {
|
||||
super(name, field, initialValue, x, y, width);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTextChanged(String text) {
|
||||
try {
|
||||
value = Integer.parseInt(text);
|
||||
saveValue();
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveValue() {
|
||||
try {
|
||||
field.setInt(ClientConfigManager.getConfig(), value);
|
||||
ClientConfigManager.save();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation for float config options
|
||||
*/
|
||||
private class FloatConfigOption extends NumericConfigOption<Float> {
|
||||
public FloatConfigOption(String name, Field field, Float initialValue, int x, int y, int width) {
|
||||
super(name, field, initialValue, x, y, width);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTextChanged(String text) {
|
||||
try {
|
||||
value = Float.parseFloat(text);
|
||||
saveValue();
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveValue() {
|
||||
try {
|
||||
field.setFloat(ClientConfigManager.getConfig(), value);
|
||||
ClientConfigManager.save();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,6 +10,6 @@ public class ModMenuIntegration implements ModMenuApi {
|
||||
|
||||
@Override
|
||||
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||
return ConfigScreen::new;
|
||||
return YACLConfigScreen::createConfigScreen;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,231 @@
|
||||
package wtf.hak.survivalfabric.modmenu;
|
||||
|
||||
import dev.isxander.yacl3.api.*;
|
||||
import dev.isxander.yacl3.api.controller.*;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import wtf.hak.survivalfabric.config.client.ClientConfigManager;
|
||||
|
||||
public class YACLConfigScreen {
|
||||
|
||||
public static Screen createConfigScreen(Screen parent) {
|
||||
return YetAnotherConfigLib.createBuilder()
|
||||
.title(Text.literal("Survival Fabric Configuration").formatted(Formatting.BOLD))
|
||||
.category(createMainCategory())
|
||||
.save(ClientConfigManager::save)
|
||||
.build()
|
||||
.generateScreen(parent);
|
||||
}
|
||||
|
||||
private static ConfigCategory createMainCategory() {
|
||||
ConfigCategory.Builder categoryBuilder = ConfigCategory.createBuilder()
|
||||
.name(Text.literal("General Settings").formatted(Formatting.YELLOW))
|
||||
.tooltip(Text.literal("Common configuration options for Survival Fabric"));
|
||||
|
||||
// Create groups for different types of options
|
||||
OptionGroup.Builder renderingGroup = OptionGroup.createBuilder()
|
||||
.name(Text.literal("Rendering Options"))
|
||||
.description(OptionDescription.of(Text.literal("Options that control fog rendering and visual effects")))
|
||||
.collapsed(false);
|
||||
|
||||
OptionGroup.Builder gameplayGroup = OptionGroup.createBuilder()
|
||||
.name(Text.literal("Gameplay Options"))
|
||||
.description(OptionDescription.of(Text.literal("Options that affect gameplay mechanics")))
|
||||
.collapsed(false);
|
||||
|
||||
OptionGroup.Builder cameraGroup = OptionGroup.createBuilder()
|
||||
.name(Text.literal("Camera & Zoom"))
|
||||
.description(OptionDescription.of(Text.literal("Camera and zoom-related settings")))
|
||||
.collapsed(false);
|
||||
|
||||
// === RENDERING OPTIONS ===
|
||||
|
||||
// Nether Fog
|
||||
renderingGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Render Nether Fog"))
|
||||
.description(OptionDescription.of(Text.literal("Enable or disable fog rendering in the Nether dimension")))
|
||||
.binding(
|
||||
false, // default
|
||||
() -> ClientConfigManager.getConfig().renderNetherFog,
|
||||
newValue -> ClientConfigManager.getConfig().renderNetherFog = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Overworld Fog
|
||||
renderingGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Render Overworld Fog"))
|
||||
.description(OptionDescription.of(Text.literal("Enable or disable fog rendering in the Overworld dimension")))
|
||||
.binding(
|
||||
false, // default
|
||||
() -> ClientConfigManager.getConfig().renderOverworldFog,
|
||||
newValue -> ClientConfigManager.getConfig().renderOverworldFog = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// End Fog
|
||||
renderingGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Render End Fog"))
|
||||
.description(OptionDescription.of(Text.literal("Enable or disable fog rendering in the End dimension")))
|
||||
.binding(
|
||||
false, // default
|
||||
() -> ClientConfigManager.getConfig().renderEndFog,
|
||||
newValue -> ClientConfigManager.getConfig().renderEndFog = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Lava Fog
|
||||
renderingGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Render Lava Fog"))
|
||||
.description(OptionDescription.of(Text.literal("Enable or disable fog when submerged in lava")))
|
||||
.binding(
|
||||
false, // default
|
||||
() -> ClientConfigManager.getConfig().renderLavaFog,
|
||||
newValue -> ClientConfigManager.getConfig().renderLavaFog = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Water Fog
|
||||
renderingGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Render Water Fog"))
|
||||
.description(OptionDescription.of(Text.literal("Enable or disable fog when submerged in water")))
|
||||
.binding(
|
||||
false, // default
|
||||
() -> ClientConfigManager.getConfig().renderWaterFog,
|
||||
newValue -> ClientConfigManager.getConfig().renderWaterFog = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Snow Fog
|
||||
renderingGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Render Snow Fog"))
|
||||
.description(OptionDescription.of(Text.literal("Enable or disable fog during snow weather")))
|
||||
.binding(
|
||||
false, // default
|
||||
() -> ClientConfigManager.getConfig().renderSnowFog,
|
||||
newValue -> ClientConfigManager.getConfig().renderSnowFog = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Remove Darkness Effect
|
||||
renderingGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Remove Darkness Effect"))
|
||||
.description(OptionDescription.of(Text.literal("Remove the darkness effect applied by the Warden and sculk shriekers")))
|
||||
.binding(
|
||||
true, // default
|
||||
() -> ClientConfigManager.getConfig().removeDarknessEffect,
|
||||
newValue -> ClientConfigManager.getConfig().removeDarknessEffect = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// === GAMEPLAY OPTIONS ===
|
||||
|
||||
// Lock Teleport Head Movement
|
||||
gameplayGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Lock Teleport Head Movement"))
|
||||
.description(OptionDescription.of(Text.literal("Prevent head movement changes during teleportation")))
|
||||
.binding(
|
||||
true, // default
|
||||
() -> ClientConfigManager.getConfig().lockTeleportHeadMovement,
|
||||
newValue -> ClientConfigManager.getConfig().lockTeleportHeadMovement = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Manipulate Block Entity Distance
|
||||
gameplayGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Manipulate Block Entity Distance"))
|
||||
.description(OptionDescription.of(Text.literal("Enable custom block entity rendering distance")))
|
||||
.binding(
|
||||
true, // default
|
||||
() -> ClientConfigManager.getConfig().manipulateBlockEntityDistance,
|
||||
newValue -> ClientConfigManager.getConfig().manipulateBlockEntityDistance = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Block Entity Range
|
||||
gameplayGroup.option(Option.<Integer>createBuilder()
|
||||
.name(Text.literal("Block Entity Range"))
|
||||
.description(OptionDescription.of(Text.literal("Maximum distance for block entity rendering (in blocks)")))
|
||||
.binding(
|
||||
512, // default
|
||||
() -> ClientConfigManager.getConfig().blockEntityRange,
|
||||
newValue -> ClientConfigManager.getConfig().blockEntityRange = newValue
|
||||
)
|
||||
.controller(opt -> IntegerSliderControllerBuilder.create(opt)
|
||||
.range(16, 2048)
|
||||
.step(16)
|
||||
.formatValue(value -> Text.literal(value + " blocks")))
|
||||
.build());
|
||||
|
||||
// === CAMERA & ZOOM OPTIONS ===
|
||||
|
||||
// Smooth Camera
|
||||
cameraGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Smooth Camera"))
|
||||
.description(OptionDescription.of(Text.literal("Enable smooth camera transitions")))
|
||||
.binding(
|
||||
true, // default
|
||||
() -> ClientConfigManager.getConfig().smoothCamera,
|
||||
newValue -> ClientConfigManager.getConfig().smoothCamera = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Initial Zoom
|
||||
cameraGroup.option(Option.<Float>createBuilder()
|
||||
.name(Text.literal("Initial Zoom Level"))
|
||||
.description(OptionDescription.of(Text.literal("Default zoom level when activating zoom")))
|
||||
.binding(
|
||||
20f, // default
|
||||
() -> ClientConfigManager.getConfig().initialZoom,
|
||||
newValue -> ClientConfigManager.getConfig().initialZoom = newValue
|
||||
)
|
||||
.controller(opt -> FloatSliderControllerBuilder.create(opt)
|
||||
.range(1.0f, 50.0f)
|
||||
.step(0.5f)
|
||||
.formatValue(value -> Text.literal(String.format("%.1fx", value))))
|
||||
.build());
|
||||
|
||||
// Scroll to Zoom
|
||||
cameraGroup.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.literal("Scroll to Zoom"))
|
||||
.description(OptionDescription.of(Text.literal("Allow using mouse wheel to adjust zoom level")))
|
||||
.binding(
|
||||
true, // default
|
||||
() -> ClientConfigManager.getConfig().scrollToZoom,
|
||||
newValue -> ClientConfigManager.getConfig().scrollToZoom = newValue
|
||||
)
|
||||
.controller(TickBoxControllerBuilder::create)
|
||||
.build());
|
||||
|
||||
// Zoom Step
|
||||
cameraGroup.option(Option.<Float>createBuilder()
|
||||
.name(Text.literal("Zoom Step"))
|
||||
.description(OptionDescription.of(Text.literal("Amount of zoom change per scroll wheel step")))
|
||||
.binding(
|
||||
2.5f, // default
|
||||
() -> ClientConfigManager.getConfig().zoomStep,
|
||||
newValue -> ClientConfigManager.getConfig().zoomStep = newValue
|
||||
)
|
||||
.controller(opt -> FloatSliderControllerBuilder.create(opt)
|
||||
.range(0.1f, 10.0f)
|
||||
.step(0.1f)
|
||||
.formatValue(value -> Text.literal(String.format("%.1f", value))))
|
||||
.build());
|
||||
|
||||
return categoryBuilder
|
||||
.group(renderingGroup.build())
|
||||
.group(gameplayGroup.build())
|
||||
.group(cameraGroup.build())
|
||||
.build();
|
||||
}
|
||||
}
|
@@ -3,13 +3,17 @@
|
||||
"package": "wtf.hak.survivalfabric.mixin.client",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"BackgroundRendererMixin",
|
||||
"BlockEntityRendererMixin",
|
||||
"EntityMixin",
|
||||
"FogMixins$DimensionOrBossFogModifierMixin",
|
||||
"FogMixins$LavaFogModifierMixin",
|
||||
"FogMixins$PowderSnowFogModifierMixin",
|
||||
"FogMixins$WaterFogModifierMixin",
|
||||
"GameRendererMixin",
|
||||
"MouseMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
},
|
||||
"mixins": []
|
||||
}
|
@@ -27,8 +27,8 @@ public class SlimeChunkCommand {
|
||||
return 0;
|
||||
}
|
||||
ServerPlayerEntity p = (ServerPlayerEntity) source.getEntity();
|
||||
Chunk chunk = p.getServerWorld().getChunk(p.getBlockPos());
|
||||
Random slimeRandom = ChunkRandom.getSlimeRandom(chunk.getPos().x, chunk.getPos().z, p.getServerWorld().getSeed(), 987234911L);
|
||||
Chunk chunk = p.getWorld().getChunk(p.getBlockPos());
|
||||
Random slimeRandom = ChunkRandom.getSlimeRandom(chunk.getPos().x, chunk.getPos().z, p.getWorld().getSeed(), 987234911L);
|
||||
if (slimeRandom.nextInt(10) == 0) {
|
||||
p.sendMessage(Text.literal(getConfig().inSlimeChunkMessage));
|
||||
} else
|
||||
|
@@ -45,7 +45,7 @@ public class SpectatorCommand {
|
||||
.getZ(), player
|
||||
.getYaw(), player
|
||||
.getPitch(), player
|
||||
.getServerWorld()));
|
||||
.getWorld()));
|
||||
player.changeGameMode(GameMode.SPECTATOR);
|
||||
PacketUtils.updateListNames(player);
|
||||
}
|
||||
|
@@ -6,11 +6,8 @@ import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.EnderChestBlock;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.Inventories;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.nbt.NbtSizeTracker;
|
||||
import net.minecraft.nbt.*;
|
||||
import net.minecraft.screen.GenericContainerScreenHandler;
|
||||
import net.minecraft.screen.SimpleNamedScreenHandlerFactory;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -24,6 +21,7 @@ import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Optional;
|
||||
|
||||
import static wtf.hak.survivalfabric.SurvivalFabric.LOGGER;
|
||||
import static wtf.hak.survivalfabric.config.ConfigManager.getConfig;
|
||||
@@ -38,7 +36,23 @@ public class SharedEnderChest implements ServerLifecycleEvents.ServerStopping, S
|
||||
File inventoryFile = getFile(server);
|
||||
NbtCompound nbt = new NbtCompound();
|
||||
DefaultedList<ItemStack> inventoryItemStacks = DefaultedList.ofSize(getConfig().sharedEnderChestRows * 9, ItemStack.EMPTY);
|
||||
Inventories.writeNbt(nbt, sharedInventory.getList(inventoryItemStacks), server.getRegistryManager());
|
||||
inventoryItemStacks = sharedInventory.getList(inventoryItemStacks);
|
||||
|
||||
NbtList itemsList = new NbtList();
|
||||
for (int i = 0; i < inventoryItemStacks.size(); i++) {
|
||||
ItemStack stack = inventoryItemStacks.get(i);
|
||||
if (!stack.isEmpty()) {
|
||||
NbtCompound itemNbt = new NbtCompound();
|
||||
itemNbt.putInt("Slot", i);
|
||||
|
||||
itemNbt.copyFromCodec(ItemStack.MAP_CODEC,
|
||||
server.getRegistryManager().getOps(NbtOps.INSTANCE), stack);
|
||||
|
||||
itemsList.add(itemNbt);
|
||||
}
|
||||
}
|
||||
nbt.put("Items", itemsList);
|
||||
|
||||
try (FileOutputStream inventoryFileOutputStream = new FileOutputStream(inventoryFile);
|
||||
DataOutputStream inventoryFileDataOutput = new DataOutputStream(inventoryFileOutputStream)) {
|
||||
inventoryFile.createNewFile();
|
||||
@@ -79,6 +93,7 @@ public class SharedEnderChest implements ServerLifecycleEvents.ServerStopping, S
|
||||
return server.getSavePath(WorldSavePath.ROOT).resolve("sharedenderchest.sav").toFile();
|
||||
}
|
||||
|
||||
|
||||
public void onServerStarted(MinecraftServer server) {
|
||||
File inventoryFile = getFile(server);
|
||||
if (inventoryFile.exists()) {
|
||||
@@ -86,7 +101,22 @@ public class SharedEnderChest implements ServerLifecycleEvents.ServerStopping, S
|
||||
DataInputStream inventoryFileDataInput = new DataInputStream(inventoryFileInputStream)) {
|
||||
NbtCompound nbt = NbtIo.readCompressed(inventoryFileDataInput, NbtSizeTracker.ofUnlimitedBytes());
|
||||
DefaultedList<ItemStack> inventoryItemStacks = DefaultedList.ofSize(getConfig().sharedEnderChestRows * 9, ItemStack.EMPTY);
|
||||
Inventories.readNbt(nbt, inventoryItemStacks, server.getRegistryManager());
|
||||
|
||||
// Load each item using the new codec system
|
||||
if (nbt.contains("Items")) {
|
||||
NbtList itemsList = nbt.getList("Items").get();
|
||||
for (int i = 0; i < itemsList.size(); i++) {
|
||||
NbtCompound itemNbt = itemsList.getCompound(i).get();
|
||||
int slot = itemNbt.getInt("Slot").get();
|
||||
if (slot >= 0 && slot < inventoryItemStacks.size()) {
|
||||
// Use ItemStack's codec for deserialization
|
||||
Optional<ItemStack> stackOpt = itemNbt.decode(ItemStack.MAP_CODEC,
|
||||
server.getRegistryManager().getOps(NbtOps.INSTANCE));
|
||||
stackOpt.ifPresent(stack -> inventoryItemStacks.set(slot, stack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sharedInventory = new SharedInventory(inventoryItemStacks);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Error while loading Shared Ender Chest: " + e);
|
||||
|
@@ -19,7 +19,7 @@ public class ServerPlayerEntityMixin {
|
||||
private void changePlayerListName(CallbackInfoReturnable<Text> cir) {
|
||||
if (ConfigManager.getConfig().dimensionIndicatorEnabled) {
|
||||
ServerPlayerEntity p = (ServerPlayerEntity) (Object) this;
|
||||
String world = p.getServerWorld().getRegistryKey().getValue().toTranslationKey();
|
||||
String world = p.getWorld().getRegistryKey().getValue().toTranslationKey();
|
||||
String finalName;
|
||||
if (!SpectatorCommand.spectating.containsKey(p)) {
|
||||
finalName = switch (world) {
|
||||
|
@@ -38,9 +38,10 @@
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.16.10",
|
||||
"minecraft": "~1.21.5",
|
||||
"minecraft": "~1.21.6",
|
||||
"java": ">=21",
|
||||
"fabric-api": "*"
|
||||
"fabric-api": "*",
|
||||
"yet_another_config_lib_v3": ">=3.7.0"
|
||||
},
|
||||
"optional": {
|
||||
"modmenu": "*"
|
||||
|
Reference in New Issue
Block a user