Compare commits
20 Commits
1.3.0
...
1d0f7f0f05
Author | SHA1 | Date | |
---|---|---|---|
1d0f7f0f05 | |||
7d969d0013 | |||
52a97dc2c1 | |||
0fede8adbf | |||
5916cc5cc2 | |||
31afdab2cf | |||
4e58bede4b | |||
7db6d01869 | |||
130b2db727 | |||
16027c04d1 | |||
c993621bdb | |||
8ae9a4f7c4 | |||
b89ab99928 | |||
cae8c34759 | |||
77ae4cc1f0 | |||
e465963daa | |||
6b862dfbc3 | |||
045623a67b | |||
b6bb6565a8 | |||
8cebb278b8 |
32
.gitea/workflows/build.yml
Normal file
32
.gitea/workflows/build.yml
Normal 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/
|
21
README.md
21
README.md
@ -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,25 @@ As a challenge I'm trying to make it as user-friendly as possible. (It ain't the
|
||||
- Vein miner
|
||||

|
||||
|
||||
|
||||
### 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)
|
||||

|
||||
- [x] Removed game fog (lava, water, etc.)
|
||||
- [ ] Made it toggleable
|
||||
- [ ] Mod Menu integration
|
||||
|
||||
# Features to come
|
||||
|
||||
## Server Side
|
||||
- Telekinesis
|
||||
|
||||
Other than that no more features!
|
||||
|
14
build.gradle
14
build.gradle
@ -18,6 +18,18 @@ repositories {
|
||||
// for more information about repositories.
|
||||
}
|
||||
|
||||
loom {
|
||||
splitEnvironmentSourceSets()
|
||||
|
||||
mods {
|
||||
"survivalfabric" {
|
||||
sourceSet sourceSets.main
|
||||
sourceSet sourceSets.client
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fabricApi {
|
||||
configureDataGeneration {
|
||||
client = true
|
||||
@ -26,7 +38,7 @@ 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}"
|
||||
|
||||
|
@ -9,7 +9,7 @@ yarn_mappings=1.21.4+build.8
|
||||
loader_version=0.16.10
|
||||
|
||||
# Mod Properties
|
||||
mod_version=1.3.0
|
||||
mod_version=1.3.2
|
||||
maven_group=wtf.hak.survivalfabric
|
||||
archives_base_name=survivalfabric
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
package wtf.hak.survivalfabric;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import wtf.hak.survivalfabric.features.AngleViewer;
|
||||
|
||||
public class SurvivalFabricClient implements ClientModInitializer {
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
AngleViewer.register();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package wtf.hak.survivalfabric.mixin.client;
|
||||
|
||||
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 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;
|
||||
|
||||
@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) {
|
||||
cir.setReturnValue(new Fog(-8.0f, 1_000_000.0F, FogShape.CYLINDER, 0,0,0,0));
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
src/client/resources/survivalfabric.client.mixins.json
Normal file
12
src/client/resources/survivalfabric.client.mixins.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "wtf.hak.survivalfabric.mixin.client",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"client": [
|
||||
"BackgroundRendererMixin",
|
||||
"EntityMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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]));
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
package wtf.hak.survivalfabric.sharedenderchest;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.Inventories;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class SharedInventory implements Inventory {
|
||||
|
||||
private final DefaultedList<ItemStack> stacks;
|
||||
@ -19,28 +18,6 @@ public class SharedInventory implements Inventory {
|
||||
this.stacks = dl;
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public void onClose(PlayerEntity player) {
|
||||
Inventory.super.onClose(player);
|
||||
EnderChestBlockEntity blockEntity = enderChests.remove(player);
|
||||
if (blockEntity != null)
|
||||
blockEntity.onClose(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(PlayerEntity player) {
|
||||
Inventory.super.onOpen(player);
|
||||
EnderChestBlockEntity blockEntity = enderChests.get(player);
|
||||
if (blockEntity != null)
|
||||
blockEntity.onOpen(player);
|
||||
}
|
||||
|
||||
public void setBlockEntity(PlayerEntity player, EnderChestBlockEntity be) {
|
||||
enderChests.put(player, be);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public DefaultedList<ItemStack> getList(DefaultedList<ItemStack> dl) {
|
||||
dl = stacks;
|
||||
@ -54,7 +31,7 @@ public class SharedInventory implements Inventory {
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
Iterator<ItemStack> var1 = this.stacks.iterator();
|
||||
var var1 = this.stacks.iterator();
|
||||
|
||||
ItemStack itemStack_1;
|
||||
do {
|
||||
@ -62,7 +39,7 @@ public class SharedInventory implements Inventory {
|
||||
return true;
|
||||
}
|
||||
|
||||
itemStack_1 = (ItemStack)var1.next();
|
||||
itemStack_1 = var1.next();
|
||||
} while(itemStack_1.isEmpty());
|
||||
|
||||
return false;
|
||||
@ -76,10 +53,6 @@ public class SharedInventory implements Inventory {
|
||||
@Override
|
||||
public ItemStack removeStack(int int_1, int int_2) {
|
||||
ItemStack itemStack_1 = Inventories.splitStack(this.stacks, int_1, int_2);
|
||||
if (!itemStack_1.isEmpty()) {
|
||||
//this.container.onContentChanged(this);
|
||||
}
|
||||
|
||||
return itemStack_1;
|
||||
}
|
||||
|
||||
@ -91,7 +64,6 @@ public class SharedInventory implements Inventory {
|
||||
@Override
|
||||
public void setStack(int i, ItemStack itemStack) {
|
||||
this.stacks.set(i, itemStack);
|
||||
//this.container.onContentChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
19
src/main/resources/assets/survivalfabric/lang/en_us.json
Normal file
19
src/main/resources/assets/survivalfabric/lang/en_us.json
Normal 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"
|
||||
}
|
@ -9,6 +9,6 @@
|
||||
"#minecraft:coal_ores",
|
||||
"#minecraft:copper_ores",
|
||||
"minecraft:ancient_debris",
|
||||
"minecraft:magma_block"
|
||||
"minecraft:nether_quartz_ore"
|
||||
]
|
||||
}
|
@ -18,12 +18,19 @@
|
||||
"main": [
|
||||
"wtf.hak.survivalfabric.SurvivalFabric"
|
||||
],
|
||||
"client": [
|
||||
"wtf.hak.survivalfabric.SurvivalFabricClient"
|
||||
],
|
||||
"fabric-datagen": [
|
||||
"wtf.hak.survivalfabric.SurvivalFabricDataGenerator"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"survivalfabric.mixins.json"
|
||||
"survivalfabric.mixins.json",
|
||||
{
|
||||
"config": "survivalfabric.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.16.10",
|
||||
@ -32,6 +39,6 @@
|
||||
"fabric-api": "*"
|
||||
},
|
||||
"suggests": {
|
||||
|
||||
"another-mod": "*"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user