Compare commits
12 Commits
1.1.1
...
8856bec073
Author | SHA1 | Date | |
---|---|---|---|
8856bec073 | |||
7ad7ce6ed4 | |||
78a56b6f28 | |||
6e15c54b80 | |||
22de60988f | |||
c8f907dc57 | |||
8377f36114 | |||
f3a1156fd4 | |||
5eae9d4a8c | |||
83cc3a38e9 | |||
7d4dca66f0 | |||
f6f0fc65d7 |
30
.github/workflows/build.yml
vendored
30
.github/workflows/build.yml
vendored
@ -1,30 +0,0 @@
|
||||
# Automatically build the project and run any configured tests for every push
|
||||
# and submitted pull request. This can help catch issues that only occur on
|
||||
# certain platforms or Java versions, and provides a first line of defence
|
||||
# against bad commits.
|
||||
|
||||
name: build
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
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@v4
|
||||
with:
|
||||
name: Artifacts
|
||||
path: build/libs/
|
38
README.md
Normal file
38
README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Survival Fabric
|
||||
|
||||
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
|
||||
|
||||
### Features
|
||||
- Custom join message
|
||||
- Custom quit message
|
||||
- Custom chat message
|
||||
- Tab list dimension indicator
|
||||
|
||||
### 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.
|
||||
|
||||
## Currently working on v1.3.0
|
||||
|
||||
### Features
|
||||
- [x] Config
|
||||
- [x] Configurable messages
|
||||
- [x] Feature toggle
|
||||
- [x] Version "control"
|
||||
- [x] Shared Ender Chest
|
||||
- [x] Shared EC Access control (via config)
|
||||
- [ ] Vein miner
|
||||
- [ ] Telekinesis
|
||||
|
||||
### Commands
|
||||
|
||||
- [ ] /slimechunk (/sc) | See if you're currently in a slimechunk
|
||||
|
||||
### Misc
|
||||
- [x] Updated icon
|
||||
|
||||
## Features to come
|
||||
|
||||
For now there are no more feautures!
|
||||
Be sure to give your idea by [opening an issue](https://git.hak.wtf/hkuijlman/SurvivalFabric/issues/new) wit the label Feature Request
|
@ -9,7 +9,7 @@ yarn_mappings=1.21.4+build.8
|
||||
loader_version=0.16.10
|
||||
|
||||
# Mod Properties
|
||||
mod_version=1.1.1
|
||||
mod_version=1.3.0
|
||||
maven_group=wtf.hak.survivalfabric
|
||||
archives_base_name=survivalfabric
|
||||
|
||||
|
@ -3,11 +3,13 @@ package wtf.hak.survivalfabric;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
||||
import net.minecraft.scoreboard.Team;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import wtf.hak.survivalfabric.commands.ReloadConfigCommand;
|
||||
import wtf.hak.survivalfabric.commands.SpectatorCommand;
|
||||
import wtf.hak.survivalfabric.sharedenderchest.SharedEnderChest;
|
||||
|
||||
import static wtf.hak.survivalfabric.config.ConfigManager.getConfig;
|
||||
|
||||
public class SurvivalFabric implements ModInitializer {
|
||||
|
||||
@ -18,6 +20,9 @@ public class SurvivalFabric implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> SpectatorCommand.register(dispatcher, new String[] { "spectator", "s", "S", "camera", "c", "C", }));
|
||||
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> ReloadConfigCommand.register(dispatcher, new String[] { "reloadsurvivalconfig" }));
|
||||
|
||||
if(getConfig().sharedEnderChestEnabled)
|
||||
new SharedEnderChest().onInitialize();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package wtf.hak.survivalfabric.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import wtf.hak.survivalfabric.config.ConfigManager;
|
||||
|
||||
public class ReloadConfigCommand {
|
||||
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher, String... aliases) {
|
||||
for (String str : aliases)
|
||||
dispatcher.register(CommandManager.literal(str)
|
||||
.requires(source -> source.hasPermissionLevel(2))
|
||||
.executes(ReloadConfigCommand::execute));
|
||||
}
|
||||
|
||||
private static int execute(CommandContext<ServerCommandSource> context) {
|
||||
ConfigManager.load();
|
||||
return 1;
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.world.GameMode;
|
||||
import wtf.hak.survivalfabric.utils.DimensionTeams;
|
||||
import wtf.hak.survivalfabric.utils.Utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -20,23 +20,23 @@ public class SpectatorCommand {
|
||||
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher, String... aliases) {
|
||||
for (String str : aliases)
|
||||
dispatcher.register(CommandManager.literal(str) // Ensure correct method name
|
||||
dispatcher.register(CommandManager.literal(str)
|
||||
.executes(SpectatorCommand::execute));
|
||||
}
|
||||
|
||||
private static int execute(CommandContext<ServerCommandSource> context) {
|
||||
ServerCommandSource source = context.getSource();
|
||||
if (source.getEntity() == null) { // Ensure correct method name
|
||||
if (source.getEntity() == null) {
|
||||
source.sendMessage(Text.literal("Console cannot go into spectator mode!"));
|
||||
return 0;
|
||||
}
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) source.getEntity(); // Ensure correct method name
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) source.getEntity();
|
||||
if (spectating.containsKey(player)) {
|
||||
LocationData data = spectating.get(player);
|
||||
player.teleport(data.world, data.x, data.y, data.z, Set.of(), data.yaw, data.pitch, false);
|
||||
player.changeGameMode(GameMode.SURVIVAL);
|
||||
spectating.remove(player);
|
||||
//DimensionTeams.assignCorrectTeam(player, data.world.getRegistryKey().getValue().toTranslationKey());
|
||||
Utils.updateListNames(player);
|
||||
} else {
|
||||
|
||||
spectating.put(player, new LocationData(player
|
||||
@ -47,7 +47,7 @@ public class SpectatorCommand {
|
||||
.getPitch(), player
|
||||
.getServerWorld()));
|
||||
player.changeGameMode(GameMode.SPECTATOR);
|
||||
//DimensionTeams.assignCorrectTeam(player, "");
|
||||
Utils.updateListNames(player);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
46
src/main/java/wtf/hak/survivalfabric/config/Config.java
Normal file
46
src/main/java/wtf/hak/survivalfabric/config/Config.java
Normal file
@ -0,0 +1,46 @@
|
||||
package wtf.hak.survivalfabric.config;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.screen.GenericContainerScreenHandler;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Config {
|
||||
|
||||
public String configVersion = "1.0";
|
||||
|
||||
public boolean joinMessageEnabled = true;
|
||||
public String joinMessage = "§8[§a+§8] §7%s";
|
||||
|
||||
public boolean quitMessageEnabled = true;
|
||||
public String quitMessage = "§8[§c-§8] §7%s";
|
||||
|
||||
public boolean chatMessageEnabled = true;
|
||||
public String chatMessage = "§7%s§8:§f %s";
|
||||
|
||||
public boolean dimensionIndicatorEnabled = true;
|
||||
public String overworldPrefix = "§8[§aOverworld§8] ";
|
||||
public String netherPrefix = "§8[§cNether§8] ";
|
||||
public String endPrefix = "§8[§dEnd§8] ";
|
||||
public String spectatorPrefix = "§8[§eSpectator§8] ";
|
||||
public String unknownPrefix = "§8[§7Unknown§8] ";
|
||||
|
||||
public boolean sharedEnderChestEnabled = true;
|
||||
public String sharedEnderChestName = "Ender Chest";
|
||||
public int sharedEnderChestRows = 6;
|
||||
public boolean sharedEnderChestLimitedAccess = true;
|
||||
public List<String> sharedEnderChestNames = Lists.newArrayList("AlwaysHAK", "LunaticFox");
|
||||
|
||||
public ScreenHandlerType<GenericContainerScreenHandler> screenHandlerType() {
|
||||
return switch (sharedEnderChestRows) {
|
||||
case 1 -> ScreenHandlerType.GENERIC_9X1;
|
||||
case 2 -> ScreenHandlerType.GENERIC_9X2;
|
||||
case 3 -> ScreenHandlerType.GENERIC_9X3;
|
||||
case 4 -> ScreenHandlerType.GENERIC_9X4;
|
||||
case 5 -> ScreenHandlerType.GENERIC_9X5;
|
||||
case 6 -> ScreenHandlerType.GENERIC_9X6;
|
||||
default -> ScreenHandlerType.GENERIC_9X3;
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package wtf.hak.survivalfabric.config;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private static final File CONFIG_FILE = FabricLoader.getInstance().getConfigDir().resolve("survivalfabric.json").toFile();
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
private static Config INSTANCE;
|
||||
|
||||
public static Config getConfig() {
|
||||
if (INSTANCE == null) {
|
||||
return load();
|
||||
} else
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static Config load() {
|
||||
try(FileReader reader = new FileReader(CONFIG_FILE)) {
|
||||
INSTANCE = GSON.fromJson(reader, Config.class);
|
||||
if (INSTANCE.configVersion.equalsIgnoreCase(new Config().configVersion)) {
|
||||
return INSTANCE;
|
||||
}
|
||||
INSTANCE.configVersion = new Config().configVersion;
|
||||
save(INSTANCE);
|
||||
return INSTANCE;
|
||||
} catch (IOException e) {
|
||||
Config config = new Config();
|
||||
INSTANCE = config;
|
||||
save(config);
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
public static void save(Config config) {
|
||||
try(FileWriter writer = new FileWriter(CONFIG_FILE)) {
|
||||
GSON.toJson(config, writer);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error saving config: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -3,14 +3,10 @@ package wtf.hak.survivalfabric.mixin;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.message.MessageType;
|
||||
import net.minecraft.network.message.SignedMessage;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.PlayerManager;
|
||||
import net.minecraft.server.network.ConnectedClientData;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TextContent;
|
||||
import net.minecraft.world.GameMode;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@ -18,9 +14,9 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import wtf.hak.survivalfabric.commands.SpectatorCommand;
|
||||
import wtf.hak.survivalfabric.utils.DimensionTeams;
|
||||
import wtf.hak.survivalfabric.utils.Messages;
|
||||
import wtf.hak.survivalfabric.config.ConfigManager;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(PlayerManager.class)
|
||||
@ -28,19 +24,19 @@ 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) {
|
||||
Text text = Text.literal(String.format(Messages.JOIN_MESSAGE, player.getName().getString()));
|
||||
player.sendMessage(text, false);
|
||||
}
|
||||
|
||||
@Inject(method = {"onPlayerConnect"}, at = {@At(value = "HEAD")})
|
||||
public void onPlayerConnectHead(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) {
|
||||
//DimensionTeams.assignCorrectTeam(player, player.getServerWorld().getRegistryKey().getValue().toTranslationKey());
|
||||
if(ConfigManager.getConfig().joinMessageEnabled) {
|
||||
Text text = Text.literal(String.format(ConfigManager.getConfig().joinMessage, player.getName().getString()));
|
||||
player.sendMessage(text, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyArg(method = {"onPlayerConnect"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V"))
|
||||
private Text onPlayerConnect(Text text) {
|
||||
String name = text.getString().split(" ")[0];
|
||||
return Text.literal(String.format(Messages.JOIN_MESSAGE, name));
|
||||
if(ConfigManager.getConfig().joinMessageEnabled) {
|
||||
String name = text.getString().split(" ")[0];
|
||||
return Text.literal(String.format(ConfigManager.getConfig().joinMessage, name));
|
||||
} else
|
||||
return text;
|
||||
}
|
||||
|
||||
@Inject(method = {"remove"}, at = {@At("HEAD")})
|
||||
@ -54,9 +50,9 @@ 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) {
|
||||
Text text = Text.literal(String.format(Messages.CHAT_FORMAT, sender.getName().getString(), message.getContent().getString()));
|
||||
sender.getServer().getPlayerManager().broadcast(text, false);
|
||||
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);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,18 @@ import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import wtf.hak.survivalfabric.utils.Messages;
|
||||
import wtf.hak.survivalfabric.config.ConfigManager;
|
||||
|
||||
@Mixin(ServerPlayNetworkHandler.class)
|
||||
public abstract class ServerPlayNetworkHandlerMixin {
|
||||
|
||||
@ModifyArg(method = {"cleanUp"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V"))
|
||||
private Text quitMessage(Text text) {
|
||||
String name = text.getString().split(" ")[0];
|
||||
return Text.literal(String.format(Messages.QUIT_MESSAGE, name));
|
||||
if(ConfigManager.getConfig().quitMessageEnabled) {
|
||||
String name = text.getString().split(" ")[0];
|
||||
return Text.literal(String.format(ConfigManager.getConfig().quitMessage, name));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
package wtf.hak.survivalfabric.mixin;
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
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 wtf.hak.survivalfabric.commands.SpectatorCommand;
|
||||
import wtf.hak.survivalfabric.config.ConfigManager;
|
||||
|
||||
@Mixin(ServerPlayerEntity.class)
|
||||
public abstract class ServerPlayerEntityMixin {
|
||||
|
||||
@Inject(method = "getPlayerListName", at = @At("HEAD"), cancellable = true)
|
||||
private void changePlayerListName(CallbackInfoReturnable<Text> cir) {
|
||||
if(ConfigManager.getConfig().dimensionIndicatorEnabled) {
|
||||
ServerPlayerEntity p = (ServerPlayerEntity) (Object) this;
|
||||
String world = p.getServerWorld().getRegistryKey().getValue().toTranslationKey();
|
||||
String finalName;
|
||||
if (!SpectatorCommand.spectating.containsKey(p)) {
|
||||
finalName = switch (world) {
|
||||
case "minecraft.overworld" -> ConfigManager.getConfig().overworldPrefix;
|
||||
case "minecraft.the_nether" -> ConfigManager.getConfig().netherPrefix;
|
||||
case "minecraft.the_end" -> ConfigManager.getConfig().endPrefix;
|
||||
default -> ConfigManager.getConfig().unknownPrefix;
|
||||
};
|
||||
} else
|
||||
finalName = ConfigManager.getConfig().spectatorPrefix;
|
||||
|
||||
finalName += "§7" + p.getName().getString();
|
||||
|
||||
cir.setReturnValue(Text.of(finalName));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,13 +3,11 @@ package wtf.hak.survivalfabric.mixin;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.Text;
|
||||
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.utils.DimensionTeams;
|
||||
import wtf.hak.survivalfabric.utils.Messages;
|
||||
import wtf.hak.survivalfabric.utils.Utils;
|
||||
|
||||
@Mixin(ServerWorld.class)
|
||||
public class ServerWorldMixin {
|
||||
@ -17,10 +15,7 @@ public class ServerWorldMixin {
|
||||
@Inject(method = "onDimensionChanged", at = {@At("HEAD")})
|
||||
public void onDimensionChange(Entity entity, CallbackInfo ci) {
|
||||
if(entity instanceof ServerPlayerEntity) {
|
||||
ServerPlayerEntity player = (ServerPlayerEntity)entity;
|
||||
String dimension = Messages.getDimensionFormatted(player.getServerWorld().getRegistryKey().getValue().toTranslationKey());
|
||||
//player.sendMessage(Text.literal(dimension), false);
|
||||
//DimensionTeams.assignCorrectTeam(player, player.getServerWorld().getRegistryKey().getValue().toTranslationKey());
|
||||
Utils.updateListNames((ServerPlayerEntity)entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
package wtf.hak.survivalfabric.sharedenderchest;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
|
||||
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.screen.GenericContainerScreenHandler;
|
||||
import net.minecraft.screen.SimpleNamedScreenHandlerFactory;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import static wtf.hak.survivalfabric.config.ConfigManager.getConfig;
|
||||
|
||||
public class SharedEnderChest implements ServerLifecycleEvents.ServerStopping, ServerLifecycleEvents.ServerStarted, ServerTickEvents.EndTick {
|
||||
|
||||
private static SharedInventory sharedInventory;
|
||||
|
||||
private long ticksUntilSave = -20;
|
||||
|
||||
public void onServerStarted(MinecraftServer server) {
|
||||
File inventoryFile = getFile(server);
|
||||
if (inventoryFile.exists()) {
|
||||
try (FileInputStream inventoryFileInputStream = new FileInputStream(inventoryFile);
|
||||
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());
|
||||
sharedInventory = new SharedInventory(inventoryItemStacks);
|
||||
} catch (Exception e) {
|
||||
System.out.println("[ShareEnderChest] Error while loading inventory: " + e);
|
||||
sharedInventory = new SharedInventory(getConfig().sharedEnderChestRows);
|
||||
}
|
||||
} else {
|
||||
sharedInventory = new SharedInventory(getConfig().sharedEnderChestRows);
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveInventory(MinecraftServer server) {
|
||||
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());
|
||||
try (FileOutputStream inventoryFileOutputStream = new FileOutputStream(inventoryFile);
|
||||
DataOutputStream inventoryFileDataOutput = new DataOutputStream(inventoryFileOutputStream)) {
|
||||
inventoryFile.createNewFile();
|
||||
NbtIo.writeCompressed(nbt, inventoryFileDataOutput);
|
||||
} catch (Exception e) {
|
||||
System.out.println("[ShareEnderChest] Error while saving inventory: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onServerStopping(MinecraftServer server) {
|
||||
saveInventory(server);
|
||||
}
|
||||
|
||||
public void onEndTick(MinecraftServer server) {
|
||||
if (ticksUntilSave != -20 && --ticksUntilSave <= 0L) {
|
||||
saveInventory(server);
|
||||
ticksUntilSave = 20L;
|
||||
}
|
||||
}
|
||||
|
||||
public void onInitialize() {
|
||||
ticksUntilSave = 20L;
|
||||
|
||||
UseBlockCallback listenerUseBlock = (player, world, hand, hitResult) -> {
|
||||
|
||||
if (world.getBlockState(hitResult.getBlockPos()).getBlock() instanceof EnderChestBlock) {
|
||||
if (!player.isSpectator()) {
|
||||
if(!getConfig().sharedEnderChestLimitedAccess) {
|
||||
if (world.isClient()) return ActionResult.SUCCESS;
|
||||
playEnderChestOpenSound(world, hitResult.getBlockPos());
|
||||
openSharedEnderChest(player);
|
||||
return ActionResult.SUCCESS;
|
||||
} else {
|
||||
for(String name : getConfig().sharedEnderChestNames) {
|
||||
if(name.toLowerCase().strip().equalsIgnoreCase(player.getNameForScoreboard().toLowerCase())) {
|
||||
if (world.isClient()) return ActionResult.SUCCESS;
|
||||
playEnderChestOpenSound(world, hitResult.getBlockPos());
|
||||
openSharedEnderChest(player);
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
};
|
||||
|
||||
UseBlockCallback.EVENT.register(listenerUseBlock);
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(this);
|
||||
ServerLifecycleEvents.SERVER_STOPPING.register(this);
|
||||
ServerTickEvents.END_SERVER_TICK.register(this);
|
||||
|
||||
}
|
||||
|
||||
public static void openSharedEnderChest(PlayerEntity player) {
|
||||
player.openHandledScreen(new SimpleNamedScreenHandlerFactory((int_1, playerInventory, playerEntity) ->
|
||||
new GenericContainerScreenHandler(getConfig().screenHandlerType(), int_1, playerInventory, sharedInventory, getConfig().sharedEnderChestRows), Text.of(getConfig().sharedEnderChestName)));
|
||||
}
|
||||
|
||||
public static void playEnderChestOpenSound(World world, BlockPos pos) {
|
||||
world.playSound(null, pos, SoundEvents.BLOCK_ENDER_CHEST_OPEN, SoundCategory.BLOCKS, 0.5F, world.random.nextFloat() * 0.1F + 0.9F);
|
||||
}
|
||||
|
||||
private static File getFile(MinecraftServer server) {
|
||||
return server.getSavePath(WorldSavePath.ROOT).resolve("sharedenderchest.sav").toFile();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
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;
|
||||
|
||||
public SharedInventory(int inventoryRows) {
|
||||
this.stacks = DefaultedList.ofSize(inventoryRows * 9, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
public SharedInventory(DefaultedList<ItemStack> dl) {
|
||||
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;
|
||||
return dl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return stacks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
Iterator<ItemStack> var1 = this.stacks.iterator();
|
||||
|
||||
ItemStack itemStack_1;
|
||||
do {
|
||||
if (!var1.hasNext()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
itemStack_1 = (ItemStack)var1.next();
|
||||
} while(itemStack_1.isEmpty());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStack(int i) {
|
||||
return i >= stacks.size() ? ItemStack.EMPTY : stacks.get(i);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack removeStack(int i) {
|
||||
return Inventories.removeStack(this.stacks, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStack(int i, ItemStack itemStack) {
|
||||
this.stacks.set(i, itemStack);
|
||||
//this.container.onContentChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayerUse(PlayerEntity playerEntity) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
stacks.clear();
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
package wtf.hak.survivalfabric.utils;
|
||||
|
||||
import net.minecraft.scoreboard.ServerScoreboard;
|
||||
import net.minecraft.scoreboard.Team;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import wtf.hak.survivalfabric.commands.SpectatorCommand;
|
||||
|
||||
public class DimensionTeams {
|
||||
|
||||
public static DimensionTeams INSTANCE;
|
||||
|
||||
public Team overworldTeam;
|
||||
public Team netherTeam;
|
||||
public Team endTeam;
|
||||
public Team spectatorTeam;
|
||||
public Team unknownTeam;
|
||||
|
||||
public DimensionTeams(ServerPlayerEntity player) {
|
||||
ServerScoreboard scoreboard = player.getServer().getScoreboard();
|
||||
for(Team team : scoreboard.getTeams()) {
|
||||
if(team.getName().equals("survivalfabric_overworld")) {
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
|
||||
overworldTeam = team;
|
||||
} else if(team.getName().equals("survivalfabric_nether")) {
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
|
||||
netherTeam = team;
|
||||
} else if(team.getName().equals("survivalfabric_end")) {
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
|
||||
endTeam = team;
|
||||
} else if(team.getName().equals("survivalfabric_spectator")) {
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
|
||||
spectatorTeam = team;
|
||||
} else if(team.getName().equals("survivalfabric_unknown")) {
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("found old"), false);
|
||||
unknownTeam = team;
|
||||
}
|
||||
}
|
||||
if(overworldTeam == null) {
|
||||
overworldTeam = scoreboard.addTeam("survivalfabric_overworld");
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
|
||||
} else if (netherTeam == null) {
|
||||
netherTeam = scoreboard.addTeam("survivalfabric_nether");
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
|
||||
|
||||
} else if (endTeam == null) {
|
||||
endTeam = scoreboard.addTeam("survivalfabric_end");
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
|
||||
|
||||
} else if (spectatorTeam == null) {
|
||||
spectatorTeam = scoreboard.addTeam("survivalfabric_spectator");
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
|
||||
|
||||
} else if (unknownTeam == null) {
|
||||
unknownTeam = scoreboard.addTeam("survivalfabric_unknown");
|
||||
player.getServer().getPlayerManager().broadcast(Text.literal("added new"), false);
|
||||
|
||||
}
|
||||
|
||||
overworldTeam.setPrefix(Text.literal(Messages.OVERWORLD_PREFIX));
|
||||
overworldTeam.setColor(Formatting.GRAY);
|
||||
netherTeam.setPrefix(Text.literal(Messages.NETHER_PREFIX));
|
||||
netherTeam.setColor(Formatting.GRAY);
|
||||
endTeam.setPrefix(Text.literal(Messages.END_PREFIX));
|
||||
endTeam.setColor(Formatting.GRAY);
|
||||
spectatorTeam.setPrefix(Text.literal(Messages.SPECTATOR_PREFIX));
|
||||
spectatorTeam.setColor(Formatting.GRAY);
|
||||
unknownTeam.setPrefix(Text.literal(Messages.UNKNOWN_PREFIX));
|
||||
unknownTeam.setColor(Formatting.GRAY);
|
||||
}
|
||||
|
||||
public static Team assignCorrectTeam(ServerPlayerEntity player, String translationKey) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new DimensionTeams(player);
|
||||
}
|
||||
|
||||
ServerScoreboard scoreboard = player.getServer().getScoreboard();
|
||||
String name = player.getNameForScoreboard();
|
||||
|
||||
for(Team team : player.getServer().getScoreboard().getTeams()) {
|
||||
if(team.getName().startsWith("survivalfabric")) {
|
||||
if(team.getPlayerList().contains(name))
|
||||
scoreboard.removeScoreHolderFromTeam(name, team);
|
||||
}
|
||||
}
|
||||
|
||||
if(!SpectatorCommand.spectating.containsKey(player)) {
|
||||
switch (translationKey) {
|
||||
case "minecraft.overworld":
|
||||
scoreboard.addScoreHolderToTeam(name, INSTANCE.overworldTeam);
|
||||
return INSTANCE.overworldTeam;
|
||||
case "minecraft.the_nether":
|
||||
scoreboard.addScoreHolderToTeam(name, INSTANCE.netherTeam);
|
||||
return INSTANCE.netherTeam;
|
||||
case "minecraft.the_end":
|
||||
scoreboard.addScoreHolderToTeam(name, INSTANCE.endTeam);
|
||||
return INSTANCE.endTeam;
|
||||
default:
|
||||
scoreboard.addScoreHolderToTeam(name, INSTANCE.unknownTeam);
|
||||
return INSTANCE.unknownTeam;
|
||||
}
|
||||
} else {
|
||||
scoreboard.addScoreHolderToTeam(name, INSTANCE.spectatorTeam);
|
||||
return INSTANCE.spectatorTeam;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package wtf.hak.survivalfabric.utils;
|
||||
|
||||
public class Messages {
|
||||
public static final String JOIN_MESSAGE = "§8[§a+§8] §7%s";
|
||||
|
||||
public static final String QUIT_MESSAGE = "§8[§c-§8] §7%s";
|
||||
|
||||
public static final String CHAT_FORMAT = "§7%s§8:§f %s";
|
||||
|
||||
public static final String OVERWORLD_PREFIX = "§8[§aOverworld§8] ";
|
||||
public static final String NETHER_PREFIX = "§8[§cNether§8] ";
|
||||
public static final String END_PREFIX = "§8[§dEnd§8] ";
|
||||
public static final String SPECTATOR_PREFIX = "§8[§eSpectator§8] ";
|
||||
public static final String UNKNOWN_PREFIX = "§8[§7Unknown§8] ";
|
||||
|
||||
public static String getDimensionFormatted(String translationKey) {
|
||||
switch(translationKey) {
|
||||
case "minecraft.overworld":
|
||||
return "Overworld";
|
||||
case "minecraft.the_nether":
|
||||
return "Nether";
|
||||
case "minecraft.the_end":
|
||||
return "End";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
15
src/main/java/wtf/hak/survivalfabric/utils/Utils.java
Normal file
15
src/main/java/wtf/hak/survivalfabric/utils/Utils.java
Normal file
@ -0,0 +1,15 @@
|
||||
package wtf.hak.survivalfabric.utils;
|
||||
|
||||
import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static void updateListNames(ServerPlayerEntity p) {
|
||||
for(ServerPlayerEntity sp : Objects.requireNonNull(p.getServer()).getPlayerManager().getPlayerList()) {
|
||||
sp.networkHandler.sendPacket(new PlayerListS2CPacket(PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME, p));
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.2 KiB |
@ -1,13 +1,14 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "wtf.hak.survivalfabric.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
"PlayerManagerMixin",
|
||||
"ServerPlayNetworkHandlerMixin",
|
||||
"ServerWorldMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
"required": true,
|
||||
"package": "wtf.hak.survivalfabric.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
"PlayerManagerMixin",
|
||||
"ServerPlayerEntityMixin",
|
||||
"ServerPlayNetworkHandlerMixin",
|
||||
"ServerWorldMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user