15 Commits

Author SHA1 Message Date
6b806574ac Removed Darkness Effect (toggleable)
All checks were successful
build / build (push) Successful in 1m19s
2025-04-11 13:17:19 +02:00
ddd5b9bf75 Fixed typo
All checks were successful
build / build (push) Successful in 1m12s
2025-04-07 10:37:44 +02:00
8c3798d456 Created basic Mod Menu Integration and made different fog types toggleable 2025-04-07 10:32:39 +02:00
d99467d953 Added ModMenu as (optional) dependency 2025-04-07 09:18:14 +02:00
7d969d0013 Removed Game Fog (cleaned up AngleViewer code)
All checks were successful
build / build (push) Successful in 1m2s
2025-04-06 12:25:30 +02:00
0fede8adbf Added Chat Calculator
All checks were successful
build / build (push) Successful in 1m7s
2025-03-30 23:32:43 +02:00
31afdab2cf Reverted head movement unlock on teleport due to bugs
All checks were successful
build / build (push) Successful in 1m6s
revert Made head movement lock expire as soon as teleported
2025-03-30 18:15:18 +02:00
7db6d01869 Made head movement lock expire as soon as teleported
All checks were successful
build / build (push) Successful in 1m2s
2025-03-30 17:57:57 +02:00
16027c04d1 Made head movement locked while "angle viewing"
All checks were successful
build / build (push) Successful in 1m6s
2025-03-30 17:26:55 +02:00
8ae9a4f7c4 Fixed annoyance 2025-03-30 17:12:27 +02:00
cae8c34759 Added Teleportation Angle Viewer
All checks were successful
build / build (push) Successful in 1m8s
(Also removed FPS counter)
2025-03-30 16:16:51 +02:00
77ae4cc1f0 Removed Magma Blocks and added Quartz Ore to veinmine 2025-03-30 14:45:44 +02:00
e465963daa Created 'build.yml' workflow
All checks were successful
build / build (push) Successful in 4m0s
2025-03-27 13:19:22 +01:00
6b862dfbc3 Deleted duplicate class 2025-03-27 11:31:52 +01:00
045623a67b Split client & common sources + POC FPS counter 2025-03-27 11:03:35 +01:00
21 changed files with 550 additions and 23 deletions

View File

@ -0,0 +1,32 @@
name: build
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@v4
- name: Setup JDK
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'microsoft'
- name: Make Gradle wrapper executable
run: chmod +x ./gradlew
- name: Build
run: ./gradlew build
- name: Capture build artifacts
uses: actions/upload-artifact@v3
with:
name: Artifacts
path: build/libs/

View File

@ -4,7 +4,9 @@
This mod is FAR FROM FINISHED, and initially just created for our private Survival Server.
As a challenge I'm trying to make it as user-friendly as possible. (It ain't there yet tho ;) )
## Current feature-set
# Current feature-set
## Server Side
### Features
- Custom join message
@ -27,16 +29,28 @@ As a challenge I'm trying to make it as user-friendly as possible. (It ain't the
- Vein miner
![VeinMiner](https://i.imgur.com/zOXWMNa.gif)
### Commands
- /spectator | Essentially server-side free-cam, you get put in spectator and are able to fly around, once you use the command again you get put back to where you were.
- /slimechunk (/sc) | See if you're currently in a slimechunk
### Misc
- Updated icon
# Currently working on 1.3.2
## Features to come
## Server Side
- [x] Chat Calculator
## Client Side
- [x] Teleportation Angle Viewer for [this machine](https://www.youtube.com/watch?v=FnUE-ZaALLw)
![Teleportation Keybindings](https://i.imgur.com/gjO1H3d.png)
- [x] Removed game fog (lava, water, etc.)
- [x] All types individually toggleable
- [x] Mod Menu integration
- [x] Automatic config adaption (currently booleans only)
- [x] Removed darkness effect
- [x] Toggleable
# Features to come
## Server Side
- Telekinesis
Other than that no more features!

View File

@ -11,11 +11,22 @@ base {
}
repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
maven {
name = "Terraformers"
url = "https://maven.terraformersmc.com/"
}
}
loom {
splitEnvironmentSourceSets()
mods {
"survivalfabric" {
sourceSet sourceSets.main
sourceSet sourceSets.client
}
}
}
fabricApi {
@ -26,13 +37,13 @@ fabricApi {
dependencies {
// To change the versions see the gradle.properties file
minecraft "net.minecraft:minecraft:${project.minecraft_version}"
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation("com.terraformersmc:modmenu:${project.modmenu_version}")
}
processResources {

View File

@ -9,9 +9,11 @@ yarn_mappings=1.21.5+build.1
loader_version=0.16.10
# Mod Properties
mod_version=1.3.1
mod_version=1.3.2
maven_group=wtf.hak.survivalfabric
archives_base_name=survivalfabric
# Dependencies
fabric_version=0.119.5+1.21.5
fabric_version=0.119.5+1.21.5
modmenu_version=14.0.0-rc.2

0
gradlew vendored Normal file → Executable file
View File

View File

@ -0,0 +1,16 @@
package wtf.hak.survivalfabric;
import net.fabricmc.api.ClientModInitializer;
import wtf.hak.survivalfabric.config.client.ClientConfigManager;
import wtf.hak.survivalfabric.features.AngleViewer;
import wtf.hak.survivalfabric.features.RemoveDarknessEffect;
public class SurvivalFabricClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
ClientConfigManager.getConfig();
AngleViewer.register();
RemoveDarknessEffect.register();
}
}

View File

@ -0,0 +1,13 @@
package wtf.hak.survivalfabric.config.client;
public class ClientConfig {
public String configVersion = "1.0";
public boolean renderNetherFog = false;
public boolean renderOverworldFog = false;
public boolean renderEndFog = false;
public boolean renderLavaFog = false;
public boolean renderWaterFog = false;
public boolean renderSnowFog = false;
public boolean removeDarknessEffect = true;
}

View File

@ -0,0 +1,55 @@
package wtf.hak.survivalfabric.config.client;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.fabricmc.loader.api.FabricLoader;
import wtf.hak.survivalfabric.config.Config;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class ClientConfigManager {
private static final File CONFIG_FILE = FabricLoader.getInstance().getConfigDir().resolve("survivalfabric-client.json").toFile();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static ClientConfig INSTANCE;
public static ClientConfig getConfig() {
if (INSTANCE == null) {
return load();
} else
return INSTANCE;
}
public static ClientConfig load() {
try(FileReader reader = new FileReader(CONFIG_FILE)) {
INSTANCE = GSON.fromJson(reader, ClientConfig.class);
if (INSTANCE.configVersion.equalsIgnoreCase(new Config().configVersion)) {
return INSTANCE;
}
INSTANCE.configVersion = new ClientConfig().configVersion;
save(INSTANCE);
return INSTANCE;
} catch (IOException e) {
ClientConfig config = new ClientConfig();
INSTANCE = config;
save(config);
return config;
}
}
public static void save(){
save(INSTANCE);
}
public static void save(ClientConfig config) {
try(FileWriter writer = new FileWriter(CONFIG_FILE)) {
GSON.toJson(config, writer);
} catch (IOException e) {
System.out.println("Error saving config: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,75 @@
package wtf.hak.survivalfabric.features;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil;
import org.lwjgl.glfw.GLFW;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class AngleViewer {
private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
public static boolean PREVENT_HEAD_MOVEMENT = false;
public static void register() {
for(Angle angle : Angle.values()) {
KeyBinding keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
"key.survivalfabric." + angle.name().toLowerCase(),
InputUtil.Type.KEYSYM,
GLFW.GLFW_DONT_CARE,
"category.survivalfabric.tpangles"
));
ClientTickEvents.END_CLIENT_TICK.register(mc -> {
while (keyBinding.wasPressed()) {
ClientPlayerEntity player = mc.player;
if(player == null) return;
player.setYaw(angle.yaw);
player.setPitch(angle.pitch);
PREVENT_HEAD_MOVEMENT = true;
scheduler.schedule(() -> {
if(player == null) return;
PREVENT_HEAD_MOVEMENT = false;
player.setPitch(-90);
PREVENT_HEAD_MOVEMENT = true;
scheduler.schedule(() -> PREVENT_HEAD_MOVEMENT = false, 1500, TimeUnit.MILLISECONDS);
}, 1500, TimeUnit.MILLISECONDS);
}
});
}
}
public enum Angle {
ANGLE0(-65.19f, -54.23f),
ANGLE1(-24.86f, -54.23f),
ANGLE2(-65.02f, -41.68f),
ANGLE3(-25.03f, -41.71f),
ANGLE4(24.81f, -54.23f),
ANGLE5(65.14f, -54.23f),
ANGLE6(24.98f, -41.68f),
ANGLE7(64.97f, -41.71f),
ANGLE8(114.81f, -54.23f),
ANGLE9(155.14f, -54.23f),
ANGLE10(114.98f, -41.68f),
ANGLE11(154.97f, -41.71f),
ANGLE12(204.81f, -54.23f),
ANGLE13(245.14f, -54.23f),
ANGLE14(204.98f, -41.68f),
ANGLE15(244.97f, -41.71f);
public final float yaw;
public final float pitch;
Angle(float yaw, float pitch) {
this.yaw = yaw;
this.pitch = pitch;
}
}
}

View File

@ -0,0 +1,19 @@
package wtf.hak.survivalfabric.features;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import wtf.hak.survivalfabric.config.client.ClientConfigManager;
public class RemoveDarknessEffect {
public static void register() {
ClientTickEvents.END_CLIENT_TICK.register(client -> {
if(client.player != null && ClientConfigManager.getConfig().removeDarknessEffect){
StatusEffectInstance darknessEffect = client.player.getStatusEffect(StatusEffects.DARKNESS);
if(darknessEffect != null)
client.player.removeStatusEffect(darknessEffect.getEffectType());
}
});
}
}

View File

@ -0,0 +1,42 @@
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.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 abstract class BackgroundRendererMixin {
@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) {
boolean renderFog = true;
CameraSubmersionType subType = camera.getSubmersionType();
if(subType == CameraSubmersionType.NONE) {
World world = camera.getFocusedEntity().getWorld();
if(world.getRegistryKey() == World.OVERWORLD && !getConfig().renderOverworldFog)
renderFog = false;
else if(world.getRegistryKey() == World.NETHER && !getConfig().renderNetherFog)
renderFog = false;
else if(world.getRegistryKey() == World.END && !getConfig().renderEndFog)
renderFog = false;
} else if(subType == CameraSubmersionType.WATER && !getConfig().renderWaterFog)
renderFog = false;
else if(subType == CameraSubmersionType.LAVA && !getConfig().renderLavaFog)
renderFog = false;
else if(subType == CameraSubmersionType.POWDER_SNOW && !getConfig().renderSnowFog)
renderFog = false;
if(!renderFog)
cir.setReturnValue(new Fog(-8.0f, 1_000_000.0F, FogShape.CYLINDER, 0,0,0,0));
}
}

View File

@ -0,0 +1,31 @@
package wtf.hak.survivalfabric.mixin.client;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.Entity;
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 wtf.hak.survivalfabric.features.AngleViewer;
@Mixin(Entity.class)
public abstract class EntityMixin {
@Inject(method = "setYaw", at = @At("HEAD"), cancellable = true)
private void preventYawChange(float yaw, CallbackInfo ci) {
if((Object) this instanceof ClientPlayerEntity player) {
if(player.isMainPlayer() && AngleViewer.PREVENT_HEAD_MOVEMENT) {
ci.cancel();
}
}
}
@Inject(method = "setPitch", at = @At("HEAD"), cancellable = true)
private void preventPitchChange(float pitch, CallbackInfo ci) {
if((Object) this instanceof ClientPlayerEntity player) {
if(player.isMainPlayer() && AngleViewer.PREVENT_HEAD_MOVEMENT) {
ci.cancel();
}
}
}
}

View File

@ -0,0 +1,88 @@
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.text.Text;
import wtf.hak.survivalfabric.config.client.ClientConfig;
import wtf.hak.survivalfabric.config.client.ClientConfigManager;
import java.lang.reflect.Field;
public class ConfigScreen extends Screen {
private final Screen parent;
public ConfigScreen(Screen parent) {
super(Text.literal("Survival Fabric - Client Config"));
this.parent = parent;
}
@Override
protected void init() {
int buttonWidth = 200;
int buttonHeight = 20;
int spacing = 5;
int startY = 40;
int i = 0;
for (Field field : ClientConfig.class.getFields()) {
if (field.getType() == boolean.class) {
int y = startY + i * (buttonHeight + spacing);
try {
boolean value = field.getBoolean(ClientConfigManager.getConfig());
String label = formatFieldName(field.getName()) + ": " + (value ? "ON" : "OFF");
ButtonWidget button = ButtonWidget.builder(
Text.literal(label),
b -> {
try {
boolean current = field.getBoolean(ClientConfigManager.getConfig());
field.setBoolean(ClientConfigManager.getConfig(), !current);
b.setMessage(Text.literal(formatFieldName(field.getName()) + ": " + (!current ? "ON" : "OFF")));
ClientConfigManager.save(); // Save if needed
} catch (Exception e) {
e.printStackTrace();
}
}
).dimensions(this.width / 2 - buttonWidth / 2, y, buttonWidth, buttonHeight).build();
this.addDrawableChild(button);
i++;
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Done button
this.addDrawableChild(ButtonWidget.builder(
Text.translatable("gui.done"),
button -> this.client.setScreen(parent)
).dimensions(this.width / 2 - 75, startY + i * (buttonHeight + spacing) + 10, 150, 20).build());
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
context.fill(0, 0, this.width, this.height, 0xC0101010);
int titleX = (this.width / 2) - (this.textRenderer.getWidth(this.title) / 2);
context.drawTextWithShadow(this.textRenderer, this.title, titleX, 20, 0xFFFFFF);
super.render(context, mouseX, mouseY, delta);
}
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();
}
}

View File

@ -0,0 +1,16 @@
package wtf.hak.survivalfabric.modmenu;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@Environment(EnvType.CLIENT)
public class ModMenuIntegration implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
System.out.println("Does ModMenuIntegration even load?");
return parent -> new ConfigScreen(parent);
}
}

View File

@ -0,0 +1,12 @@
{
"required": true,
"package": "wtf.hak.survivalfabric.mixin.client",
"compatibilityLevel": "JAVA_21",
"client": [
"BackgroundRendererMixin",
"EntityMixin"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -38,6 +38,8 @@ public class Config {
public boolean veinMinerEnabled = true;
public int maxVeinSize = 99999;
public boolean chatCalcEnabled = true;
public ScreenHandlerType<GenericContainerScreenHandler> screenHandlerType() {
return switch (sharedEnderChestRows) {
case 1 -> ScreenHandlerType.GENERIC_9X1;

View File

@ -1,8 +1,10 @@
package wtf.hak.survivalfabric.mixin;
import com.mojang.authlib.minecraft.client.MinecraftClient;
import net.minecraft.network.ClientConnection;
import net.minecraft.network.message.MessageType;
import net.minecraft.network.message.SignedMessage;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ConnectedClientData;
import net.minecraft.server.network.ServerPlayerEntity;
@ -16,6 +18,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import wtf.hak.survivalfabric.commands.SpectatorCommand;
import wtf.hak.survivalfabric.config.ConfigManager;
import java.awt.*;
import java.beans.Expression;
import java.util.Objects;
import java.util.Set;
@ -24,7 +28,7 @@ public abstract class PlayerManagerMixin {
@Inject(method = {"onPlayerConnect"}, at = {@At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V")})
public void onPlayerConnect(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) {
if(ConfigManager.getConfig().joinMessageEnabled) {
if(ConfigManager.getConfig().joinMessageEnabled && !player.getServer().isSingleplayer()) {
Text text = Text.literal(String.format(ConfigManager.getConfig().joinMessage, player.getName().getString()));
player.sendMessage(text, false);
}
@ -51,9 +55,74 @@ public abstract class PlayerManagerMixin {
@Inject(method = {"broadcast(Lnet/minecraft/network/message/SignedMessage;Lnet/minecraft/server/network/ServerPlayerEntity;Lnet/minecraft/network/message/MessageType$Parameters;)V"}, at = {@At("HEAD")}, cancellable = true)
private void onBroadcast(SignedMessage message, ServerPlayerEntity sender, MessageType.Parameters parameters, CallbackInfo ci) {
if(sender != null && ConfigManager.getConfig().chatMessageEnabled) {
Text text = Text.literal(String.format(ConfigManager.getConfig().chatMessage, sender.getName().getString(), message.getContent().getString()));
Objects.requireNonNull(sender.getServer()).getPlayerManager().broadcast(text, false);
String rawMessage = message.getContent().getString().trim();
if(sender != null && ConfigManager.getConfig().chatCalcEnabled && rawMessage.endsWith("=")) {
String expression = rawMessage.substring(0, rawMessage.length() - 1).trim();
try {
String result = String.valueOf(evaluateExpression(expression));
if(rawMessage.contains(" ")) rawMessage += " ";
rawMessage += (result.endsWith(".0")) ? result.substring(0, result.length() - 2) : result;
} catch (Exception e) {}
}
Text text = Text.literal(String.format(ConfigManager.getConfig().chatMessage, sender.getName().getString(), rawMessage));
sender.getServer().getPlayerManager().broadcast(text, false);
ci.cancel();
} else if (sender != null && ConfigManager.getConfig().chatCalcEnabled) {
String rawMessage = message.getContent().getString().trim();
if (rawMessage.endsWith("=")) {
String expression = rawMessage.substring(0, rawMessage.length() - 1).trim();
try {
String result = String.valueOf(evaluateExpression(expression));
if(rawMessage.contains(" ")) rawMessage += " ";
rawMessage += (result.endsWith(".0")) ? result.substring(0, result.length() - 2) : result;
Text formattedMessage = Text.literal("<" + sender.getName().getString() + "> " + rawMessage);
sender.getServer().getPlayerManager().broadcast(formattedMessage, false);
ci.cancel();
} catch (Exception e) {}
}
}
}
private double evaluateExpression(String expression) {
return evaluate(expression.replaceAll("\\s", ""), new int[]{0});
}
private double evaluate(String expr, int[] index) {
double value = parseTerm(expr, index);
while (index[0] < expr.length()) {
char op = expr.charAt(index[0]);
if (op != '+' && op != '-') break;
index[0]++;
double nextTerm = parseTerm(expr, index);
value = (op == '+') ? value + nextTerm : value - nextTerm;
}
return value;
}
private double parseTerm(String expr, int[] index) {
double value = parseFactor(expr, index);
while (index[0] < expr.length()) {
char op = expr.charAt(index[0]);
if (op != '*' && op != '/') break;
index[0]++;
double nextFactor = parseFactor(expr, index);
value = (op == '*') ? value * nextFactor : value / nextFactor;
}
return value;
}
private double parseFactor(String expr, int[] index) {
if (expr.charAt(index[0]) == '(') {
index[0]++;
double value = evaluate(expr, index);
index[0]++; // Skip closing ')'
return value;
}
int start = index[0];
while (index[0] < expr.length() && (Character.isDigit(expr.charAt(index[0])) || expr.charAt(index[0]) == '.')) {
index[0]++;
}
return Double.parseDouble(expr.substring(start, index[0]));
}
}

View File

@ -0,0 +1,19 @@
{
"category.survivalfabric.tpangles": "Teleportation Angles",
"key.survivalfabric.angle0": "-65.19 / -54.23",
"key.survivalfabric.angle1": "-24.86 / -54.23",
"key.survivalfabric.angle2": "-65.02 / -41.68",
"key.survivalfabric.angle3": "-25.03 / -41.71",
"key.survivalfabric.angle4": "24.81 / -54.23",
"key.survivalfabric.angle5": "65.14 / -54.23",
"key.survivalfabric.angle6": "24.98 / -41.68",
"key.survivalfabric.angle7": "64.97 / -41.71",
"key.survivalfabric.angle8": "114.81 / -54.23",
"key.survivalfabric.angle9": "155.14 / -54.23",
"key.survivalfabric.angle10": "114.98 / -41.68",
"key.survivalfabric.angle11": "154.97 / -41.71",
"key.survivalfabric.angle12": "204.81 / -54.23",
"key.survivalfabric.angle13": "245.14 / -54.23",
"key.survivalfabric.angle14": "204.98 / -41.68",
"key.survivalfabric.angle15": "244.97 / -41.71"
}

View File

@ -9,6 +9,6 @@
"#minecraft:coal_ores",
"#minecraft:copper_ores",
"minecraft:ancient_debris",
"minecraft:magma_block"
"minecraft:nether_quartz_ore"
]
}

View File

@ -9,7 +9,8 @@
],
"contact": {
"homepage": "https://hak.wtf",
"sources": "https://git.hak.wtf/hkuijlman/SurvivalFabric"
"sources": "https://git.hak.wtf/hkuijlman/SurvivalFabric",
"issues": "https://git.hak.wtf/hkuijlman/SurvivalFabric/issues"
},
"license": "CC0-1.0",
"icon": "assets/survivalfabric/icon.png",
@ -18,20 +19,30 @@
"main": [
"wtf.hak.survivalfabric.SurvivalFabric"
],
"client": [
"wtf.hak.survivalfabric.SurvivalFabricClient"
],
"fabric-datagen": [
"wtf.hak.survivalfabric.SurvivalFabricDataGenerator"
],
"modmenu": [
"wtf.hak.survivalfabric.modmenu.ModMenuIntegration"
]
},
"mixins": [
"survivalfabric.mixins.json"
"survivalfabric.mixins.json",
{
"config": "survivalfabric.client.mixins.json",
"environment": "client"
}
],
"depends": {
"fabricloader": ">=0.16.10",
"minecraft": "~1.21.4",
"minecraft": "~1.21.5",
"java": ">=21",
"fabric-api": "*"
},
"suggests": {
"optional": {
"modmenu": "*"
}
}