Added the Shared Ender Chest
This commit is contained in:
18
README.md
18
README.md
@ -13,15 +13,21 @@ As a challenge I'm trying to make it as user-friendly as possible. (It ain't the
|
|||||||
### Commands
|
### 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.
|
- /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
|
## Currently working on v1.3.0
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- Config
|
- [x] Config
|
||||||
- [x] Configurable messages
|
- [x] Configurable messages
|
||||||
- [x] Feature toggle
|
- [x] Feature toggle
|
||||||
- [ ] Shared Ender Chest
|
- [x] Version "control"
|
||||||
- [ ] Access 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
|
### Misc
|
||||||
- [x] Updated icon
|
- [x] Updated icon
|
||||||
@ -30,9 +36,5 @@ As a challenge I'm trying to make it as user-friendly as possible. (It ain't the
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- Vein miner
|
|
||||||
- Telekinesis
|
|
||||||
|
|
||||||
### Commands
|
|
||||||
|
|
||||||
- /slimechunk (/sc) | See if you're currently in a slimechunk
|
|
@ -9,7 +9,7 @@ yarn_mappings=1.21.4+build.8
|
|||||||
loader_version=0.16.10
|
loader_version=0.16.10
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=1.2.1
|
mod_version=1.3.0
|
||||||
maven_group=wtf.hak.survivalfabric
|
maven_group=wtf.hak.survivalfabric
|
||||||
archives_base_name=survivalfabric
|
archives_base_name=survivalfabric
|
||||||
|
|
||||||
|
@ -3,11 +3,13 @@ package wtf.hak.survivalfabric;
|
|||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import wtf.hak.survivalfabric.commands.ReloadConfigCommand;
|
||||||
import wtf.hak.survivalfabric.commands.SpectatorCommand;
|
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 {
|
public class SurvivalFabric implements ModInitializer {
|
||||||
|
|
||||||
@ -18,6 +20,9 @@ public class SurvivalFabric implements ModInitializer {
|
|||||||
@Override
|
@Override
|
||||||
public void onInitialize() {
|
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) -> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,11 @@
|
|||||||
package wtf.hak.survivalfabric.config;
|
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 class Config {
|
||||||
|
|
||||||
public String configVersion = "1.0";
|
public String configVersion = "1.0";
|
||||||
@ -20,4 +26,21 @@ public class Config {
|
|||||||
public String spectatorPrefix = "§8[§eSpectator§8] ";
|
public String spectatorPrefix = "§8[§eSpectator§8] ";
|
||||||
public String unknownPrefix = "§8[§7Unknown§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,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();
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user