Merge branch 'dev'
# Conflicts: # gradle.properties # src/main/java/one/oth3r/sit/Events.java # src/main/java/one/oth3r/sit/ModMenu.java # src/main/java/one/oth3r/sit/file/Config.java
|
@ -1,280 +0,0 @@
|
|||
package one.oth3r.sit;
|
||||
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.enums.BlockHalf;
|
||||
import net.minecraft.block.enums.SlabType;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.consume.UseAction;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import one.oth3r.sit.Utl.HandSettings.HandType;
|
||||
import one.oth3r.sit.file.Config;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Events {
|
||||
private static int tick;
|
||||
public static HashMap<ServerPlayerEntity, Entity> entities = new HashMap<>();
|
||||
public static HashMap<ServerPlayerEntity, Integer> checkPlayers = new HashMap<>();
|
||||
public static boolean checkLogic(ServerPlayerEntity player) {
|
||||
ArrayList<UseAction> food = new ArrayList<>();
|
||||
food.add(UseAction.EAT);
|
||||
food.add(UseAction.DRINK);
|
||||
ArrayList<UseAction> notUsable = new ArrayList<>(food);
|
||||
notUsable.add(UseAction.NONE);
|
||||
HashMap<HandType, ItemStack> itemMap = new HashMap<>();
|
||||
itemMap.put(Utl.HandSettings.HandType.main,player.getMainHandStack());
|
||||
itemMap.put(Utl.HandSettings.HandType.off,player.getOffHandStack());
|
||||
// if sneaking cant sit
|
||||
if (player.isSneaking()) return false;
|
||||
// for both hands
|
||||
for (HandType type: Utl.HandSettings.HandType.values()) {
|
||||
ItemStack targetStack = itemMap.get(type);
|
||||
// if req is empty and the item isn't empty, false
|
||||
if (Utl.HandSettings.getReq(player,type).equals(Config.HandRequirement.empty) && !targetStack.isEmpty()) return false;
|
||||
// if req is restrictive
|
||||
if (Utl.HandSettings.getReq(player,type).equals(Config.HandRequirement.restrictive)) {
|
||||
// if item is in blacklist, false
|
||||
if (checkList(Utl.HandSettings.getList(player,type,"blacklist"),targetStack)) return false;
|
||||
// if item is NOT in whitelist
|
||||
if (!checkList(Utl.HandSettings.getList(player,type,"whitelist"),targetStack)) {
|
||||
// if block is restricted and items is block, false, ect
|
||||
if (Utl.HandSettings.getBool(player,type,"block") && (targetStack.getItem() instanceof BlockItem)) return false;
|
||||
if (Utl.HandSettings.getBool(player,type,"food") && food.contains(targetStack.getUseAction())) return false;
|
||||
if (Utl.HandSettings.getBool(player,type,"usable") && !notUsable.contains(targetStack.getUseAction())) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else true
|
||||
return true;
|
||||
}
|
||||
public static boolean checkList(List<String> list, ItemStack itemStack) {
|
||||
// check if a list has an item
|
||||
String itemID = Registries.ITEM.getId(itemStack.getItem()).toString();
|
||||
return list.contains(itemID);
|
||||
}
|
||||
public static HashMap<String,HashMap<String,Object>> getCustomBlocks() {
|
||||
// get a hashmap of custom blocks
|
||||
HashMap<String,HashMap<String,Object>> map = new HashMap<>();
|
||||
int i = 1;
|
||||
for (String s: Config.customBlocks) {
|
||||
String[] split = s.split("\\|");
|
||||
HashMap<String,Object> data = new HashMap<>();
|
||||
data.put("block",split[0]);
|
||||
data.put("height",split[1]);
|
||||
data.put("hitbox",split[2]);
|
||||
if (split.length==4) data.put("state",split[3]);
|
||||
map.put(String.valueOf(i),data);
|
||||
i++;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
public static boolean isSitSafe(Block block) {
|
||||
// check if the block is sit safe (like a sign in the way)
|
||||
return block instanceof WallSignBlock || block instanceof TrapdoorBlock ||
|
||||
block instanceof WallBannerBlock || block instanceof AirBlock;
|
||||
}
|
||||
public static boolean checkBlocks(BlockPos pos, World world, boolean isAbove) {
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
Block block = blockState.getBlock();
|
||||
// make sure the block above the chair is safe
|
||||
if (!isSitSafe(world.getBlockState(pos.add(0,1,0)).getBlock())) return false;
|
||||
// if the player is above the block, (taller) check the next block above
|
||||
if (isAbove && !isSitSafe(world.getBlockState(pos.add(0,2,0)).getBlock())) return false;
|
||||
//if there's already an entity at the block location or one above it
|
||||
for (Entity entity:entities.values()) if (entity.getBlockPos().equals(pos) || entity.getBlockPos().add(0,1,0).equals(pos)) return false;
|
||||
|
||||
// return for the 4 default types
|
||||
if (block instanceof StairsBlock && Config.stairsOn) return blockState.get(StairsBlock.HALF) == BlockHalf.BOTTOM;
|
||||
if (block instanceof SlabBlock && Config.slabsOn) return blockState.get(SlabBlock.TYPE) == SlabType.BOTTOM;
|
||||
if (block instanceof CarpetBlock && Config.carpetsOn) return true;
|
||||
if (blockState.isFullCube(world,pos.add(0,1,0)) && Config.fullBlocksOn) return true;
|
||||
// custom checker
|
||||
if (Config.customOn && Config.customBlocks.size() != 0) {
|
||||
for (HashMap<String,Object> map:getCustomBlocks().values()) {
|
||||
String blockID = Registries.BLOCK.getId(block).toString();
|
||||
if (map.get("block").equals(blockID)) {
|
||||
if (!map.containsKey("state")) return true;
|
||||
String[] states = ((String) map.get("state")).split(",\\s*");
|
||||
boolean matching = true;
|
||||
for (String state:states) {
|
||||
if (state.charAt(0) == '!') {
|
||||
if (blockState.toString().contains(state.substring(1))) matching = false;
|
||||
} else if (!blockState.toString().contains(state)) matching = false;
|
||||
}
|
||||
return matching;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static boolean isAboveBlockheight(Entity entity) {
|
||||
return entity.getPitch()<0;
|
||||
}
|
||||
public static void setEntity(BlockPos pos, World world, Entity entity) {
|
||||
Block block = world.getBlockState(pos).getBlock();
|
||||
entity.setCustomName(Text.of(Sit.ENTITY_NAME));
|
||||
entity.setCustomNameVisible(false);
|
||||
double hitBoxY = 0.5;
|
||||
entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.47, pos.getZ() + 0.5, 0, 0);
|
||||
entity.setInvulnerable(true);
|
||||
if (block instanceof StairsBlock) {
|
||||
entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.27, pos.getZ() + 0.5, 0, 0);
|
||||
hitBoxY = 2;
|
||||
}
|
||||
if (block instanceof SlabBlock) {
|
||||
entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.27, pos.getZ() + 0.5, 0, 0);
|
||||
hitBoxY = 1;
|
||||
}
|
||||
if (block instanceof CarpetBlock) {
|
||||
entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()-.17, pos.getZ() + 0.5, 0, 0);
|
||||
hitBoxY = 0.125;
|
||||
}
|
||||
if (world.getBlockState(pos).isFullCube(world,pos.add(0,1,0))) {
|
||||
entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.78, pos.getZ() + 0.5, 0, 0);
|
||||
hitBoxY = 2;
|
||||
}
|
||||
if (Config.customOn && !Config.customBlocks.isEmpty()) {
|
||||
for (HashMap<String,Object> map:getCustomBlocks().values()) {
|
||||
String blockID = Registries.BLOCK.getId(block).toString();
|
||||
if (map.get("block").equals(blockID)) {
|
||||
double input = Math.max(Math.min(Double.parseDouble((String) map.get("height")),1),0);
|
||||
entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+input-.22, pos.getZ() + 0.5, 0, 0);
|
||||
hitBoxY = Double.parseDouble((String) map.get("hitbox"));
|
||||
}
|
||||
}
|
||||
}
|
||||
//1.20.2 mounting pos change (shifts everything down by .25)
|
||||
double oneTwentyTwo = .25;
|
||||
entity.updatePositionAndAngles(entity.getX(),entity.getY()+oneTwentyTwo,entity.getZ(),0,0);
|
||||
entity.setBoundingBox(Box.of(Vec3d.of(pos),1.5,hitBoxY,1.5));
|
||||
//change pitch based on if player is sitting below block height or not
|
||||
if (entity.getY() <= pos.getY()+.35+oneTwentyTwo) entity.setPitch(90); // below
|
||||
else entity.setPitch(-90); // above
|
||||
}
|
||||
public static boolean sit(ServerPlayerEntity player, BlockPos pos) {
|
||||
// todo interactions entity to make the sitting hitbox?
|
||||
World world = player.getWorld();
|
||||
DisplayEntity.TextDisplayEntity entity = new DisplayEntity.TextDisplayEntity(EntityType.TEXT_DISPLAY,player.getServerWorld());
|
||||
setEntity(pos,world,entity);
|
||||
if (checkBlocks(pos,world,isAboveBlockheight(entity))) {
|
||||
if (entities.containsKey(player)) {
|
||||
if (!Config.sitWhileSeated) return false;
|
||||
entities.get(player).setRemoved(Entity.RemovalReason.DISCARDED);
|
||||
entities.remove(player);
|
||||
}
|
||||
player.getServerWorld().spawnEntity(entity);
|
||||
player.startRiding(entity);
|
||||
entities.put(player,entity);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static void register() {
|
||||
ServerTickEvents.END_SERVER_TICK.register(minecraftServer -> minecraftServer.execute(Events::cleanUp));
|
||||
// PLAYER JOIN
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
||||
ServerPlayerEntity player = handler.player;
|
||||
checkPlayers.put(player,2);
|
||||
// put server settings in the player settings
|
||||
Sit.playerSettings.put(player, Utl.HandSettings.getHandSettings());
|
||||
});
|
||||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||
ServerPlayerEntity player = handler.player;
|
||||
if (entities.containsKey(player)) {
|
||||
if (!Config.keepActive) {
|
||||
player.dismountVehicle();
|
||||
entities.get(player).setRemoved(Entity.RemovalReason.DISCARDED);
|
||||
}
|
||||
entities.remove(player);
|
||||
}
|
||||
checkPlayers.remove(player);
|
||||
Sit.playerSettings.remove(player);
|
||||
});
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(s -> {
|
||||
Sit.server = s;
|
||||
Sit.commandManager = s.getCommandManager();
|
||||
UseBlockCallback.EVENT.register((pl, world, hand, hitResult) -> {
|
||||
if (!Config.handSitting) return ActionResult.PASS;
|
||||
// make sure its a server player
|
||||
if (pl.getClass() != ServerPlayerEntity.class) return ActionResult.PASS;
|
||||
ServerPlayerEntity player = Sit.server.getPlayerManager().getPlayer(pl.getUuid());
|
||||
if (player == null) return ActionResult.PASS;
|
||||
if (hand == net.minecraft.util.Hand.MAIN_HAND && hitResult.getType() == HitResult.Type.BLOCK) {
|
||||
BlockPos pos = hitResult.getBlockPos();
|
||||
// check the players hands
|
||||
if (!checkLogic(player)) return ActionResult.PASS;
|
||||
// make the player sit
|
||||
boolean status = sit(player,pos);
|
||||
// if sat, cancel / FAIL the use block event
|
||||
if (status) return ActionResult.FAIL;
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
});
|
||||
});
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> SitCommand.register(dispatcher));
|
||||
}
|
||||
public static void cleanUp() {
|
||||
tick++;
|
||||
if (tick >= 5) {
|
||||
tick = 0;
|
||||
Iterator<Map.Entry<ServerPlayerEntity, Entity>> entityLoop = entities.entrySet().iterator();
|
||||
while (entityLoop.hasNext()) {
|
||||
Map.Entry<ServerPlayerEntity, Entity> entry = entityLoop.next();
|
||||
ServerPlayerEntity player = entry.getKey();
|
||||
Entity entity = entry.getValue();
|
||||
if (player.getVehicle() == null || !player.getVehicle().equals(entity)) {
|
||||
entity.setRemoved(Entity.RemovalReason.DISCARDED);
|
||||
entityLoop.remove();
|
||||
} else {
|
||||
// if below the blockheight, round up the player pos
|
||||
BlockPos pos = new BlockPos(entity.getBlockX(),(int)Math.ceil(player.getY()),entity.getBlockZ());
|
||||
// if above the block, round down the player pos
|
||||
if (isAboveBlockheight(entity)) pos = new BlockPos(entity.getBlockX(),(int)Math.floor(player.getY()),entity.getBlockZ());
|
||||
BlockState blockState = player.getWorld().getBlockState(pos);
|
||||
// check if said block is still there
|
||||
if (blockState.isAir()) {
|
||||
player.teleport(player.getX(),player.getBlockY()+1,player.getZ(),false);
|
||||
entity.setRemoved(Entity.RemovalReason.DISCARDED);
|
||||
entityLoop.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
Iterator<Map.Entry<ServerPlayerEntity, Integer>> playerCheckLoop = checkPlayers.entrySet().iterator();
|
||||
while (playerCheckLoop.hasNext()) {
|
||||
Map.Entry<ServerPlayerEntity, Integer> entry = playerCheckLoop.next();
|
||||
ServerPlayerEntity player = entry.getKey();
|
||||
int i = entry.getValue();
|
||||
checkPlayers.put(player,i-1);
|
||||
if (i<0) {
|
||||
playerCheckLoop.remove();
|
||||
continue;
|
||||
}
|
||||
if (player.getVehicle() != null) {
|
||||
Entity entity = player.getVehicle();
|
||||
if (entity.getName().getString().equals(Sit.ENTITY_NAME)) {
|
||||
setEntity(player.getBlockPos().add(0,1,0),player.getServerWorld(),entity);
|
||||
entities.put(player,entity);
|
||||
playerCheckLoop.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
package one.oth3r.sit;
|
||||
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
import dev.isxander.yacl3.api.*;
|
||||
import dev.isxander.yacl3.api.controller.BooleanControllerBuilder;
|
||||
import dev.isxander.yacl3.api.controller.EnumControllerBuilder;
|
||||
import dev.isxander.yacl3.api.controller.StringControllerBuilder;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TextColor;
|
||||
import net.minecraft.util.Formatting;
|
||||
import one.oth3r.sit.file.Config;
|
||||
|
||||
public class ModMenu implements ModMenuApi {
|
||||
|
||||
private static MutableText lang(String key) {
|
||||
return Text.translatable("config.sit."+key);
|
||||
}
|
||||
|
||||
private static MutableText lang(String key, Object... args) {
|
||||
return Text.translatable("config.sit."+key,args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||
// return null if YACL isn't installed to not throw an error
|
||||
if (!yaclCheck()) return screen -> null;
|
||||
return parent -> YetAnotherConfigLib.createBuilder().save(() -> {
|
||||
// save and load to get rid of bad data
|
||||
Config.save();
|
||||
Config.load();
|
||||
})
|
||||
.title(Text.of("Sit!"))
|
||||
.category(ConfigCategory.createBuilder()
|
||||
.name(lang("category.general"))
|
||||
.tooltip(lang("category.general.tooltip"))
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("general.keep_active"))
|
||||
.description(OptionDescription.of(lang("general.keep_active.description")))
|
||||
.binding(Config.defaults.keepActive, () -> Config.keepActive, n -> Config.keepActive = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("general.sit_while_seated"))
|
||||
.description(OptionDescription.of(lang("general.sit_while_seated.description")))
|
||||
.binding(Config.defaults.sitWhileSeated, () -> Config.sitWhileSeated, n -> Config.sitWhileSeated = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(Text.of("Sitting with Hand"))
|
||||
.description(OptionDescription.of(Text.of("Toggles the player's ability to sit with their hand.")))
|
||||
.binding(Config.defaults.handSitting,()-> Config.handSitting, n -> Config.handSitting = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.group(OptionGroup.createBuilder()
|
||||
.name(lang("general.sittable"))
|
||||
.description(OptionDescription.of(lang("general.sittable.description")))
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("general.sittable.stairs"))
|
||||
.binding(Config.defaults.stairsOn, () -> Config.stairsOn, n -> Config.stairsOn = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("general.sittable.slabs"))
|
||||
.binding(Config.defaults.slabsOn, () -> Config.slabsOn, n -> Config.slabsOn = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("general.sittable.carpets"))
|
||||
.binding(Config.defaults.carpetsOn, () -> Config.carpetsOn, n -> Config.carpetsOn = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("general.sittable.full_blocks"))
|
||||
.binding(Config.defaults.fullBlocksOn, () -> Config.fullBlocksOn, n -> Config.fullBlocksOn = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("general.sittable.custom"))
|
||||
.description(OptionDescription.of(lang("general.sittable.custom.description")))
|
||||
.binding(Config.defaults.customOn, () -> Config.customOn, n -> Config.customOn = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter())
|
||||
.build())
|
||||
.build())
|
||||
.group(ListOption.<String>createBuilder()
|
||||
.name(lang("general.sittable_blocks"))
|
||||
.description(OptionDescription.of(
|
||||
lang("general.sittable_blocks.description")
|
||||
.append("\n\n").append(lang("general.sittable_blocks.description_2",
|
||||
Text.literal("\"")
|
||||
.append(Text.literal("minecraft:campfire").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
.append("|")
|
||||
.append(Text.literal("0.255").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED))))
|
||||
.append("|")
|
||||
.append(Text.literal("1").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
.append("|")
|
||||
.append(Text.literal("lit=false").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD))))
|
||||
.append("\"").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY)))))
|
||||
.append("\n\n").append(lang("general.sittable_blocks.description_4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
.append("\n").append(lang("general.sittable_blocks.description_5").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED))))
|
||||
.append("\n").append(lang("general.sittable_blocks.description_6").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
.append("\n").append(lang("general.sittable_blocks.description_7").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD))))
|
||||
.append("\n\n").append(lang("general.sittable_blocks.description_8").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.YELLOW))))))
|
||||
.binding(Config.defaults.customBlocks, () -> Config.customBlocks, n -> Config.customBlocks = n)
|
||||
.controller(StringControllerBuilder::create)
|
||||
.initial("")
|
||||
.build())
|
||||
.build())
|
||||
.category(ConfigCategory.createBuilder()
|
||||
.name(lang("category.main_hand"))
|
||||
.tooltip(lang("category.main_hand.tooltip"))
|
||||
.option(Option.<Config.HandRequirement>createBuilder()
|
||||
.name(lang("hand.requirements"))
|
||||
.description(OptionDescription.of(lang("hand.requirements.description")
|
||||
.append("\n\n").append(lang("hand.requirements.description_2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
.append("\n").append(lang("hand.requirements.description_3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
.append("\n").append(lang("hand.requirements.description_4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED))))))
|
||||
.binding(Config.defaults.mainReq, () -> Config.mainReq, n -> Config.mainReq = n)
|
||||
.controller(opt -> EnumControllerBuilder.create(opt).enumClass(Config.HandRequirement.class)
|
||||
.formatValue(v -> Text.translatable("config.sit."+v.name().toLowerCase())))
|
||||
.build())
|
||||
.group(OptionGroup.createBuilder()
|
||||
.name(lang("hand.restrictions"))
|
||||
.description(OptionDescription.of(lang("hand.restrictions.description")))
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restrictions.blocks"))
|
||||
.binding(Config.defaults.mainBlock,()-> Config.mainBlock, n -> Config.mainBlock = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restrictions.food"))
|
||||
.binding(Config.defaults.mainFood,()-> Config.mainFood, n -> Config.mainFood = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restrictions.usable"))
|
||||
.description(OptionDescription.of(lang("hand.restrictions.usable.description")))
|
||||
.binding(Config.defaults.mainUsable,()-> Config.mainUsable, n -> Config.mainUsable = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.build())
|
||||
.group(ListOption.<String>createBuilder()
|
||||
.name(lang("hand.whitelist"))
|
||||
.description(OptionDescription.of(lang("hand.whitelist.description")
|
||||
.append("\n\n").append(lang("hand.list.description"))
|
||||
.append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))
|
||||
.binding(Config.defaults.mainWhitelist, () -> Config.mainWhitelist, n -> Config.mainWhitelist = n)
|
||||
.controller(StringControllerBuilder::create)
|
||||
.initial("")
|
||||
.build())
|
||||
.group(ListOption.<String>createBuilder()
|
||||
.name(lang("hand.blacklist"))
|
||||
.description(OptionDescription.of(lang("hand.blacklist.description")
|
||||
.append("\n\n").append(lang("hand.list.description"))
|
||||
.append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))
|
||||
.binding(Config.defaults.mainBlacklist, () -> Config.mainBlacklist, n -> Config.mainBlacklist = n)
|
||||
.controller(StringControllerBuilder::create)
|
||||
.initial("")
|
||||
.build())
|
||||
.build())
|
||||
.category(ConfigCategory.createBuilder()
|
||||
.name(lang("category.off_hand"))
|
||||
.tooltip(lang("category.off_hand.tooltip"))
|
||||
.option(Option.<Config.HandRequirement>createBuilder()
|
||||
.name(lang("hand.requirements"))
|
||||
.description(OptionDescription.of(lang("hand.requirements.description")
|
||||
.append("\n\n").append(lang("hand.requirements.description_2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
.append("\n").append(lang("hand.requirements.description_3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
.append("\n").append(lang("hand.requirements.description_4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED))))))
|
||||
.binding(Config.defaults.offReq, () -> Config.offReq, n -> Config.offReq = n)
|
||||
.controller(opt -> EnumControllerBuilder.create(opt).enumClass(Config.HandRequirement.class)
|
||||
.formatValue(v -> Text.translatable("config.sit."+v.name().toLowerCase())))
|
||||
.build())
|
||||
.group(OptionGroup.createBuilder()
|
||||
.name(lang("hand.restrictions"))
|
||||
.description(OptionDescription.of(lang("hand.restrictions.description")))
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restrictions.blocks"))
|
||||
.binding(Config.defaults.offBlock,()-> Config.offBlock, n -> Config.offBlock = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restrictions.food"))
|
||||
.binding(Config.defaults.offFood,()-> Config.offFood, n -> Config.offFood = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restrictions.usable"))
|
||||
.description(OptionDescription.of(lang("hand.restrictions.usable.description")))
|
||||
.binding(Config.defaults.offUsable,()-> Config.offUsable, n -> Config.offUsable = n)
|
||||
.controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter())
|
||||
.build())
|
||||
.build())
|
||||
.group(ListOption.<String>createBuilder()
|
||||
.name(lang("hand.whitelist"))
|
||||
.description(OptionDescription.of(lang("hand.whitelist.description")
|
||||
.append("\n\n").append(lang("hand.list.description"))
|
||||
.append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))
|
||||
.binding(Config.defaults.offWhitelist, () -> Config.offWhitelist, n -> Config.offWhitelist = n)
|
||||
.controller(StringControllerBuilder::create)
|
||||
.initial("")
|
||||
.build())
|
||||
.group(ListOption.<String>createBuilder()
|
||||
.name(lang("hand.blacklist"))
|
||||
.description(OptionDescription.of(lang("hand.blacklist.description")
|
||||
.append("\n\n").append(lang("hand.list.description"))
|
||||
.append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY))))))
|
||||
.binding(Config.defaults.offBlacklist, () -> Config.offBlacklist, n -> Config.offBlacklist = n)
|
||||
.controller(StringControllerBuilder::create)
|
||||
.initial("")
|
||||
.build())
|
||||
.build())
|
||||
.build().generateScreen(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if YACL is installed by getting a class and seeing if it throws
|
||||
* @return if YACL is installed
|
||||
*/
|
||||
public static boolean yaclCheck() {
|
||||
try {
|
||||
Class.forName("dev.isxander.yacl3.platform.Env");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +1,15 @@
|
|||
package one.oth3r.sit;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import one.oth3r.sit.file.Config;
|
||||
import one.oth3r.sit.packet.CustomPayloads;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import one.oth3r.sit.file.FileData;
|
||||
import one.oth3r.sit.utl.Events;
|
||||
|
||||
public class Sit implements ModInitializer {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("sit");
|
||||
public static final String MOD_ID = "oth3r-sit";
|
||||
public static HashMap<ServerPlayerEntity, HashMap<String,String>> playerSettings = new HashMap<>();
|
||||
public static final String ENTITY_NAME = "-sit!-entity-";
|
||||
public static MinecraftServer server;
|
||||
public static CommandManager commandManager;
|
||||
public static boolean isClient = false;
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
//todo future:
|
||||
// make it so it updates the sitting height and pos based on the block so if it changed while offline it still works (or if stair changes shape)
|
||||
// inner stair offset & custom support for that ig
|
||||
Config.load();
|
||||
Events.register();
|
||||
//PACKETS
|
||||
PayloadTypeRegistry.playC2S().register(CustomPayloads.SettingsPayload.ID, CustomPayloads.SettingsPayload.CODEC);
|
||||
ServerPlayNetworking.registerGlobalReceiver(CustomPayloads.SettingsPayload.ID,((payload, context) -> server.execute(() -> {
|
||||
Type hashMapToken = new TypeToken<HashMap<String, Object>>() {}.getType();
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
LOGGER.info(String.format("Received custom sitting settings from %s.",context.player().getName().getString()));
|
||||
playerSettings.put(context.player(),gson.fromJson(payload.value(),hashMapToken));
|
||||
})));
|
||||
}
|
||||
|
||||
public static MutableText lang(String key, Object... args) {
|
||||
if (isClient) return Text.translatable(key, args);
|
||||
else return LangReader.of(key, args).getTxT();
|
||||
FileData.loadFiles();
|
||||
Events.registerCommon();
|
||||
}
|
||||
}
|
|
@ -1,33 +1,16 @@
|
|||
package one.oth3r.sit;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import one.oth3r.sit.packet.CustomPayloads;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Events;
|
||||
|
||||
public class SitClient implements ClientModInitializer {
|
||||
public static boolean inGame = false;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
Sit.isClient = true;
|
||||
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
|
||||
inGame = true;
|
||||
// send a data packet whenever joining a server
|
||||
sendSettingsPackets();
|
||||
});
|
||||
// reset inGame
|
||||
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> inGame = false);
|
||||
Data.setClient(true);
|
||||
Events.registerClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* sends the settings packets to the server is the client is in game
|
||||
*/
|
||||
public static void sendSettingsPackets() {
|
||||
if (inGame) {
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
ClientPlayNetworking.send(new CustomPayloads.SettingsPayload(gson.toJson(Utl.HandSettings.getHandSettings())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package one.oth3r.sit;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import one.oth3r.sit.file.Config;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class Utl {
|
||||
public static class HandSettings {
|
||||
public static HashMap<String,String> getHandSettings() {
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
HashMap<String,String> settings = new HashMap<>();
|
||||
settings.put("hand.main.requirement",String.valueOf(Config.mainReq));
|
||||
settings.put("hand.main.block",String.valueOf(Config.mainBlock));
|
||||
settings.put("hand.main.food",String.valueOf(Config.mainFood));
|
||||
settings.put("hand.main.usable",String.valueOf(Config.mainUsable));
|
||||
settings.put("hand.main.whitelist",gson.toJson(Config.mainWhitelist));
|
||||
settings.put("hand.main.blacklist",gson.toJson(Config.mainBlacklist));
|
||||
settings.put("hand.off.requirement",String.valueOf(Config.offReq));
|
||||
settings.put("hand.off.block",String.valueOf(Config.offBlock));
|
||||
settings.put("hand.off.food",String.valueOf(Config.offFood));
|
||||
settings.put("hand.off.usable",String.valueOf(Config.offUsable));
|
||||
settings.put("hand.off.whitelist",gson.toJson(Config.offWhitelist));
|
||||
settings.put("hand.off.blacklist",gson.toJson(Config.offBlacklist));
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static Config.HandRequirement getReq(ServerPlayerEntity player, HandType type) {
|
||||
return Config.HandRequirement.get(Sit.playerSettings.get(player).get("hand."+type+".requirement"));
|
||||
}
|
||||
|
||||
public static List<String> getList(ServerPlayerEntity player, HandType type, String setting) {
|
||||
Type listType = new TypeToken<ArrayList<String>>() {}.getType();
|
||||
return new Gson().fromJson(Sit.playerSettings.get(player).get("hand."+type+"."+setting),listType);
|
||||
}
|
||||
|
||||
public static boolean getBool(ServerPlayerEntity player, HandType type, String setting) {
|
||||
return Boolean.parseBoolean(Sit.playerSettings.get(player).get("hand."+type+"."+setting));
|
||||
}
|
||||
|
||||
public enum HandType {
|
||||
main,
|
||||
off
|
||||
}
|
||||
}
|
||||
public static class Num {
|
||||
public static boolean isInt(String string) {
|
||||
try {
|
||||
Integer.parseInt(string);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static boolean isFloat(String string) {
|
||||
try {
|
||||
Float.parseFloat(string);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +1,18 @@
|
|||
package one.oth3r.sit;
|
||||
package one.oth3r.sit.command;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.ParseResults;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.TextColor;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import one.oth3r.sit.file.Config;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Logic;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
@ -27,57 +26,59 @@ public class SitCommand {
|
|||
.suggests(SitCommand::getSuggestions)
|
||||
.executes((context2) -> command(context2.getSource(), context2.getInput()))));
|
||||
}
|
||||
|
||||
public static CompletableFuture<Suggestions> getSuggestions(CommandContext<ServerCommandSource> context, SuggestionsBuilder builder) {
|
||||
builder.suggest("reload");
|
||||
builder.suggest("purgeChairEntities");
|
||||
return builder.buildFuture();
|
||||
}
|
||||
|
||||
private static int command(ServerCommandSource source, String arg) {
|
||||
ServerPlayerEntity player = source.getPlayer();
|
||||
//trim all the arguments before the command
|
||||
String keyword = "sit";
|
||||
int index = Integer.MAX_VALUE;
|
||||
if (arg.contains(keyword)) index = arg.indexOf(keyword);
|
||||
//trims the words before the text
|
||||
if (index != Integer.MAX_VALUE) arg = arg.substring(index).trim();
|
||||
// trim all the arguments before the command (for commands like /execute)
|
||||
int index = arg.indexOf("sit");
|
||||
// trims the words before the text
|
||||
if (index != -1) arg = arg.substring(index).trim();
|
||||
|
||||
String[] args = arg.split(" ");
|
||||
// if command string starts with sit, remove it
|
||||
if (args[0].equalsIgnoreCase("sit"))
|
||||
args = arg.replaceFirst("sit ", "").split(" ");
|
||||
|
||||
// if console
|
||||
if (player == null) {
|
||||
if (args[0].equalsIgnoreCase("reload")) {
|
||||
Config.load();
|
||||
Sit.LOGGER.info(Sit.lang("key.sit.command.reloaded").getString());
|
||||
Logic.reload();
|
||||
Data.LOGGER.info(Utl.lang("sit!.chat.reloaded").getString());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// player
|
||||
|
||||
if (args[0].equalsIgnoreCase("sit")) {
|
||||
BlockPos pos = player.getBlockPos();
|
||||
// get the block under the player if player on top of a solid
|
||||
if (!(player.getY() - ((int) player.getY()) > 0.00)) {
|
||||
pos = pos.add(0,-1,0);
|
||||
// if the player can't sit where they're looking, try to sit below
|
||||
if (!Logic.sitLooking(player)) {
|
||||
BlockPos pos = player.getBlockPos();
|
||||
|
||||
if (!(player.getY() - ((int) player.getY()) > 0.00)) {
|
||||
pos = pos.add(0, -1, 0);
|
||||
}
|
||||
|
||||
// if already sitting, ignore
|
||||
if (Data.getSitEntity(player) != null) return 1;
|
||||
|
||||
// try to make the player sit
|
||||
Logic.sit(player, pos, null);
|
||||
}
|
||||
// if already sitting, ignore
|
||||
if (Events.entities.containsKey(player)) return 1;
|
||||
// sit
|
||||
Events.sit(player,pos);
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("reload")) {
|
||||
Config.load();
|
||||
player.sendMessage(Sit.lang("key.sit.command.reloaded").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))));
|
||||
}
|
||||
if (args[0].equalsIgnoreCase("purgeChairEntities")) {
|
||||
String cmd = "kill @e[type=minecraft:text_display,name=\""+Sit.ENTITY_NAME+"\"]";
|
||||
try {
|
||||
ParseResults<ServerCommandSource> parse =
|
||||
Sit.commandManager.getDispatcher().parse(cmd, player.getCommandSource());
|
||||
Sit.commandManager.getDispatcher().execute(parse);
|
||||
player.sendMessage(Sit.lang("key.sit.command.purged"));
|
||||
} catch (CommandSyntaxException e) {
|
||||
player.sendMessage(Sit.lang("key.sit.command.purged"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
Logic.reload();
|
||||
player.sendMessage(Utl.messageTag().append(Utl.lang("sit!.chat.reloaded").formatted(Formatting.GREEN)));
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("purgeChairEntities")) Utl.Entity.purge(player,true);
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,252 +0,0 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import one.oth3r.sit.LangReader;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.SitClient;
|
||||
import one.oth3r.sit.Utl.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public class Config {
|
||||
public static String lang = defaults.lang;
|
||||
public static boolean keepActive = defaults.keepActive;
|
||||
public static boolean sitWhileSeated = defaults.sitWhileSeated;
|
||||
public static boolean stairsOn = defaults.stairsOn;
|
||||
public static boolean slabsOn = defaults.slabsOn;
|
||||
public static boolean carpetsOn = defaults.carpetsOn;
|
||||
public static boolean fullBlocksOn = defaults.fullBlocksOn;
|
||||
public static boolean customOn = defaults.customOn;
|
||||
public static List<String> customBlocks = defaults.customBlocks;
|
||||
public enum HandRequirement {
|
||||
empty,
|
||||
restrictive,
|
||||
none;
|
||||
public static HandRequirement get(String s) {
|
||||
try {
|
||||
return HandRequirement.valueOf(s);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static boolean handSitting = defaults.handSitting;
|
||||
public static HandRequirement mainReq = defaults.mainReq;
|
||||
public static boolean mainBlock = defaults.mainBlock;
|
||||
public static boolean mainFood = defaults.mainFood;
|
||||
public static boolean mainUsable = defaults.mainUsable;
|
||||
public static List<String> mainWhitelist = defaults.mainWhitelist;
|
||||
public static List<String> mainBlacklist = defaults.mainBlacklist;
|
||||
public static HandRequirement offReq = defaults.offReq;
|
||||
public static boolean offBlock = defaults.offBlock;
|
||||
public static boolean offFood = defaults.offFood;
|
||||
public static boolean offUsable = defaults.offUsable;
|
||||
public static List<String> offWhitelist = defaults.offWhitelist;
|
||||
public static List<String> offBlacklist = defaults.offBlacklist;
|
||||
public static File configFile() {
|
||||
return new File(FabricLoader.getInstance().getConfigDir().toFile()+"/Sit!.properties");
|
||||
}
|
||||
public static void load() {
|
||||
if (!configFile().exists() || !configFile().canRead()) {
|
||||
save();
|
||||
load();
|
||||
return;
|
||||
}
|
||||
try (FileInputStream fileStream = new FileInputStream(configFile())) {
|
||||
Properties properties = new Properties();
|
||||
properties.load(fileStream);
|
||||
String ver = (String) properties.computeIfAbsent("version", a -> String.valueOf(defaults.version));
|
||||
|
||||
// if the old version system (v1.0) remove "v"
|
||||
if (ver.contains("v")) ver = ver.substring(1);
|
||||
|
||||
loadVersion(properties,Double.parseDouble(ver));
|
||||
LangReader.loadLanguageFile();
|
||||
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
//read fail
|
||||
e.printStackTrace();
|
||||
save();
|
||||
}
|
||||
}
|
||||
public static ArrayList<String> validateCustomBlocks(ArrayList<String> fix) {
|
||||
ArrayList<String> out = new ArrayList<>();
|
||||
for (String entry : fix) {
|
||||
String[] split = entry.split("\\|");
|
||||
// skip if not the right size
|
||||
if (split.length < 3 || split.length > 4) continue;
|
||||
// keep going if that block exists
|
||||
// if (Registries.BLOCK.stream().anyMatch(match -> Registries.BLOCK.getId(match).toString().equals(split[0]))) {}
|
||||
// if the other entries aren't correct, skip
|
||||
if (!Num.isFloat(split[1]) || !Num.isInt(split[2])) continue;
|
||||
// add if everything is a okay
|
||||
out.add(entry);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
public static void loadVersion(Properties properties, double version) {
|
||||
try {
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
Type listType = new TypeToken<ArrayList<String>>() {}.getType();
|
||||
lang = (String) properties.computeIfAbsent("lang", a -> defaults.lang);
|
||||
//CONFIG
|
||||
keepActive = Boolean.parseBoolean((String) properties.computeIfAbsent("keep-active", a -> String.valueOf(defaults.keepActive)));
|
||||
sitWhileSeated = Boolean.parseBoolean((String) properties.computeIfAbsent("sit-while-seated", a -> String.valueOf(defaults.sitWhileSeated)));
|
||||
stairsOn = Boolean.parseBoolean((String) properties.computeIfAbsent("stairs", a -> String.valueOf(defaults.stairsOn)));
|
||||
slabsOn = Boolean.parseBoolean((String) properties.computeIfAbsent("slabs", a -> String.valueOf(defaults.slabsOn)));
|
||||
carpetsOn = Boolean.parseBoolean((String) properties.computeIfAbsent("carpets", a -> String.valueOf(defaults.carpetsOn)));
|
||||
fullBlocksOn = Boolean.parseBoolean((String) properties.computeIfAbsent("full-blocks", a -> String.valueOf(defaults.fullBlocksOn)));
|
||||
customOn = Boolean.parseBoolean((String) properties.computeIfAbsent("custom", a -> String.valueOf(defaults.customOn)));
|
||||
try {
|
||||
customBlocks = validateCustomBlocks(new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("custom-blocks", a -> gson.toJson(defaults.customBlocks)), listType));
|
||||
} catch (JsonSyntaxException ignore) {}
|
||||
|
||||
handSitting = Boolean.parseBoolean((String) properties.computeIfAbsent("hand.sitting", a -> String.valueOf(defaults.handSitting)));
|
||||
mainReq = HandRequirement.get((String) properties.computeIfAbsent("hand.main.requirement", a -> String.valueOf(defaults.mainReq)));
|
||||
mainBlock = Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.block", a -> String.valueOf(defaults.mainBlock)));
|
||||
mainFood = Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.food", a -> String.valueOf(defaults.mainFood)));
|
||||
mainUsable = Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.usable", a -> String.valueOf(defaults.mainUsable)));
|
||||
try {
|
||||
mainWhitelist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("hand.main.whitelist", a -> gson.toJson(defaults.mainWhitelist)), listType);
|
||||
} catch (JsonSyntaxException ignore) {}
|
||||
try {
|
||||
mainBlacklist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("hand.main.blacklist", a -> gson.toJson(defaults.mainBlacklist)), listType);
|
||||
} catch (JsonSyntaxException ignore) {}
|
||||
offReq = HandRequirement.get((String) properties.computeIfAbsent("hand.off.requirement", a -> String.valueOf(defaults.offReq)));
|
||||
offBlock = Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.block", a -> String.valueOf(defaults.offBlock)));
|
||||
offFood = Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.food", a -> String.valueOf(defaults.offFood)));
|
||||
offUsable = Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.usable", a -> String.valueOf(defaults.offUsable)));
|
||||
offWhitelist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("hand.off.whitelist", a -> gson.toJson(defaults.offWhitelist)), listType);
|
||||
offBlacklist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("hand.off.blacklist", a -> gson.toJson(defaults.offBlacklist)), listType);
|
||||
if (version == 1.0) {
|
||||
mainReq = HandRequirement.get((String) properties.computeIfAbsent("main-hand-requirement", a -> String.valueOf(defaults.mainReq)));
|
||||
mainBlock = Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-block", a -> String.valueOf(defaults.mainBlock)));
|
||||
mainFood = Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-food", a -> String.valueOf(defaults.mainFood)));
|
||||
mainUsable = Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-usable", a -> String.valueOf(defaults.mainUsable)));
|
||||
try {
|
||||
mainWhitelist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("main-hand-whitelist", a -> gson.toJson(defaults.mainWhitelist)), listType);
|
||||
} catch (JsonSyntaxException ignore) {}
|
||||
try {
|
||||
mainBlacklist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("main-hand-blacklist", a -> gson.toJson(defaults.mainBlacklist)), listType);
|
||||
} catch (JsonSyntaxException ignore) {}
|
||||
offReq = HandRequirement.get((String) properties.computeIfAbsent("off-hand-requirement", a -> String.valueOf(defaults.offReq)));
|
||||
offBlock = Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-block", a -> String.valueOf(defaults.offBlock)));
|
||||
offFood = Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-food", a -> String.valueOf(defaults.offFood)));
|
||||
offUsable = Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-usable", a -> String.valueOf(defaults.offUsable)));
|
||||
try {
|
||||
offWhitelist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("off-hand-whitelist", a -> gson.toJson(defaults.offWhitelist)), listType);
|
||||
} catch (JsonSyntaxException ignore) {}
|
||||
try {
|
||||
offBlacklist = new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("off-hand-blacklist", a -> gson.toJson(defaults.offBlacklist)), listType);
|
||||
} catch (JsonSyntaxException ignore) {}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.info("ERROR LOADING CONFIG - PLEASE REPORT WITH THE ERROR LOG");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String lang(String key, Object... args) {
|
||||
return LangReader.of("config.sit."+key, args).getTxT().getString();
|
||||
}
|
||||
|
||||
public static void save() {
|
||||
try (var file = Files.newBufferedWriter(configFile().toPath(), StandardCharsets.UTF_8)) {
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
file.write("# Sit! Config\n");
|
||||
file.write("\nversion="+defaults.version);
|
||||
file.write("\n# all available languages: en_us, ru_ru, es_es, zh_tw");
|
||||
file.write("\nlang=" + lang);
|
||||
file.write("\n\n# "+lang("general.keep_active.description"));
|
||||
file.write("\nkeep-active=" + keepActive);
|
||||
file.write("\n# "+lang("general.sit_while_seated.description"));
|
||||
file.write("\nsit-while-seated=" + sitWhileSeated);
|
||||
file.write("\n# "+lang("general.sittable.description"));
|
||||
file.write("\nstairs=" + stairsOn);
|
||||
file.write("\nslabs=" + slabsOn);
|
||||
file.write("\ncarpets=" + carpetsOn);
|
||||
file.write("\nfull-blocks=" + fullBlocksOn);
|
||||
file.write("\ncustom=" + customOn);
|
||||
file.write("\n# "+Sit.lang("config.sit."+
|
||||
"general.sittable_blocks.description")
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description_2",
|
||||
"\"minecraft:campfire|0.255|1|lit=false\""))
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description_4"))
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description_5"))
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description_6"))
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description_7"))
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description_8")).getString());
|
||||
file.write("\ncustom-blocks="+gson.toJson(customBlocks));
|
||||
file.write("\n\n# "+lang("hand"));
|
||||
file.write("\nhand.sitting=" + handSitting);
|
||||
file.write("\n# "+Sit.lang("config.sit."+
|
||||
"hand.requirements.description")
|
||||
.append("\n# ").append(lang("hand.requirements.description_2"))
|
||||
.append("\n# ").append(lang("hand.requirements.description_3"))
|
||||
.append("\n# ").append(lang("hand.requirements.description_4")).getString());
|
||||
file.write("\nhand.main.requirement=" + mainReq);
|
||||
file.write("\nhand.main.block=" + mainBlock);
|
||||
file.write("\nhand.main.food=" + mainFood);
|
||||
file.write("\nhand.main.usable=" + mainUsable);
|
||||
file.write("\nhand.main.whitelist="+gson.toJson(mainWhitelist));
|
||||
file.write("\nhand.main.blacklist="+gson.toJson(mainBlacklist));
|
||||
file.write("\nhand.off.requirement=" + offReq);
|
||||
file.write("\nhand.off.block=" + offBlock);
|
||||
file.write("\nhand.off.food=" + offFood);
|
||||
file.write("\nhand.off.usable=" + offUsable);
|
||||
file.write("\nhand.off.whitelist="+gson.toJson(offWhitelist));
|
||||
file.write("\nhand.off.blacklist="+gson.toJson(offBlacklist));
|
||||
// send packets to update the settings on the server
|
||||
SitClient.sendSettingsPackets();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public static class defaults {
|
||||
public static double version = 1.1;
|
||||
public static String lang = "en_us";
|
||||
public static boolean keepActive = true;
|
||||
public static boolean sitWhileSeated = true;
|
||||
public static boolean stairsOn = true;
|
||||
public static boolean slabsOn = true;
|
||||
public static boolean carpetsOn = true;
|
||||
public static boolean fullBlocksOn = false;
|
||||
public static boolean customOn = false;
|
||||
public static List<String> customBlocks = List.of("minecraft:campfire|.46|1|lit=false","minecraft:soul_campfire|.46|1|lit=false,waterlogged=false");
|
||||
public static boolean handSitting = true;
|
||||
public static HandRequirement mainReq = HandRequirement.empty;
|
||||
public static boolean mainBlock = false;
|
||||
public static boolean mainFood = false;
|
||||
public static boolean mainUsable = false;
|
||||
public static List<String> mainWhitelist = new ArrayList<>();
|
||||
public static List<String> mainBlacklist = new ArrayList<>();
|
||||
public static HandRequirement offReq = HandRequirement.restrictive;
|
||||
public static boolean offBlock = true;
|
||||
public static boolean offFood = false;
|
||||
public static boolean offUsable = true;
|
||||
public static List<String> offWhitelist = List.of("minecraft:torch","minecraft:soul_torch","minecraft:redstone_torch");
|
||||
public static List<String> offBlacklist = new ArrayList<>();
|
||||
}
|
||||
}
|
100
src/main/java/one/oth3r/sit/file/CustomBlock.java
Normal file
|
@ -0,0 +1,100 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.state.State;
|
||||
import net.minecraft.util.Identifier;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CustomBlock {
|
||||
|
||||
@SerializedName("block-ids")
|
||||
private ArrayList<String> blockIds = new ArrayList<>();
|
||||
@SerializedName("block-tags")
|
||||
private ArrayList<String> blockTags = new ArrayList<>();
|
||||
@SerializedName("blockstates")
|
||||
private ArrayList<String> blockStates = new ArrayList<>();
|
||||
|
||||
|
||||
public CustomBlock() {}
|
||||
|
||||
public CustomBlock(ArrayList<String> blockIds, ArrayList<String> blockTags, ArrayList<String> blockStates) {
|
||||
this.blockIds = blockIds;
|
||||
this.blockTags = blockTags;
|
||||
this.blockStates = blockStates;
|
||||
}
|
||||
|
||||
public ArrayList<String> getBlockIds() {
|
||||
return blockIds;
|
||||
}
|
||||
|
||||
public ArrayList<String> getBlockTags() {
|
||||
return blockTags;
|
||||
}
|
||||
|
||||
public ArrayList<String> getBlockStates() {
|
||||
return blockStates;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* checks if the blockstate matches the CustomBlock params
|
||||
* @param blockState the blockState to check
|
||||
* @return if the blockstate is allowed by the CustomBlock rules
|
||||
*/
|
||||
public boolean isValid(BlockState blockState) {
|
||||
boolean blockType = checkBlockType(blockState);
|
||||
if (!blockType) return false;
|
||||
|
||||
// now check if the state is one of the acceptable states
|
||||
for (String state : blockStates) {
|
||||
// if there is a NOT (!) blockstate
|
||||
if (state.startsWith("!")) {
|
||||
// if it is contained in the block, return false
|
||||
// remove the '!'
|
||||
String fixedState = state.substring(1);
|
||||
if (blockState.getEntries().entrySet().stream().map(State.PROPERTY_MAP_PRINTER).anyMatch(s -> s.equals(fixedState))) return false;
|
||||
}
|
||||
// else check if the blockstate matches, if not return false
|
||||
else if (blockState.getEntries().entrySet().stream().map(State.PROPERTY_MAP_PRINTER).noneMatch(s -> s.equals(state))) return false;
|
||||
}
|
||||
|
||||
// if here, all passes have passed
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if the block is the correct type or not
|
||||
* @param blockState the blockstate to check
|
||||
* @return if the type of block is matching the CustomBlock rules (e.g. if it is wood, ect.)
|
||||
*/
|
||||
private boolean checkBlockType(BlockState blockState) {
|
||||
// for all the entered blocks
|
||||
for (String id : blockIds) {
|
||||
// if there is a match for the NOT(!) blocks, return false immediately
|
||||
if (id.startsWith("!") && id.substring(1).equals(Utl.getBlockID(blockState))) return false;
|
||||
// if there is a match for the block, return true immediately
|
||||
if (id.equalsIgnoreCase(Utl.getBlockID(blockState))) return true;
|
||||
}
|
||||
|
||||
// a boolean to check if one of the blocks are in a filtered tag
|
||||
boolean tagCheck = false;
|
||||
|
||||
// for all the entered tags
|
||||
for (String tag : blockTags) {
|
||||
// substring to remove # and if needed, !
|
||||
// if there is a math for the NOT(!) tag, return false
|
||||
if (tag.startsWith("!") && blockState.isIn(TagKey.of(Registries.BLOCK.getKey(), Identifier.of(tag.substring(2))))) return false;
|
||||
// if there is a match, return true
|
||||
if (blockState.isIn(TagKey.of(Registries.BLOCK.getKey(), Identifier.tryParse(tag.substring(1))))) tagCheck = true;
|
||||
}
|
||||
|
||||
// not returning true in the loop because there might be a (!) not tag that the block might fall into, after the block was already in another tag
|
||||
return tagCheck;
|
||||
}
|
||||
}
|
90
src/main/java/one/oth3r/sit/file/CustomFile.java
Normal file
|
@ -0,0 +1,90 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public interface CustomFile <T extends CustomFile<T>> {
|
||||
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* saves the current instance to file
|
||||
*/
|
||||
default void save() {
|
||||
if (!getFile().exists()) {
|
||||
Data.LOGGER.info(String.format("Creating new `%s`", getFile().getName()));
|
||||
}
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(getFile().toPath(), StandardCharsets.UTF_8)) {
|
||||
writer.write(Utl.getGson().toJson(this));
|
||||
} catch (Exception e) {
|
||||
Data.LOGGER.error(String.format("ERROR SAVING '%s`: %s", getFile().getName(), e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the file to the current instance using updateFromReader()
|
||||
*/
|
||||
default void load() {
|
||||
File file = getFile();
|
||||
if (!file.exists()) fileNotExist();
|
||||
// try reading the file
|
||||
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
updateFromReader(reader);
|
||||
} catch (Exception e) {
|
||||
Data.LOGGER.error(String.format("ERROR LOADING '%s`: %s", file.getName(),e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
default void updateFromReader(BufferedReader reader) {
|
||||
// try to read the json
|
||||
T file;
|
||||
try {
|
||||
file = Utl.getGson().fromJson(reader, getFileClass());
|
||||
} catch (Exception e) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
// throw null if the fileData is null or version is null
|
||||
if (file == null) throw new NullPointerException();
|
||||
|
||||
// update the instance
|
||||
updateToNewFile(file);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Class<T> getFileClass();
|
||||
|
||||
void updateToNewFile(T newFile);
|
||||
|
||||
/**
|
||||
* logic for the file not existing when loading, defaults to saving
|
||||
*/
|
||||
default void fileNotExist() {
|
||||
// try to make the config directory
|
||||
try {
|
||||
Files.createDirectories(Paths.get(getDirectory()));
|
||||
} catch (Exception e) {
|
||||
Data.LOGGER.error("Failed to create config directory. Canceling all config loading...");
|
||||
return;
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
String getFileName();
|
||||
|
||||
default String getDirectory() {
|
||||
return FabricLoader.getInstance().getConfigDir().toFile()+"/";
|
||||
}
|
||||
|
||||
default File getFile() {
|
||||
return new File(getDirectory()+getFileName());
|
||||
}
|
||||
}
|
65
src/main/java/one/oth3r/sit/file/CustomItem.java
Normal file
|
@ -0,0 +1,65 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CustomItem {
|
||||
@SerializedName("item-ids")
|
||||
private ArrayList<String> itemIDs = new ArrayList<>();
|
||||
@SerializedName("item-tags")
|
||||
private ArrayList<String> itemTags = new ArrayList<>();
|
||||
|
||||
public CustomItem() {}
|
||||
|
||||
public CustomItem(ArrayList<String> itemIDs, ArrayList<String> itemTags) {
|
||||
this.itemIDs = itemIDs;
|
||||
this.itemTags = itemTags;
|
||||
}
|
||||
|
||||
public ArrayList<String> getItemIDs() {
|
||||
return itemIDs;
|
||||
}
|
||||
|
||||
public ArrayList<String> getItemTags() {
|
||||
return itemTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if the block is the correct type or not
|
||||
* @param itemStack the blockstate to check
|
||||
* @return if the type of block is matching the CustomBlock rules (e.g. if it is wood, ect.)
|
||||
*/
|
||||
public boolean checkItem(ItemStack itemStack) {
|
||||
String itemId = Registries.ITEM.getId(itemStack.getItem()).toString();
|
||||
// check the custom item ids
|
||||
for (String id : itemIDs) {
|
||||
// if there is a match for the NOT(!) item, its filtered, false
|
||||
if (id.startsWith("!") && id.substring(1).equalsIgnoreCase(itemId)) return false;
|
||||
// if there is a match for the item, return true immediately
|
||||
if (id.equalsIgnoreCase(itemId)) return true;
|
||||
}
|
||||
|
||||
// a boolean to check if one of the items are in a filtered tag
|
||||
boolean tagCheck = false;
|
||||
|
||||
// check the custom item tags
|
||||
for (String tag : itemTags) {
|
||||
// substring to remove # and if needed, "!"
|
||||
// if a NOT tag
|
||||
if (tag.startsWith("!")) {
|
||||
// if there is a math for the NOT(!) tag, return false
|
||||
if (itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), Identifier.of(tag.substring(2))))) return false;
|
||||
}
|
||||
// else (normal tag), if there is a match, set tagCheck to true
|
||||
else if (itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), Identifier.of(tag.substring(1))))) tagCheck = true;
|
||||
}
|
||||
|
||||
// not returning true in the loop because there might be a (!) not tag that the item might fall into, after the item was already in another tag
|
||||
return tagCheck;
|
||||
}
|
||||
}
|
96
src/main/java/one/oth3r/sit/file/FileData.java
Normal file
|
@ -0,0 +1,96 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class FileData {
|
||||
/**
|
||||
* Sit! config file
|
||||
*/
|
||||
private static ServerConfig serverConfig = new ServerConfig();
|
||||
|
||||
public static ServerConfig getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
public static void setServerConfig(ServerConfig newServerConfig) {
|
||||
serverConfig = new ServerConfig(newServerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default sitting config for all new players
|
||||
*/
|
||||
private static SittingConfig sittingConfig = new SittingConfig();
|
||||
|
||||
public static SittingConfig getSittingConfig() {
|
||||
return sittingConfig;
|
||||
}
|
||||
|
||||
public static void setSittingConfig(SittingConfig newSittingConfig) {
|
||||
sittingConfig = new SittingConfig(newSittingConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* the sitting config stored per player on the server
|
||||
*/
|
||||
private static final HashMap<ServerPlayerEntity, SittingConfig> playerSettings = new HashMap<>();
|
||||
|
||||
public static void clearPlayerSettings() {
|
||||
playerSettings.clear();
|
||||
}
|
||||
|
||||
public static void setPlayerSetting(ServerPlayerEntity player, SittingConfig config) {
|
||||
playerSettings.put(player, config);
|
||||
}
|
||||
|
||||
public static void removePlayerSetting(ServerPlayerEntity player) {
|
||||
playerSettings.remove(player);
|
||||
}
|
||||
|
||||
public static SittingConfig getPlayerSetting(ServerPlayerEntity player) {
|
||||
return playerSettings.getOrDefault(player, sittingConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* loads all config files to memory
|
||||
*/
|
||||
public static void loadFiles() {
|
||||
getServerConfig().load();
|
||||
|
||||
getSittingConfig().load();
|
||||
// if loading file and is on supported server on client, send the new settings over
|
||||
if (Data.isClient() && Data.isSupportedServer()) {
|
||||
Utl.sendSettingsPackets();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Defaults {
|
||||
public static final ArrayList<SittingBlock> SITTING_BLOCKS = new ArrayList<>(Arrays.asList(
|
||||
new SittingBlock(new ArrayList<>(),new ArrayList<>(Arrays.asList("#minecraft:campfires")), new ArrayList<>(Arrays.asList("lit=false")),.437),
|
||||
new SittingBlock(new ArrayList<>(Arrays.asList("!minecraft:crimson_stem","!minecraft:warped_stem","minecraft:polished_basalt")), new ArrayList<>(Arrays.asList("#minecraft:logs","!#minecraft:oak_logs")), new ArrayList<>(Arrays.asList("!axis=y")),1.0),
|
||||
new SittingBlock(new ArrayList<>(Arrays.asList()), new ArrayList<>(Arrays.asList("#minecraft:beds")), new ArrayList<>(Arrays.asList("part=foot","occupied=false")),.5625)
|
||||
));
|
||||
|
||||
public static final ArrayList<CustomBlock> BLACKLISTED_BLOCKS = new ArrayList<>(Arrays.asList(
|
||||
new CustomBlock(new ArrayList<>(),new ArrayList<>(Arrays.asList("#minecraft:shulker_boxes")),new ArrayList<>())
|
||||
));
|
||||
|
||||
public static final HandSetting MAIN_HAND = new HandSetting(HandSetting.SittingRequirement.EMPTY, new HandSetting.Filter(
|
||||
false,new HandSetting.Filter.Presets(),
|
||||
new CustomItem(
|
||||
new ArrayList<>(),
|
||||
new ArrayList<>(Arrays.asList("#minecraft:bookshelf_books","!#minecraft:lectern_books")))));
|
||||
|
||||
public static final HandSetting OFF_HAND = new HandSetting(HandSetting.SittingRequirement.FILTER, new HandSetting.Filter(
|
||||
false, new HandSetting.Filter.Presets(false, true, false),
|
||||
new CustomItem(new ArrayList<>(Arrays.asList("minecraft:filled_map",
|
||||
"minecraft:torch", "minecraft:soul_torch","minecraft:redstone_torch",
|
||||
"minecraft:lantern", "minecraft:soul_lantern")),
|
||||
new ArrayList<>())));
|
||||
}
|
||||
}
|
96
src/main/java/one/oth3r/sit/file/HandSetting.java
Normal file
|
@ -0,0 +1,96 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HandSetting {
|
||||
|
||||
@SerializedName("requirement")
|
||||
private SittingRequirement sittingRequirement = SittingRequirement.NONE;
|
||||
@SerializedName("requirement-options") @SuppressWarnings("unused")
|
||||
private final String sittingRequirementOptions = Arrays.stream(SittingRequirement.values()).map(Enum::toString).collect(Collectors.joining(", "));
|
||||
@SerializedName("filter")
|
||||
private Filter filter = new Filter();
|
||||
|
||||
public HandSetting() {}
|
||||
|
||||
public HandSetting(SittingRequirement sittingRequirement, Filter filter) {
|
||||
this.sittingRequirement = sittingRequirement;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public SittingRequirement getSittingRequirement() {
|
||||
return sittingRequirement;
|
||||
}
|
||||
|
||||
public Filter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public enum SittingRequirement {
|
||||
NONE,
|
||||
FILTER,
|
||||
EMPTY
|
||||
}
|
||||
|
||||
public static class Filter {
|
||||
|
||||
@SerializedName("invert-filter")
|
||||
private Boolean invert = false;
|
||||
@SerializedName("presets")
|
||||
private Presets presets = new Presets();
|
||||
@SerializedName("custom-items")
|
||||
private CustomItem customItems = new CustomItem();
|
||||
|
||||
public Filter() {}
|
||||
|
||||
public Filter(boolean invert, Presets presets, CustomItem customItems) {
|
||||
this.invert = invert;
|
||||
this.presets = presets;
|
||||
this.customItems = customItems;
|
||||
}
|
||||
|
||||
public Boolean isInverted() {
|
||||
return invert;
|
||||
}
|
||||
|
||||
public Presets getPresets() {
|
||||
return presets;
|
||||
}
|
||||
|
||||
public CustomItem getCustomItems() {
|
||||
return customItems;
|
||||
}
|
||||
|
||||
public static class Presets {
|
||||
@SerializedName("block")
|
||||
private boolean block = false;
|
||||
@SerializedName("food")
|
||||
private boolean food = false;
|
||||
@SerializedName("usable")
|
||||
private boolean usable = false;
|
||||
|
||||
public Presets() {}
|
||||
|
||||
public Presets(boolean block, boolean food, boolean usable) {
|
||||
this.block = block;
|
||||
this.food = food;
|
||||
this.usable = usable;
|
||||
}
|
||||
|
||||
public boolean isBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public boolean isFood() {
|
||||
return food;
|
||||
}
|
||||
|
||||
public boolean isUsable() {
|
||||
return usable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
package one.oth3r.sit;
|
||||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import one.oth3r.sit.file.Config;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -75,20 +76,30 @@ public class LangReader {
|
|||
public static LangReader of(String translationKey, Object... placeholders) {
|
||||
return new LangReader(translationKey, placeholders);
|
||||
}
|
||||
|
||||
public static void loadLanguageFile() {
|
||||
ClassLoader classLoader = Sit.class.getClassLoader();
|
||||
try {
|
||||
ClassLoader classLoader = Sit.class.getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream("assets/sit/lang/"+ Config.lang+".json");
|
||||
InputStream inputStream = classLoader.getResourceAsStream("assets/sit-oth3r/lang/" + FileData.getServerConfig().getLang() +".json");
|
||||
|
||||
// if the input stream is null, the language file wasn't found
|
||||
if (inputStream == null) {
|
||||
inputStream = classLoader.getResourceAsStream("assets/sit/lang/"+ Config.defaults.lang+".json");
|
||||
Config.lang = Config.defaults.lang;
|
||||
// try loading the default language file
|
||||
inputStream = classLoader.getResourceAsStream("assets/sit-oth3r/lang/" + new ServerConfig().getLang() +".json");
|
||||
Data.LOGGER.error("COULDN'T LOAD THE LANGUAGE FILE. RESETTING TO en_us.");
|
||||
}
|
||||
if (inputStream == null) throw new IllegalArgumentException("CANT LOAD THE LANGUAGE FILE. DIRECTIONHUD WILL BREAK.");
|
||||
|
||||
// if the input stream is still null, throw an exception
|
||||
if (inputStream == null) throw new IllegalArgumentException("UNABLE TO LOAD THE ENGLISH LANGUAGE FILE.");
|
||||
|
||||
Type type = new TypeToken<Map<String, String>>(){}.getType();
|
||||
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
|
||||
languageMap.putAll(new Gson().fromJson(reader, type));
|
||||
|
||||
// close the input stream
|
||||
inputStream.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Data.LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
public static String getLanguageValue(String key) {
|
373
src/main/java/one/oth3r/sit/file/ServerConfig.java
Normal file
|
@ -0,0 +1,373 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.minecraft.util.Hand;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ServerConfig implements CustomFile<ServerConfig> {
|
||||
|
||||
@SerializedName("version")
|
||||
private Double version = 2.0;
|
||||
@SerializedName("lang")
|
||||
private String lang = "en_us";
|
||||
@SerializedName("lang-options")
|
||||
private final String langOptions = "en_us, it_it, pt_br, tr_tr, zh_tw";
|
||||
@SerializedName("keep-active")
|
||||
private Boolean keepActive = true;
|
||||
@SerializedName("sit-while-seated")
|
||||
private Boolean sitWhileSeated = false;
|
||||
@SerializedName("preset-blocks")
|
||||
private PresetBlocks presetBlocks = new PresetBlocks();
|
||||
@SerializedName("custom-enabled")
|
||||
private Boolean customEnabled = false;
|
||||
@SerializedName("custom-blocks")
|
||||
private ArrayList<SittingBlock> sittingBlocks = FileData.Defaults.SITTING_BLOCKS;
|
||||
@SerializedName("blacklisted-blocks")
|
||||
private ArrayList<CustomBlock> blacklistedBlocks = FileData.Defaults.BLACKLISTED_BLOCKS;
|
||||
|
||||
public ServerConfig() {}
|
||||
|
||||
public ServerConfig(ServerConfig serverConfig) {
|
||||
this.version = serverConfig.version;
|
||||
this.lang = serverConfig.lang;
|
||||
this.keepActive = serverConfig.keepActive;
|
||||
this.sitWhileSeated = serverConfig.sitWhileSeated;
|
||||
this.presetBlocks = serverConfig.presetBlocks;
|
||||
this.customEnabled = serverConfig.customEnabled;
|
||||
this.sittingBlocks = serverConfig.sittingBlocks;
|
||||
this.blacklistedBlocks = serverConfig.blacklistedBlocks;
|
||||
}
|
||||
|
||||
public ServerConfig(Double version, String lang, boolean keepActive, boolean sitWhileSeated,
|
||||
PresetBlocks presetBlocks, boolean customEnabled,
|
||||
ArrayList<SittingBlock> sittingBlocks, ArrayList<CustomBlock> blacklistedBlocks) {
|
||||
this.version = version;
|
||||
this.lang = lang;
|
||||
this.keepActive = keepActive;
|
||||
this.sitWhileSeated = sitWhileSeated;
|
||||
this.presetBlocks = presetBlocks;
|
||||
this.customEnabled = customEnabled;
|
||||
this.sittingBlocks = sittingBlocks;
|
||||
this.blacklistedBlocks = blacklistedBlocks;
|
||||
}
|
||||
|
||||
public Double getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getLang() {
|
||||
return lang;
|
||||
}
|
||||
|
||||
public boolean isKeepActive() {
|
||||
return keepActive;
|
||||
}
|
||||
|
||||
public boolean canSitWhileSeated() {
|
||||
return sitWhileSeated;
|
||||
}
|
||||
|
||||
public PresetBlocks getPresetBlocks() {
|
||||
return presetBlocks;
|
||||
}
|
||||
|
||||
public Boolean isCustomEnabled() {
|
||||
return customEnabled;
|
||||
}
|
||||
|
||||
public ArrayList<SittingBlock> getSittingBlocks() {
|
||||
return sittingBlocks;
|
||||
}
|
||||
|
||||
public ArrayList<CustomBlock> getBlacklistedBlocks() {
|
||||
return blacklistedBlocks;
|
||||
}
|
||||
|
||||
public static class PresetBlocks {
|
||||
|
||||
@SerializedName("stairs")
|
||||
private boolean stairs = true;
|
||||
@SerializedName("slabs")
|
||||
private boolean slabs = true;
|
||||
@SerializedName("carpets")
|
||||
private boolean carpets = true;
|
||||
@SerializedName("full-blocks")
|
||||
private boolean fullBlocks = false;
|
||||
|
||||
public PresetBlocks() {}
|
||||
|
||||
public PresetBlocks(boolean stairs, boolean slabs, boolean carpets, boolean fullBlocks) {
|
||||
this.stairs = stairs;
|
||||
this.slabs = slabs;
|
||||
this.carpets = carpets;
|
||||
this.fullBlocks = fullBlocks;
|
||||
}
|
||||
|
||||
public boolean isStairs() {
|
||||
return stairs;
|
||||
}
|
||||
|
||||
public boolean isSlabs() {
|
||||
return slabs;
|
||||
}
|
||||
|
||||
public boolean isCarpets() {
|
||||
return carpets;
|
||||
}
|
||||
|
||||
public boolean isFullBlocks() {
|
||||
return fullBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
updateToNewFile(new ServerConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Class<ServerConfig> getFileClass() {
|
||||
return ServerConfig.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateToNewFile(ServerConfig newFile) {
|
||||
this.version = newFile.version;
|
||||
this.lang = newFile.lang;
|
||||
this.keepActive = newFile.keepActive;
|
||||
this.sitWhileSeated = newFile.sitWhileSeated;
|
||||
this.presetBlocks = newFile.presetBlocks;
|
||||
this.customEnabled = newFile.customEnabled;
|
||||
this.sittingBlocks = newFile.sittingBlocks;
|
||||
this.blacklistedBlocks = newFile.blacklistedBlocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return "server-config.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDirectory() {
|
||||
return Data.CONFIG_DIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileNotExist() {
|
||||
CustomFile.super.fileNotExist();
|
||||
// try checking the old/legacy config directory for the file
|
||||
if (Legacy.getLegacyFile().exists()) {
|
||||
Data.LOGGER.info("Updating Sit!.properties to sit!/config.json");
|
||||
Legacy.run();
|
||||
}
|
||||
}
|
||||
|
||||
protected static class Legacy {
|
||||
/**
|
||||
* gets the legacy file, from the old directory for fabric, and the same one for spigot
|
||||
*/
|
||||
public static File getLegacyFile() {
|
||||
// strip the new directory
|
||||
return new File(Data.CONFIG_DIR.substring(0, Data.CONFIG_DIR.length()-5)+"Sit!.properties");
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the old Sit!.properties to config.json
|
||||
*/
|
||||
public static void run() {
|
||||
// shouldn't happen, only call if the file exists
|
||||
File file = getLegacyFile();
|
||||
if (!file.exists()) return;
|
||||
|
||||
// update to the new system
|
||||
try (FileInputStream fileStream = new FileInputStream(file)) {
|
||||
Properties properties = new Properties();
|
||||
properties.load(fileStream);
|
||||
String ver = (String) properties.computeIfAbsent("version", a -> String.valueOf(new ServerConfig().getVersion()));
|
||||
|
||||
// if the old version system (v1.0) remove "v"
|
||||
if (ver.contains("v")) ver = ver.substring(1);
|
||||
|
||||
loadVersion(properties,Double.parseDouble(ver));
|
||||
|
||||
} catch (Exception e) {
|
||||
Data.LOGGER.error("Error loading legacy config file: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// delete the old file
|
||||
try {
|
||||
Files.delete(file.toPath());
|
||||
Data.LOGGER.info("Deleted " + file.getName());
|
||||
} catch (Exception e) {
|
||||
Data.LOGGER.error("Failed to delete the old Sit! config.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* converts the legacy hand requirement enum to the new one
|
||||
* @param requirement the old string
|
||||
*/
|
||||
private static HandSetting.SittingRequirement handRequirementUpdater(String requirement) {
|
||||
return switch (requirement) {
|
||||
case "restrictive" -> HandSetting.SittingRequirement.FILTER;
|
||||
case "none" -> HandSetting.SittingRequirement.NONE;
|
||||
default -> HandSetting.SittingRequirement.EMPTY;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a list of custom blocks from the legacy way of entering custom sit blocks
|
||||
*/
|
||||
private static ArrayList<SittingBlock> getCustomBlocks(ArrayList<String> fix) {
|
||||
//eg. minecraft:campfire|.46|1|lit=false
|
||||
ArrayList<SittingBlock> out = new ArrayList<>();
|
||||
for (String entry : fix) {
|
||||
String[] split = entry.split("\\|");
|
||||
// skip if not the right size
|
||||
if (split.length < 3 || split.length > 4) continue;
|
||||
// if the other entries aren't correct, skip
|
||||
if (!Utl.Num.isNum(split[2])) continue;
|
||||
|
||||
// make the block states list if possible
|
||||
ArrayList<String> blockstates = new ArrayList<>();
|
||||
// if there are blockstates
|
||||
if (split.length == 4) {
|
||||
blockstates.addAll(Arrays.asList(split[3].split(",")));
|
||||
}
|
||||
|
||||
// add if everything is A-OK
|
||||
out.add(new SittingBlock(
|
||||
new ArrayList<>(Arrays.asList(split[0])),
|
||||
new ArrayList<>(),blockstates,Double.parseDouble(split[1])));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private static ArrayList<String> getFilterList(ArrayList<String> whitelist, ArrayList<String> blacklist) {
|
||||
ArrayList<String> out = new ArrayList<>(whitelist);
|
||||
// add a ! in front of every entry of the blacklist
|
||||
out.addAll(blacklist.stream().map(e -> "!"+e).toList());
|
||||
return out;
|
||||
}
|
||||
|
||||
public static void loadVersion(Properties properties, double version) {
|
||||
try {
|
||||
Type listType = new TypeToken<ArrayList<String>>() {}.getType();
|
||||
ServerConfig defaultConfig = new ServerConfig();
|
||||
|
||||
// load the latest config
|
||||
ServerConfig serverConfig = new ServerConfig(
|
||||
2.0,
|
||||
(String) properties.computeIfAbsent("lang", a -> defaultConfig.getLang()),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("keep-active", a -> String.valueOf(defaultConfig.isKeepActive()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("sit-while-seated", a -> String.valueOf(defaultConfig.canSitWhileSeated()))),
|
||||
new PresetBlocks(
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("stairs", a -> String.valueOf(defaultConfig.getPresetBlocks().isStairs()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("slabs", a -> String.valueOf(defaultConfig.getPresetBlocks().isSlabs()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("carpets", a -> String.valueOf(defaultConfig.getPresetBlocks().isCarpets()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("full-blocks", a -> String.valueOf(defaultConfig.getPresetBlocks().isFullBlocks())))
|
||||
),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("custom", a -> String.valueOf(defaultConfig.isCustomEnabled()))),
|
||||
getCustomBlocks(new Gson().fromJson((String)
|
||||
properties.computeIfAbsent("custom-blocks", a -> "[]"), listType)),
|
||||
new ArrayList<>()
|
||||
);
|
||||
|
||||
SittingConfig defaultSittingConfig = new SittingConfig();
|
||||
|
||||
SittingConfig sittingConfig = new SittingConfig();
|
||||
// * filters are flipped because the way they work are flipped
|
||||
try {
|
||||
sittingConfig = new SittingConfig(
|
||||
1.0, true, Boolean.parseBoolean((String) properties.computeIfAbsent("hand.sitting", a -> String.valueOf(defaultSittingConfig.canSitWithHand()))),
|
||||
new HandSetting(
|
||||
handRequirementUpdater((String) properties.computeIfAbsent("hand.main.requirement", a -> String.valueOf(defaultSittingConfig.getHand(Hand.MAIN_HAND).getSittingRequirement()))),
|
||||
new HandSetting.Filter(false,
|
||||
new HandSetting.Filter.Presets(
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.block", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.MAIN_HAND).getFilter().getPresets().isBlock()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.food", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.MAIN_HAND).getFilter().getPresets().isFood()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.usable", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.MAIN_HAND).getFilter().getPresets().isUsable())))),
|
||||
new CustomItem(getFilterList(
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("hand.main.whitelist", a -> "[]"), listType),
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("hand.main.blacklist", a -> "[]"), listType)
|
||||
),
|
||||
new ArrayList<>())
|
||||
)
|
||||
),
|
||||
new HandSetting(
|
||||
handRequirementUpdater((String) properties.computeIfAbsent("hand.off.requirement", a -> String.valueOf(defaultSittingConfig.getHand(Hand.OFF_HAND).getSittingRequirement()))),
|
||||
new HandSetting.Filter(false,
|
||||
new HandSetting.Filter.Presets(
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.block", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.OFF_HAND).getFilter().getPresets().isBlock()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.food", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.OFF_HAND).getFilter().getPresets().isFood()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.usable", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.OFF_HAND).getFilter().getPresets().isUsable())))),
|
||||
new CustomItem(getFilterList(
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("hand.off.whitelist", a -> "[]"), listType),
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("hand.off.blacklist", a -> "[]"), listType)
|
||||
),
|
||||
new ArrayList<>())
|
||||
)
|
||||
)
|
||||
);
|
||||
} catch (JsonSyntaxException ignored) {}
|
||||
|
||||
// load an older version
|
||||
if (version == 1.0) {
|
||||
try {
|
||||
sittingConfig = new SittingConfig(
|
||||
1.0, true, defaultSittingConfig.canSitWithHand(),
|
||||
new HandSetting(
|
||||
handRequirementUpdater((String) properties.computeIfAbsent("main-hand-requirement", a -> String.valueOf(defaultSittingConfig.getHand(Hand.MAIN_HAND).getSittingRequirement()))),
|
||||
new HandSetting.Filter(false,
|
||||
new HandSetting.Filter.Presets(
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-block", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.MAIN_HAND).getFilter().getPresets().isBlock()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-food", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.MAIN_HAND).getFilter().getPresets().isFood()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-usable", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.MAIN_HAND).getFilter().getPresets().isUsable())))),
|
||||
new CustomItem(getFilterList(
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("main-hand-whitelist", a -> "[]"), listType),
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("main-hand-blacklist", a -> "[]"), listType)
|
||||
),
|
||||
new ArrayList<>())
|
||||
)
|
||||
),
|
||||
new HandSetting(
|
||||
handRequirementUpdater((String) properties.computeIfAbsent("off-hand-requirement", a -> String.valueOf(defaultSittingConfig.getHand(Hand.OFF_HAND).getSittingRequirement()))),
|
||||
new HandSetting.Filter(false,
|
||||
new HandSetting.Filter.Presets(
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-block", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.OFF_HAND).getFilter().getPresets().isBlock()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-food", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.OFF_HAND).getFilter().getPresets().isFood()))),
|
||||
!Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-usable", a -> String.valueOf(!defaultSittingConfig.getHand(Hand.OFF_HAND).getFilter().getPresets().isUsable())))),
|
||||
new CustomItem(getFilterList(
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("off-hand-whitelist", a -> "[]"), listType),
|
||||
new Gson().fromJson((String) properties.computeIfAbsent("off-hand-blacklist", a -> "[]"), listType)
|
||||
),
|
||||
new ArrayList<>())
|
||||
)
|
||||
)
|
||||
);
|
||||
} catch (JsonSyntaxException ignored) {}
|
||||
}
|
||||
|
||||
FileData.setServerConfig(serverConfig);
|
||||
FileData.setSittingConfig(sittingConfig);
|
||||
serverConfig.save();
|
||||
sittingConfig.save();
|
||||
} catch (Exception e) {
|
||||
Data.LOGGER.error("Error loading legacy config: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
src/main/java/one/oth3r/sit/file/SittingBlock.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SittingBlock extends CustomBlock {
|
||||
@SerializedName("sitting-height")
|
||||
private Double sittingHeight = 0.5;
|
||||
|
||||
/**
|
||||
* gets the sitting height of a block, limiting the size from 0 - 1
|
||||
* @return the sitting height, clamped
|
||||
*/
|
||||
public Double getSittingHeight() {
|
||||
return Math.max(0f, Math.min(1f, sittingHeight));
|
||||
}
|
||||
|
||||
public SittingBlock() {}
|
||||
|
||||
public SittingBlock(ArrayList<String> blockIds, ArrayList<String> blockTags, ArrayList<String> blockStates, Double sittingHeight) {
|
||||
super(blockIds, blockTags, blockStates);
|
||||
this.sittingHeight = sittingHeight;
|
||||
}
|
||||
}
|
103
src/main/java/one/oth3r/sit/file/SittingConfig.java
Normal file
|
@ -0,0 +1,103 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import net.minecraft.util.Hand;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SittingConfig implements CustomFile<SittingConfig> {
|
||||
|
||||
@SerializedName("version")
|
||||
private Double version = 1.0;
|
||||
@SerializedName("enabled")
|
||||
private Boolean enabled = true;
|
||||
@SerializedName("hand-sitting")
|
||||
private Boolean handSitting = true;
|
||||
@SerializedName("main-hand")
|
||||
private HandSetting mainHand = FileData.Defaults.MAIN_HAND;
|
||||
@SerializedName("off-hand")
|
||||
private HandSetting offHand = FileData.Defaults.OFF_HAND;
|
||||
|
||||
public SittingConfig() {}
|
||||
|
||||
public SittingConfig(double version, boolean enabled, boolean handSitting, HandSetting mainHand, HandSetting offHand) {
|
||||
this.version = version;
|
||||
this.enabled = enabled;
|
||||
this.handSitting = handSitting;
|
||||
this.mainHand = mainHand;
|
||||
this.offHand = offHand;
|
||||
}
|
||||
|
||||
public SittingConfig(SittingConfig sittingConfig) {
|
||||
updateToNewFile(sittingConfig);
|
||||
}
|
||||
|
||||
public Double getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean canSitWithHand() {
|
||||
return handSitting;
|
||||
}
|
||||
|
||||
public void setHandSitting(Boolean handSitting) {
|
||||
this.handSitting = handSitting;
|
||||
}
|
||||
|
||||
public HandSetting getHand(Hand handType) {
|
||||
return handType.equals(Hand.MAIN_HAND) ? mainHand : offHand;
|
||||
}
|
||||
|
||||
public HandSetting getMainHand() {
|
||||
return mainHand;
|
||||
}
|
||||
|
||||
public HandSetting getOffHand() {
|
||||
return offHand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
updateToNewFile(new SittingConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Class<SittingConfig> getFileClass() {
|
||||
return SittingConfig.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateToNewFile(SittingConfig newFile) {
|
||||
this.version = newFile.version;
|
||||
this.enabled = newFile.enabled;
|
||||
this.handSitting = newFile.handSitting;
|
||||
this.mainHand = newFile.mainHand;
|
||||
this.offHand = newFile.offHand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName() {
|
||||
return "sitting-config.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDirectory() {
|
||||
return Data.CONFIG_DIR;
|
||||
}
|
||||
}
|
34
src/main/java/one/oth3r/sit/mixin/ReloadCommandMixin.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
package one.oth3r.sit.mixin;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.ReloadCommand;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Formatting;
|
||||
import one.oth3r.sit.file.FileData;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
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;
|
||||
|
||||
@Mixin(ReloadCommand.class)
|
||||
public class ReloadCommandMixin {
|
||||
@Inject(at = @At("TAIL"), method = "register")
|
||||
private static void register(CommandDispatcher<ServerCommandSource> dispatcher, CallbackInfo ci) {
|
||||
FileData.loadFiles();
|
||||
|
||||
// make sure the server isn't null
|
||||
MinecraftServer server = Data.getServer();
|
||||
if (server == null || server.getPlayerManager() == null) return;
|
||||
|
||||
// send a reloaded message to all players with permissions
|
||||
for (ServerPlayerEntity player : server.getPlayerManager().getPlayerList()) {
|
||||
if (player.isCreativeLevelTwoOp()) {
|
||||
player.sendMessage(Utl.messageTag().append(Utl.lang("sit!.chat.reloaded").formatted(Formatting.GREEN)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package one.oth3r.sit.mixin;
|
||||
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.util.math.*;
|
||||
import net.minecraft.world.World;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@Mixin(DisplayEntity.TextDisplayEntity.class)
|
||||
public abstract class TextDisplayDismountMixin extends DisplayEntity {
|
||||
public TextDisplayDismountMixin(EntityType<?> entityType, World world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d updatePassengerForDismount(LivingEntity passenger) {
|
||||
// get the passenger's horizontal rotation, rotated counterclockwise, because the method rotates it clockwise for some reason
|
||||
int[][] offset = Dismounting.getDismountOffsets(passenger.getHorizontalFacing().rotateYCounterclockwise());
|
||||
// new array with another slot
|
||||
int[][] dismountOffsets = new int[offset.length + 1][];
|
||||
// add an empty offset to the start of the array
|
||||
dismountOffsets[0] = new int[]{0, 0};
|
||||
// copy the original elements into the new array starting from index 1
|
||||
System.arraycopy(offset, 0, dismountOffsets, 1, offset.length);
|
||||
|
||||
BlockPos blockPos = this.getBlockPos();
|
||||
|
||||
for (EntityPose entityPose : passenger.getPoses()) {
|
||||
Vec3d vec3d = getDismountPos(passenger, entityPose, dismountOffsets, blockPos);
|
||||
|
||||
// check around the block above
|
||||
if (vec3d == null) vec3d = getDismountPos(passenger, entityPose, dismountOffsets, blockPos.up());
|
||||
|
||||
if (vec3d != null) return vec3d;
|
||||
|
||||
}
|
||||
|
||||
return super.updatePassengerForDismount(passenger);
|
||||
}
|
||||
|
||||
/**
|
||||
* searches around the BlockPos for a stable dismount spot using the dismountOffsets
|
||||
* @param passenger the passenger to check
|
||||
* @param entityPose the pose of the passenger to check
|
||||
* @param dismountOffsets the positions to check around the BlockPos
|
||||
* @param blockPos the BlockPos to check around
|
||||
* @return the Vec3d to dismount at, null if not found
|
||||
*/
|
||||
@Unique
|
||||
private @Nullable Vec3d getDismountPos(LivingEntity passenger, EntityPose entityPose, int[][] dismountOffsets, BlockPos blockPos) {
|
||||
// iterate through all dismount offsets
|
||||
for (int[] offset : dismountOffsets) {
|
||||
BlockPos.Mutable mutable = new BlockPos.Mutable();
|
||||
mutable.set(blockPos.getX() + offset[0], blockPos.getY(), blockPos.getZ() + offset[1]);
|
||||
|
||||
double dismountHeight = this.getWorld().getDismountHeight(mutable);
|
||||
if (Dismounting.canDismountInBlock(dismountHeight)) {
|
||||
Vec3d vec3d = Vec3d.ofCenter(mutable, dismountHeight);
|
||||
|
||||
Box boundingBox = passenger.getBoundingBox(entityPose);
|
||||
if (Dismounting.canPlaceEntityAt(this.getWorld(), passenger, boundingBox.offset(vec3d))) {
|
||||
passenger.setPose(entityPose);
|
||||
return vec3d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package one.oth3r.sit.packet;
|
||||
|
||||
import net.minecraft.network.RegistryByteBuf;
|
||||
import net.minecraft.network.codec.PacketCodec;
|
||||
import net.minecraft.network.codec.PacketCodecs;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
import net.minecraft.util.Identifier;
|
||||
import one.oth3r.sit.Sit;
|
||||
|
||||
public class CustomPayloads {
|
||||
public record SettingsPayload(String value) implements CustomPayload {
|
||||
|
||||
public static final Id<SettingsPayload> ID = new Id<>(Identifier.of(Sit.MOD_ID,"settings_v1.1"));
|
||||
|
||||
public static final PacketCodec<RegistryByteBuf, SettingsPayload> CODEC = PacketCodecs.STRING.xmap(SettingsPayload::new, SettingsPayload::value).cast();
|
||||
|
||||
@Override
|
||||
public Id<SettingsPayload> getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
43
src/main/java/one/oth3r/sit/packet/SitPayloads.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
package one.oth3r.sit.packet;
|
||||
|
||||
import net.minecraft.network.RegistryByteBuf;
|
||||
import net.minecraft.network.codec.PacketCodec;
|
||||
import net.minecraft.network.codec.PacketCodecs;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
import net.minecraft.util.Identifier;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
|
||||
public class SitPayloads {
|
||||
/**
|
||||
* the packet that the client sends to the server
|
||||
* @param value the sitting settings for the client
|
||||
*/
|
||||
public record SettingsPayload(String value) implements CustomPayload {
|
||||
|
||||
public static final Id<SettingsPayload> ID = new Id<>(Identifier.of(Data.MOD_ID,"settings_v2.0"));
|
||||
|
||||
public static final PacketCodec<RegistryByteBuf, SettingsPayload> CODEC = PacketCodecs.STRING.xmap(SettingsPayload::new, SettingsPayload::value).cast();
|
||||
|
||||
@Override
|
||||
public Id<SettingsPayload> getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* the packet that the server sends to the client when responding to the settings payload
|
||||
*/
|
||||
public record ResponsePayload(String value) implements CustomPayload {
|
||||
|
||||
public static final String VERSION = "response_v1.0";
|
||||
|
||||
public static final Id<ResponsePayload> ID = new Id<>(Identifier.of(Data.MOD_ID,VERSION));
|
||||
|
||||
public static final PacketCodec<RegistryByteBuf, ResponsePayload> CODEC = PacketCodecs.STRING.xmap(ResponsePayload::new, ResponsePayload::value).cast();
|
||||
|
||||
@Override
|
||||
public Id<ResponsePayload> getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
}
|
30
src/main/java/one/oth3r/sit/screen/ClickableImageWidget.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package one.oth3r.sit.screen;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.tooltip.Tooltip;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ClickableImageWidget extends ButtonWidget {
|
||||
private final Identifier image;
|
||||
|
||||
public ClickableImageWidget(int x, int y, int width, int height, Tooltip tooltip, Identifier image, ButtonWidget.PressAction onPress) {
|
||||
super(x, y, width, height, Text.empty(), onPress, Supplier::get);
|
||||
this.image = image;
|
||||
this.setTooltip(tooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.enableDepthTest();
|
||||
context.drawTexture(RenderLayer::getGuiTextured, image,
|
||||
this.getX(), this.getY(), 0.0f, 0.0f, this.getWidth(), this.getHeight(), this.getWidth(), this.getHeight());
|
||||
}
|
||||
|
||||
}
|
81
src/main/java/one/oth3r/sit/screen/ConfigScreen.java
Normal file
|
@ -0,0 +1,81 @@
|
|||
package one.oth3r.sit.screen;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.ConfirmLinkScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.ColorHelper;
|
||||
import one.oth3r.sit.file.FileData;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class ConfigScreen extends Screen {
|
||||
protected final Screen parent;
|
||||
|
||||
public ConfigScreen(Screen parent) {
|
||||
super(Text.translatable("sit!.screen.config"));
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
int startY = this.height / 4 + 48;
|
||||
int spacing = 36;
|
||||
TextureButtonWidget serverConfigButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("config.server"),
|
||||
(button) -> client.setScreen(new UnderConstructionScreen(this, FileData.getServerConfig())), false)
|
||||
.dimensions(250,30).texture(Identifier.of(Data.MOD_ID, "server_button"), 246, 26).build());
|
||||
serverConfigButton.setPosition(this.width / 2 - (serverConfigButton.getWidth()/2), startY);
|
||||
|
||||
TextureButtonWidget sittingConfigButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("config.sitting"),
|
||||
(button) -> client.setScreen(new UnderConstructionScreen(this, FileData.getSittingConfig())), false)
|
||||
.dimensions(250,30).texture(Identifier.of(Data.MOD_ID, "sitting_button"), 246, 26).build());
|
||||
sittingConfigButton.setPosition(this.width / 2 - (sittingConfigButton.getWidth()/2), startY+36);
|
||||
|
||||
|
||||
TextureButtonWidget issuesButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("sit!.gui.button.issues"),
|
||||
ConfirmLinkScreen.opening(this, URI.create("https://github.com/Oth3r/Sit/issues")), true)
|
||||
.dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "issues"), 15, 15).build());
|
||||
issuesButton.setPosition(this.width / 2 - 125, startY + 72 + 12);
|
||||
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.translatable("sit!.gui.button.website"),
|
||||
ConfirmLinkScreen.opening(this, URI.create("https://modrinth.com/mod/sit!"))
|
||||
).dimensions(this.width / 2 - 100, startY + 72 + 12, 98, 20).build());
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.translatable("gui.done"), (button) -> {
|
||||
close();
|
||||
}).dimensions(this.width / 2 + 2, startY + 72 + 12, 98, 20).build());
|
||||
|
||||
TextureButtonWidget donateButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("sit!.gui.button.donate"),
|
||||
ConfirmLinkScreen.opening(this, URI.create("https://Ko-fi.com/oth3r")), true)
|
||||
.dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "donate"), 15, 15).build());
|
||||
donateButton.setPosition(this.width / 2 + 105, startY + 72 + 12);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
super.render(context, mouseX, mouseY, delta);
|
||||
|
||||
// todo fade in like the title screen on first load?
|
||||
renderBanner(context,width/2 - 64,this.height / 4 -38,1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.client.setScreen(parent);
|
||||
}
|
||||
|
||||
private void renderBanner(DrawContext context, int x, int y, float alpha) {
|
||||
RenderSystem.enableBlend();
|
||||
|
||||
context.drawTexture(RenderLayer::getGuiTextured,Identifier.of(Data.MOD_ID, "textures/gui/banner.png"),
|
||||
x, y, 0.0f, 0.0f, 128, 72, 128, 72, ColorHelper.getWhite(alpha));
|
||||
|
||||
RenderSystem.disableBlend();
|
||||
}
|
||||
}
|
11
src/main/java/one/oth3r/sit/screen/ModMenu.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package one.oth3r.sit.screen;
|
||||
|
||||
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
|
||||
public class ModMenu implements ModMenuApi {
|
||||
@Override
|
||||
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||
return ConfigScreen::new;
|
||||
}
|
||||
}
|
86
src/main/java/one/oth3r/sit/screen/TextureButtonWidget.java
Normal file
|
@ -0,0 +1,86 @@
|
|||
package one.oth3r.sit.screen;
|
||||
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.tooltip.Tooltip;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TextureButtonWidget extends ButtonWidget {
|
||||
//todo gray support
|
||||
protected final Identifier texture;
|
||||
protected final int textureWidth;
|
||||
protected final int textureHeight;
|
||||
protected final boolean tooltip;
|
||||
|
||||
TextureButtonWidget(int width, int height, Text message, int textureWidth, int textureHeight, Identifier texture, ButtonWidget.PressAction onPress, @Nullable ButtonWidget.NarrationSupplier narrationSupplier, boolean tooltip) {
|
||||
super(0, 0, width, height, message, onPress, narrationSupplier == null ? DEFAULT_NARRATION_SUPPLIER : narrationSupplier);
|
||||
this.textureWidth = textureWidth;
|
||||
this.textureHeight = textureHeight;
|
||||
this.texture = texture;
|
||||
this.tooltip = tooltip;
|
||||
if (tooltip) setTooltip(Tooltip.of(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
super.renderWidget(context, mouseX, mouseY, delta);
|
||||
int x = this.getX() + this.getWidth() / 2 - this.textureWidth / 2;
|
||||
int y = this.getY() + this.getHeight() / 2 - this.textureHeight / 2;
|
||||
context.drawGuiTexture(RenderLayer::getGuiTextured, this.texture, x, y, this.textureWidth, this.textureHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawMessage(DrawContext context, TextRenderer textRenderer, int color) {
|
||||
if (!this.tooltip) super.drawMessage(context, textRenderer, color);
|
||||
}
|
||||
|
||||
|
||||
public static class Builder {
|
||||
private final Text text;
|
||||
private final ButtonWidget.PressAction onPress;
|
||||
private final boolean hideText;
|
||||
private int width = 150;
|
||||
private int height = 20;
|
||||
@Nullable
|
||||
private Identifier texture;
|
||||
private int textureWidth;
|
||||
private int textureHeight;
|
||||
@Nullable
|
||||
ButtonWidget.NarrationSupplier narrationSupplier;
|
||||
|
||||
public Builder(Text text, ButtonWidget.PressAction onPress, boolean hideText) {
|
||||
this.text = text;
|
||||
this.onPress = onPress;
|
||||
this.hideText = hideText;
|
||||
}
|
||||
|
||||
public Builder dimensions(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder texture(Identifier texture, int width, int height) {
|
||||
this.texture = texture;
|
||||
this.textureWidth = width;
|
||||
this.textureHeight = height;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder narration(ButtonWidget.NarrationSupplier narrationSupplier) {
|
||||
this.narrationSupplier = narrationSupplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextureButtonWidget build() {
|
||||
if (this.texture == null) {
|
||||
throw new IllegalStateException("Sprite not set");
|
||||
}
|
||||
return new TextureButtonWidget(width,height,text,textureWidth,textureHeight,texture,onPress,narrationSupplier,hideText);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package one.oth3r.sit.screen;
|
||||
|
||||
import net.minecraft.client.gui.screen.ConfirmLinkScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.tooltip.Tooltip;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Util;
|
||||
import one.oth3r.sit.file.CustomFile;
|
||||
import one.oth3r.sit.file.SittingConfig;
|
||||
import one.oth3r.sit.utl.Data;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class UnderConstructionScreen<T extends CustomFile<T>> extends Screen {
|
||||
protected final Screen parent;
|
||||
protected T file;
|
||||
|
||||
public UnderConstructionScreen(Screen parent, T file) {
|
||||
super(Text.translatable("sit!.screen.config"));
|
||||
this.parent = parent;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
int startY = this.height / 5-4;
|
||||
ButtonWidget foxPNG = this.addDrawableChild(new ClickableImageWidget(70,70,140,140, Tooltip.of(Text.of("Art by @bunnestbun")),
|
||||
Identifier.of(Data.MOD_ID, "textures/gui/fox.png"), ConfirmLinkScreen.opening(this, URI.create("https://www.instagram.com/bunnestbun/"))));
|
||||
foxPNG.setPosition(this.width / 2 - (foxPNG.getWidth()/2), startY-35);
|
||||
|
||||
ButtonWidget openFileButton = this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("sit!.gui.button.file"),
|
||||
(button) -> Util.getOperatingSystem().open(this.file.getFile()))
|
||||
.dimensions(0, 0, 118 ,20).build());
|
||||
openFileButton.setPosition(this.width / 2 - 70, startY+110);
|
||||
|
||||
TextureButtonWidget folderButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("sit!.gui.button.folder"),
|
||||
(button) -> Util.getOperatingSystem().open(Paths.get(this.file.getFile().getParent())), true)
|
||||
.dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "folder"), 15, 15).build());
|
||||
folderButton.setPosition(this.width / 2 + 50, startY + 110);
|
||||
|
||||
TextureButtonWidget resetButton = this.addDrawableChild(new TextureButtonWidget.Builder(Text.translatable("sit!.gui.button.reset"),
|
||||
(button) -> {
|
||||
this.file.reset();
|
||||
this.file.save();
|
||||
}, true)
|
||||
.dimensions(20,20).texture(Identifier.of(Data.MOD_ID, "reset_file"), 15, 15).build());
|
||||
resetButton.setPosition(this.width / 2 -70, startY + 135);
|
||||
|
||||
ButtonWidget revertButton = this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("sit!.gui.button.revert"),
|
||||
(button) -> this.file.save())
|
||||
.dimensions(0, 0, 118,20).build());
|
||||
revertButton.setPosition(this.width / 2 - 48, startY+135);
|
||||
|
||||
|
||||
ButtonWidget saveExitButton = this.addDrawableChild(new ButtonWidget.Builder(Text.translatable("sit!.gui.button.save"),
|
||||
(button) -> {
|
||||
this.file.load();
|
||||
this.file.save();
|
||||
|
||||
// send the settings to the server if editing the sitting file and on a supported server
|
||||
if (this.file instanceof SittingConfig && Data.isSupportedServer()) {
|
||||
Utl.sendSettingsPackets();
|
||||
}
|
||||
|
||||
this.client.setScreen(parent);
|
||||
})
|
||||
.dimensions(0, 0, 140,20).build());
|
||||
saveExitButton.setPosition(this.width / 2 - 70, startY+168);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.client.setScreen(parent);
|
||||
}
|
||||
}
|
125
src/main/java/one/oth3r/sit/utl/Data.java
Normal file
|
@ -0,0 +1,125 @@
|
|||
package one.oth3r.sit.utl;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Data {
|
||||
public static final String MOD_ID = "sit-oth3r";
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||
|
||||
public static final String CONFIG_DIR = FabricLoader.getInstance().getConfigDir().toFile()+"/sit!/";
|
||||
|
||||
public static final String ENTITY_NAME = "-sit!-entity-";
|
||||
|
||||
// init on server load
|
||||
private static MinecraftServer server;
|
||||
|
||||
public static MinecraftServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public static void setServer(MinecraftServer server) {
|
||||
Data.server = server;
|
||||
}
|
||||
|
||||
// client booleans
|
||||
private static boolean client = false;
|
||||
private static boolean inGame = false;
|
||||
private static boolean singleplayer = false;
|
||||
private static boolean supportedServer = false;
|
||||
|
||||
public static boolean isClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public static void setClient(boolean client) {
|
||||
Data.client = client;
|
||||
}
|
||||
|
||||
public static boolean isInGame() {
|
||||
return inGame;
|
||||
}
|
||||
|
||||
public static void setInGame(boolean inGame) {
|
||||
Data.inGame = inGame;
|
||||
}
|
||||
|
||||
public static boolean isSingleplayer() {
|
||||
return singleplayer;
|
||||
}
|
||||
|
||||
public static void setSingleplayer(boolean singleplayer) {
|
||||
Data.singleplayer = singleplayer;
|
||||
}
|
||||
|
||||
public static boolean isSupportedServer() {
|
||||
return supportedServer;
|
||||
}
|
||||
|
||||
public static void setSupportedServer(boolean supportedServer) {
|
||||
Data.supportedServer = supportedServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* a list of players who just joined, to check if they are mounted to a Sit! entity
|
||||
* (they don't load in on the player join event for some reason)
|
||||
*/
|
||||
private static final HashMap<ServerPlayerEntity, Integer> checkPlayers = new HashMap<>();
|
||||
|
||||
public static void setCheckPlayer(ServerPlayerEntity player, Integer time) {
|
||||
checkPlayers.put(player, time);
|
||||
}
|
||||
|
||||
public static void removeCheckPlayer(ServerPlayerEntity player) {
|
||||
checkPlayers.remove(player);
|
||||
}
|
||||
|
||||
public static HashMap<ServerPlayerEntity, Integer> getCheckPlayers() {
|
||||
return new HashMap<>(checkPlayers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* a list of players that need a sit entity spawned for them, on the server loop to stop crashing with other mods (ASYNC)
|
||||
*/
|
||||
private static final HashMap<ServerPlayerEntity, DisplayEntity.TextDisplayEntity> spawnList = new HashMap<>();
|
||||
|
||||
public static void setSpawnList(ServerPlayerEntity player, DisplayEntity.TextDisplayEntity entity) {
|
||||
spawnList.put(player, entity);
|
||||
}
|
||||
|
||||
public static void removeSpawnList(ServerPlayerEntity player) {
|
||||
spawnList.remove(player);
|
||||
}
|
||||
|
||||
public static HashMap<ServerPlayerEntity, DisplayEntity.TextDisplayEntity> getSpawnList() {
|
||||
return new HashMap<>(spawnList);
|
||||
}
|
||||
|
||||
/**
|
||||
* a list of every Sit! entity in the server, bound to the player
|
||||
*/
|
||||
private static final HashMap<ServerPlayerEntity, DisplayEntity.TextDisplayEntity> sitEntities = new HashMap<>();
|
||||
|
||||
public static void addSitEntity(ServerPlayerEntity player, DisplayEntity.TextDisplayEntity entity) {
|
||||
sitEntities.put(player, entity);
|
||||
}
|
||||
|
||||
public static void removeSitEntity(DisplayEntity.TextDisplayEntity entity) {
|
||||
sitEntities.values().remove(entity);
|
||||
}
|
||||
|
||||
public static DisplayEntity.TextDisplayEntity getSitEntity(ServerPlayerEntity player) {
|
||||
return sitEntities.get(player);
|
||||
}
|
||||
|
||||
public static HashMap<ServerPlayerEntity, DisplayEntity.TextDisplayEntity> getSitEntities() {
|
||||
return new HashMap<>(sitEntities);
|
||||
}
|
||||
}
|
215
src/main/java/one/oth3r/sit/utl/Events.java
Normal file
|
@ -0,0 +1,215 @@
|
|||
package one.oth3r.sit.utl;
|
||||
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.option.KeyBinding;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Formatting;
|
||||
import one.oth3r.sit.command.SitCommand;
|
||||
import one.oth3r.sit.file.FileData;
|
||||
import one.oth3r.sit.file.LangReader;
|
||||
import one.oth3r.sit.file.SittingConfig;
|
||||
import one.oth3r.sit.packet.SitPayloads;
|
||||
import one.oth3r.sit.screen.ConfigScreen;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
public class Events {
|
||||
|
||||
private static class Keybindings {
|
||||
private static KeyBinding toggle_key;
|
||||
private static KeyBinding sit_key;
|
||||
private static KeyBinding config__key;
|
||||
|
||||
private static void register() {
|
||||
toggle_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key.sit!.toggle",
|
||||
GLFW.GLFW_KEY_UNKNOWN,
|
||||
"category.sit!"
|
||||
));
|
||||
sit_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key.sit!.sit",
|
||||
GLFW.GLFW_KEY_UNKNOWN,
|
||||
"category.sit!"
|
||||
));
|
||||
config__key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
"key.sit!.config",
|
||||
GLFW.GLFW_KEY_UNKNOWN,
|
||||
"category.sit!"
|
||||
));
|
||||
}
|
||||
|
||||
private static void loopLogic(MinecraftClient client) {
|
||||
ClientPlayerEntity player = client.player;
|
||||
|
||||
while (config__key.wasPressed()) {
|
||||
client.setScreen(new ConfigScreen(client.currentScreen));
|
||||
}
|
||||
|
||||
/// anything below uses the player object, make sure it's not null
|
||||
if (player == null) return;
|
||||
|
||||
while (toggle_key.wasPressed()) {
|
||||
if (Data.isInGame()) {
|
||||
player.sendMessage(Logic.toggleSiting(), true);
|
||||
}
|
||||
}
|
||||
|
||||
while (sit_key.wasPressed()) {
|
||||
// just send the sit command
|
||||
if (Data.isInGame()) {
|
||||
if (Data.isSupportedServer()) {
|
||||
player.networkHandler.sendCommand("sit");
|
||||
} else {
|
||||
// unsupported server message if not in a Sit! server
|
||||
player.sendMessage(Utl.lang("sit!.chat.unsupported")
|
||||
.formatted(Formatting.RED), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Packet {
|
||||
private static void common() {
|
||||
// register the data
|
||||
PayloadTypeRegistry.playC2S().register(SitPayloads.SettingsPayload.ID, SitPayloads.SettingsPayload.CODEC);
|
||||
|
||||
PayloadTypeRegistry.playS2C().register(SitPayloads.ResponsePayload.ID, SitPayloads.ResponsePayload.CODEC);
|
||||
|
||||
// server receiver is common
|
||||
|
||||
/// receiving the sitting setting payload
|
||||
ServerPlayNetworking.registerGlobalReceiver(SitPayloads.SettingsPayload.ID,((payload, context) -> Data.getServer().execute(() -> {
|
||||
// save the setting on the server for that player
|
||||
FileData.setPlayerSetting(context.player(),Utl.getGson().fromJson(payload.value(), SittingConfig.class));
|
||||
|
||||
// send the player back a response packet for confirmation
|
||||
ServerPlayNetworking.send(context.player(),new SitPayloads.ResponsePayload(SitPayloads.ResponsePayload.VERSION));
|
||||
|
||||
// log the receiving of the packet from the player
|
||||
Data.LOGGER.info(Utl.lang("sit!.console.player_settings",context.player().getName().getString()).getString());
|
||||
})));
|
||||
}
|
||||
|
||||
private static void client() {
|
||||
/// receiving the response packet from the server
|
||||
ClientPlayNetworking.registerGlobalReceiver(SitPayloads.ResponsePayload.ID, ((payload, context) -> {
|
||||
// only update when needed
|
||||
if (!Data.isSupportedServer()) {
|
||||
Data.setSupportedServer(true);
|
||||
Data.LOGGER.info(Utl.lang("sit!.console.connected",payload.value()).getString());
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private static void clientMisc() {
|
||||
// client tick loop
|
||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||
assert client.player != null;
|
||||
Keybindings.loopLogic(client);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* registers all client connection code
|
||||
*/
|
||||
private static void clientConnections() {
|
||||
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
|
||||
Data.setInGame(true);
|
||||
if (client.isInSingleplayer()) Data.setSingleplayer(true);
|
||||
// send a data packet whenever joining a server
|
||||
Utl.sendSettingsPackets();
|
||||
});
|
||||
|
||||
// reset cashed things on disconnect
|
||||
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> {
|
||||
Data.setInGame(false);
|
||||
Data.setSingleplayer(false);
|
||||
Data.setSupportedServer(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* registers all common server player connection code
|
||||
*/
|
||||
private static void playerConnections() {
|
||||
// PLAYER JOIN
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
||||
FileData.setPlayerSetting(handler.player, FileData.getSittingConfig());
|
||||
Data.setCheckPlayer(handler.player, 5);
|
||||
});
|
||||
|
||||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||
// if keep is off, remove the entity
|
||||
if (!FileData.getServerConfig().isKeepActive()) {
|
||||
Logic.removeEntity(handler.player);
|
||||
}
|
||||
FileData.removePlayerSetting(handler.player);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* registers all server lifecycle events
|
||||
*/
|
||||
private static void serverLifecycle() {
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(s -> {
|
||||
Data.setServer(s);
|
||||
LangReader.loadLanguageFile();
|
||||
|
||||
// right click on block event
|
||||
UseBlockCallback.EVENT.register((pl, world, hand, hitResult) -> {
|
||||
if (Data.isClient() && !Data.isSingleplayer()) return ActionResult.PASS;
|
||||
// get the server player
|
||||
ServerPlayerEntity player = Data.getServer().getPlayerManager().getPlayer(pl.getUuid());
|
||||
|
||||
// make sure the player isn't null, and make sure they aren't in spectator
|
||||
if (player == null || player.isSpectator()) return ActionResult.PASS;
|
||||
|
||||
// consume if sitting, if not pass
|
||||
return Logic.sit(player,hitResult.getBlockPos(),hitResult) ? ActionResult.CONSUME : ActionResult.PASS;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
ServerLifecycleEvents.SERVER_STOPPED.register(s -> {
|
||||
// clear the server
|
||||
Data.setServer(null);
|
||||
// clear all player settings (singleplayer and such)
|
||||
FileData.clearPlayerSettings();
|
||||
});
|
||||
|
||||
// server loop setup
|
||||
ServerTickEvents.END_SERVER_TICK.register(minecraftServer -> minecraftServer.execute(LoopManager::tick));
|
||||
|
||||
// server command setup
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> SitCommand.register(dispatcher));
|
||||
}
|
||||
|
||||
// a one call method for the common and client
|
||||
|
||||
public static void registerCommon() {
|
||||
playerConnections();
|
||||
serverLifecycle();
|
||||
Packet.common();
|
||||
}
|
||||
|
||||
public static void registerClient() {
|
||||
Keybindings.register();
|
||||
clientConnections();
|
||||
clientMisc();
|
||||
Packet.client();
|
||||
}
|
||||
}
|
185
src/main/java/one/oth3r/sit/utl/Logic.java
Normal file
|
@ -0,0 +1,185 @@
|
|||
package one.oth3r.sit.utl;
|
||||
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import one.oth3r.sit.file.FileData;
|
||||
import one.oth3r.sit.file.SittingConfig;
|
||||
import one.oth3r.sit.file.HandSetting;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Logic {
|
||||
public static boolean sit(ServerPlayerEntity player, BlockPos blockPos, @Nullable BlockHitResult hitResult) {
|
||||
// cant sit if crouching
|
||||
if (player.isSneaking()) return false;
|
||||
|
||||
// if sitting on a sit entity and sit while seated off, false
|
||||
if (!FileData.getServerConfig().canSitWhileSeated() && Data.getSitEntity(player) != null) return false;
|
||||
|
||||
// if hit result isnt null (check the hands of the player) & the player hand checker returns false (can't sit with the items in the hand), quit
|
||||
if (hitResult != null) {
|
||||
if (!checkHands(player)) return false;
|
||||
}
|
||||
|
||||
ServerWorld serverWorld = player.getServerWorld();
|
||||
BlockState blockState = serverWorld.getBlockState(blockPos);
|
||||
|
||||
Double sitHeight = Utl.getSittingHeight(blockState,player,blockPos,hitResult);
|
||||
|
||||
// if the sit height is null, its not a sittable block
|
||||
if (sitHeight == null) return false;
|
||||
|
||||
DisplayEntity.TextDisplayEntity entity = Utl.Entity.create(serverWorld,blockPos,sitHeight);
|
||||
|
||||
if (!checkPlayerSitAbility(entity)) return false;
|
||||
|
||||
Utl.Entity.spawnSit(player, entity);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean sitLooking(ServerPlayerEntity player) {
|
||||
return sit(player, Utl.getBlockPosPlayerIsLookingAt(player.getServerWorld(),player,5),null);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the hands of the player and the items in each hand and sees if the player can sit down
|
||||
*/
|
||||
public static boolean checkHands(ServerPlayerEntity player) {
|
||||
SittingConfig sittingConfig = FileData.getPlayerSetting(player);
|
||||
// if can't sit with hand, false
|
||||
if (!sittingConfig.canSitWithHand()) return false;
|
||||
|
||||
// a boolean that shows if the player can sit or not
|
||||
boolean canSit = true;
|
||||
|
||||
// for each hand
|
||||
for (Hand hand : Hand.values()) {
|
||||
// if they can't sit, no need to run extra code
|
||||
if (!canSit) break;
|
||||
|
||||
HandSetting handSetting = sittingConfig.getHand(hand);
|
||||
switch (handSetting.getSittingRequirement()) {
|
||||
case EMPTY -> canSit = player.getStackInHand(hand).isEmpty();
|
||||
case FILTER -> canSit = Utl.checkItem(handSetting.getFilter(), player.getStackInHand(hand));
|
||||
}
|
||||
}
|
||||
// return the output of the check
|
||||
return canSit;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the entity bound to the player from the game, using the player
|
||||
*/
|
||||
public static void removeEntity(ServerPlayerEntity player) {
|
||||
DisplayEntity.TextDisplayEntity entity = Data.getSitEntity(player);
|
||||
// make sure the player has a sit entity bounded to them
|
||||
if (entity == null) return;
|
||||
|
||||
// remove the entity
|
||||
Utl.Entity.remove(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* spawns a sit entity for the player, they HAVE TO BE in the spawn list
|
||||
*/
|
||||
public static void spawnEntity(ServerPlayerEntity player) {
|
||||
// return if not in the list
|
||||
if (Data.getSpawnList().get(player) == null) return;
|
||||
|
||||
// if the player is already sitting on a sit entity, remove it before spawning a new one
|
||||
if (Data.getSitEntity(player) != null) Logic.removeEntity(player);
|
||||
// get the new entity
|
||||
DisplayEntity.TextDisplayEntity sitEntity = Data.getSpawnList().get(player);
|
||||
// spawn and ride the entity
|
||||
player.getServerWorld().spawnEntity(sitEntity);
|
||||
player.startRiding(sitEntity);
|
||||
// add the entity to the list
|
||||
Data.addSitEntity(player, sitEntity);
|
||||
// remove the entity from the spawn list
|
||||
Data.removeSpawnList(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the player should still be sitting, e.g. the block was destroyed ect.
|
||||
*/
|
||||
public static void checkSittingValidity(ServerPlayerEntity player) {
|
||||
DisplayEntity.TextDisplayEntity entity = Data.getSitEntity(player);
|
||||
// make sure the player has a sit entity bounded to them
|
||||
if (entity == null) return;
|
||||
|
||||
// if the entity location isn't valid anymore, remove it
|
||||
if (!Utl.Entity.isValid(player,entity)) {
|
||||
removeEntity(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if entity would cause the player to suffocate when sitting
|
||||
* @param entity the entity
|
||||
* @return true if there is no obstruction
|
||||
*/
|
||||
public static boolean checkPlayerSitAbility(DisplayEntity.TextDisplayEntity entity) {
|
||||
// get the entity's block pos
|
||||
BlockPos pos = Utl.Entity.getBlockPos(entity);
|
||||
// get the poses to check above the block
|
||||
BlockPos pos1 = new BlockPos(pos).add(0,1,0), pos2 = new BlockPos(pos).add(0,2,0), posBelow = new BlockPos(pos);
|
||||
// doesn't check 2 blocks above if not sitting above .80 of the block
|
||||
if (pos.getY() > entity.getY() - .80) {
|
||||
pos2 = pos2.add(0,-1,0);
|
||||
posBelow = posBelow.add(0,-1,0);
|
||||
}
|
||||
|
||||
// check if both poses are obstructed or not
|
||||
return Utl.isNotObstructed(entity.getWorld(),pos1) && Utl.isNotObstructed(entity.getWorld(),pos2)
|
||||
// also check if occupied, checking below to make sure you cant sit directly on top of another sit entity
|
||||
&& Utl.isNotOccupied(pos) && Utl.isNotOccupied(pos1) && Utl.isNotOccupied(pos2) && Utl.isNotOccupied(posBelow);
|
||||
}
|
||||
|
||||
/**
|
||||
* reloads the config files
|
||||
*/
|
||||
public static void reload() {
|
||||
FileData.loadFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* toggles the sit ablity config option
|
||||
* @return returns a message, that can be sent to the player
|
||||
*/
|
||||
public static MutableText toggleSiting() {
|
||||
if (Data.isSupportedServer()) {
|
||||
// get the sitting config
|
||||
SittingConfig config = FileData.getSittingConfig();
|
||||
// toggle the setting
|
||||
config.setEnabled(!config.getEnabled());
|
||||
|
||||
// set the sitting config to the new value
|
||||
FileData.setSittingConfig(config);
|
||||
// save the changes to the file
|
||||
config.save();
|
||||
// send the changes to the server
|
||||
Utl.sendSettingsPackets();
|
||||
|
||||
|
||||
// get the message settings
|
||||
String messageKey = "sit!.chat.sit_toggle."+(config.getEnabled()?"on":"off");
|
||||
Formatting messageColor = config.getEnabled()?Formatting.GREEN:Formatting.RED;
|
||||
|
||||
// send the player the actionbar message
|
||||
return Utl.lang("sit!.chat.sit_toggle",
|
||||
Utl.lang(messageKey).formatted(messageColor));
|
||||
} else {
|
||||
// unsupported server message if not in a Sit! server
|
||||
return Utl.lang("sit!.chat.unsupported")
|
||||
.formatted(Formatting.RED);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
59
src/main/java/one/oth3r/sit/utl/LoopManager.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
package one.oth3r.sit.utl;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class LoopManager {
|
||||
|
||||
private static int time = 0;
|
||||
|
||||
public static void tick() {
|
||||
time++;
|
||||
if (time >= 5) {
|
||||
time = 0;
|
||||
|
||||
// check all sit entities to make sure their still valid
|
||||
HashMap<ServerPlayerEntity, DisplayEntity.TextDisplayEntity> entities = Data.getSitEntities();
|
||||
for (ServerPlayerEntity player : entities.keySet()) {
|
||||
DisplayEntity.TextDisplayEntity entity = entities.get(player);
|
||||
|
||||
if (player.getVehicle() == null || !player.getVehicle().equals(entity)) {
|
||||
Logic.removeEntity(player);
|
||||
} else {
|
||||
Logic.checkSittingValidity(player);
|
||||
}
|
||||
}
|
||||
|
||||
// get the player's sit entity when they join
|
||||
HashMap<ServerPlayerEntity, Integer> checkPlayers = Data.getCheckPlayers();
|
||||
for (ServerPlayerEntity player : checkPlayers.keySet()) {
|
||||
Integer time = checkPlayers.get(player);
|
||||
// tick down or remove the player if at the end
|
||||
time -= 1;
|
||||
if (time <= 0) Data.removeCheckPlayer(player);
|
||||
else Data.setCheckPlayer(player, time);
|
||||
|
||||
if (player.getVehicle() != null) {
|
||||
Entity entity = player.getVehicle();
|
||||
if (entity instanceof DisplayEntity.TextDisplayEntity tde && entity.getName().getString().equals(Data.ENTITY_NAME)) {
|
||||
// bind the entity to the player
|
||||
Data.addSitEntity(player, tde);
|
||||
// check if the player is still allowed to sit
|
||||
Logic.checkSittingValidity(player);
|
||||
// remove the player from the check
|
||||
Data.removeCheckPlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spawn entities for everyone in the spawn list
|
||||
HashMap<ServerPlayerEntity, DisplayEntity.TextDisplayEntity> spawnList = Data.getSpawnList();
|
||||
for (ServerPlayerEntity player : spawnList.keySet()) {
|
||||
Logic.spawnEntity(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
522
src/main/java/one/oth3r/sit/utl/Utl.java
Normal file
|
@ -0,0 +1,522 @@
|
|||
package one.oth3r.sit.utl;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.google.gson.stream.MalformedJsonException;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.enums.BlockHalf;
|
||||
import net.minecraft.block.enums.SlabType;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.consume.UseAction;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TextColor;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.RaycastContext;
|
||||
import net.minecraft.world.World;
|
||||
import one.oth3r.sit.file.*;
|
||||
import one.oth3r.sit.packet.SitPayloads;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Utl {
|
||||
|
||||
/**
|
||||
* check if a block is obstructed (no collision)
|
||||
* @return true if not obstructed
|
||||
*/
|
||||
public static boolean isNotObstructed(World world, BlockPos blockPos) {
|
||||
// get the block state at the blockPos
|
||||
BlockState state = world.getBlockState(blockPos);
|
||||
// make sure it doesn't have a collision
|
||||
return state.getCollisionShape(world,blockPos).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the list of sit entities and sees if any of them are occupying the block pos
|
||||
*/
|
||||
public static boolean isNotOccupied(BlockPos pos) {
|
||||
return Data.getSitEntities().values().stream().noneMatch(entity -> entity.getBlockPos().equals(pos));
|
||||
}
|
||||
|
||||
public static class Num {
|
||||
|
||||
public static boolean isInt(String string) {
|
||||
try {
|
||||
Integer.parseInt(string);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Integer toInt(String s) {
|
||||
// return an int no matter what
|
||||
try {
|
||||
return Integer.parseInt(s);
|
||||
} catch (NumberFormatException e) {
|
||||
try {
|
||||
return (int) Double.parseDouble(s);
|
||||
} catch (NumberFormatException e2) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNum(String s) {
|
||||
// checks if int or a double
|
||||
try {
|
||||
Integer.parseInt(s);
|
||||
return true;
|
||||
} catch (NumberFormatException e1) {
|
||||
try {
|
||||
Double.parseDouble(s);
|
||||
return true;
|
||||
} catch (NumberFormatException e2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final double HALF_BLOCK = 0.5;
|
||||
public static final double CARPET = 0.062;
|
||||
|
||||
/**
|
||||
* checks if the provided itemstack is a valid one for the provided filter
|
||||
* @param filter the filter
|
||||
* @param itemStack itemstack to check
|
||||
* @return if true, the item isn't filtered out
|
||||
*/
|
||||
public static boolean checkItem(HandSetting.Filter filter, ItemStack itemStack) {
|
||||
// default to true if there's nothing
|
||||
if (itemStack.isEmpty()) return true;
|
||||
|
||||
boolean TRUE = true, FALSE = false;
|
||||
if (filter.isInverted()) {
|
||||
TRUE = false;
|
||||
FALSE = true;
|
||||
}
|
||||
|
||||
boolean itemcheck = filter.getCustomItems().checkItem(itemStack);
|
||||
|
||||
// iif the item passes the checks, return true
|
||||
if (itemcheck) return TRUE;
|
||||
|
||||
// if none of the custom were met, try the default conditions
|
||||
|
||||
// get the use actions for the filters
|
||||
ArrayList<UseAction> food = new ArrayList<>();
|
||||
food.add(UseAction.EAT);
|
||||
food.add(UseAction.DRINK);
|
||||
ArrayList<UseAction> notUsable = new ArrayList<>(food);
|
||||
notUsable.add(UseAction.NONE);
|
||||
|
||||
HandSetting.Filter.Presets presets = filter.getPresets();
|
||||
|
||||
// try the default conditions
|
||||
if (presets.isBlock() && itemStack.getItem() instanceof BlockItem) return TRUE;
|
||||
if (presets.isFood() && food.contains(itemStack.getUseAction())) return TRUE;
|
||||
if (presets.isUsable() && hasItemUse(itemStack)) return TRUE;
|
||||
|
||||
// if nothing else is met, the item is filtered out
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a block ID (eg. minecraft:air) from a blockstate. (it is easier with a block, but we are mostly working with block states
|
||||
* @return the block ID (minecraft:air)
|
||||
*/
|
||||
public static String getBlockID(BlockState blockState) {
|
||||
return Registries.BLOCK.getId(blockState.getBlock()).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the sitting height for the provided blockstate, via memory loaded config from Data
|
||||
* @param blockState the state of the block
|
||||
* @param player the player to
|
||||
* @param blockPos the pos of the block
|
||||
* @param hit nullable, for the player interaction check
|
||||
* @return null if not a valid block
|
||||
*/
|
||||
public static Double getSittingHeight(BlockState blockState, ServerPlayerEntity player, BlockPos blockPos, @Nullable BlockHitResult hit) {
|
||||
ServerConfig config = FileData.getServerConfig();
|
||||
Block block = blockState.getBlock();
|
||||
|
||||
// make sure that the block that is being sit on has no interaction when hand sitting
|
||||
if (hit != null && hasInteraction(blockState)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// only if custom is enabled
|
||||
if (config.isCustomEnabled()) {
|
||||
// if the block is on the blacklist, false
|
||||
if (config.getBlacklistedBlocks().stream().anyMatch(c -> c.isValid(blockState))) return null;
|
||||
|
||||
for (SittingBlock sittingBlock : config.getSittingBlocks()) {
|
||||
// if the block is valid, true
|
||||
if (sittingBlock.isValid(blockState)) return sittingBlock.getSittingHeight();
|
||||
}
|
||||
}
|
||||
|
||||
// add the default block types and check for them
|
||||
if (block instanceof StairsBlock
|
||||
&& config.getPresetBlocks().isStairs()
|
||||
&& blockState.get(StairsBlock.HALF) == BlockHalf.BOTTOM) return HALF_BLOCK;
|
||||
if (config.getPresetBlocks().isSlabs()
|
||||
&& block instanceof SlabBlock
|
||||
&& blockState.get(SlabBlock.TYPE) == SlabType.BOTTOM) return HALF_BLOCK;
|
||||
if (config.getPresetBlocks().isCarpets()
|
||||
&& block instanceof CarpetBlock) return CARPET;
|
||||
if (config.getPresetBlocks().isFullBlocks()
|
||||
// make sure the block is a full cube
|
||||
&& blockState.isFullCube(player.getWorld(),blockPos)) return 1.0;
|
||||
|
||||
// at the end, return false
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if a block has an interaction
|
||||
* @param blockState the blockstate of the block to check
|
||||
* @return if the block has an interaction or not
|
||||
*/
|
||||
public static boolean hasInteraction(BlockState blockState) {
|
||||
return isMethodOverridden(AbstractBlock.class, blockState.getBlock().getClass(), "onUse", BlockState.class, World.class, BlockPos.class, PlayerEntity.class, BlockHitResult.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if an item has a use
|
||||
* @param itemStack the itemstack to check
|
||||
* @return if the item has a use or not
|
||||
*/
|
||||
public static boolean hasItemUse(ItemStack itemStack) {
|
||||
return isMethodOverridden(Item.class, itemStack.getItem().getClass(), "use", World.class, PlayerEntity.class, Hand.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if a method in the base class has been overridden in the subclass(es) by:
|
||||
* checking the subclass and its supers till the original method is found or the original method is found
|
||||
* @param baseClass the base class
|
||||
* @param subclass the subclass to check
|
||||
* @param methodName the method to check for
|
||||
* @param parameterTypes the parameterTypes for the method, see {@link java.lang.Class#getDeclaredMethod(java.lang.String, java.lang.Class[])}
|
||||
* @return if the method is overridden or not
|
||||
*/
|
||||
public static boolean isMethodOverridden(Class<?> baseClass, Class<?> subclass, String methodName, Class<?>... parameterTypes) {
|
||||
try {
|
||||
// get the original method
|
||||
Method superMethod = baseClass.getMethod(methodName, parameterTypes);
|
||||
|
||||
// the current class to check, starting with the subclass
|
||||
Class<?> currentClass = subclass;
|
||||
// while the class is null and the current class isn't the same as the baseclass.
|
||||
while (currentClass != null && !currentClass.equals(baseClass)) {
|
||||
try {
|
||||
// get the submethod
|
||||
Method subMethod = currentClass.getDeclaredMethod(methodName, parameterTypes);
|
||||
|
||||
// check if the methods are different
|
||||
if (!superMethod.equals(subMethod)) {
|
||||
return true;
|
||||
}
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
// method isnt in this class, bump up a class and check that one
|
||||
}
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
// method doesn't exist in the base class
|
||||
return false;
|
||||
}
|
||||
// an override wasn't found
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static class Entity {
|
||||
|
||||
/**
|
||||
* checks if the entity's block is still there, & is valid
|
||||
*/
|
||||
public static boolean isValid(ServerPlayerEntity player, @NotNull DisplayEntity.TextDisplayEntity entity) {
|
||||
BlockPos blockPos = getBlockPos(entity);
|
||||
// get the blockstate
|
||||
BlockState blockState = player.getWorld().getBlockState(blockPos);
|
||||
// check if the block is still there & the block is a valid sit block (by checking if there is a sit height for the block)
|
||||
return !blockState.isAir() && getSittingHeight(blockState,player,blockPos,null) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the bound block pos of the sit entity
|
||||
*/
|
||||
public static BlockPos getBlockPos(DisplayEntity.TextDisplayEntity entity) {
|
||||
// get the block pos
|
||||
BlockPos pos = new BlockPos(entity.getBlockX(),entity.getBlockY(),entity.getBlockZ());
|
||||
// if above the block, subtract 1
|
||||
if (isAboveBlockHeight(entity)) {
|
||||
pos = pos.add(0,-1,0);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* using the entity's pitch, figure out if the player is above the block height or not
|
||||
*/
|
||||
public static boolean isAboveBlockHeight(DisplayEntity.TextDisplayEntity entity) {
|
||||
return entity.getPitch() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates the sit entity from the pos & sit height provided
|
||||
* @param world the world to make the entity in
|
||||
* @param blockPos the pos of the entity
|
||||
* @param sitHeight the height for the entity to be at
|
||||
* @return the entity at the correct height and position
|
||||
*/
|
||||
public static DisplayEntity.TextDisplayEntity create(World world, BlockPos blockPos, double sitHeight) {
|
||||
DisplayEntity.TextDisplayEntity entity = new DisplayEntity.TextDisplayEntity(EntityType.TEXT_DISPLAY,world);
|
||||
|
||||
// entity flags
|
||||
entity.setCustomName(Text.of(Data.ENTITY_NAME));
|
||||
entity.setCustomNameVisible(false);
|
||||
entity.setInvulnerable(true);
|
||||
entity.setInvisible(true);
|
||||
|
||||
/// make a double for adjusting the entity height if some versions change the player sit height on entities again
|
||||
double adjustmentY = 0;
|
||||
|
||||
// get the entities y level
|
||||
double entityY = blockPos.getY();
|
||||
entityY += sitHeight + adjustmentY;
|
||||
|
||||
// set the entities position
|
||||
entity.updatePositionAndAngles(blockPos.getX()+.5, entityY, blockPos.getZ()+.5, 0, 0);
|
||||
|
||||
// change pitch based on if player is sitting below block height or not (full block height only)
|
||||
if (entity.getY() == blockPos.getY() + 1) entity.setPitch(90); // below
|
||||
else entity.setPitch(-90); // above
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the entity from the entity map and world, dismounting any passengers
|
||||
*/
|
||||
public static void remove(DisplayEntity.TextDisplayEntity entity) {
|
||||
// dismount everyone
|
||||
entity.removeAllPassengers();
|
||||
// remove the entity
|
||||
entity.setRemoved(net.minecraft.entity.Entity.RemovalReason.DISCARDED);
|
||||
// remove the entity from the data set if exists
|
||||
Data.removeSitEntity(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* spawns the entity and make the player sit on it
|
||||
*/
|
||||
public static void spawnSit(ServerPlayerEntity player, DisplayEntity.TextDisplayEntity entity) {
|
||||
Data.setSpawnList(player, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes all sit entities loaded on the server
|
||||
*/
|
||||
public static void purge(ServerPlayerEntity player, boolean message) {
|
||||
/// FYI it cant purge an entity from a disconnected player or unloaded chunks
|
||||
|
||||
// get a list of sit entities
|
||||
List<? extends DisplayEntity.TextDisplayEntity> list = player.getServerWorld()
|
||||
.getEntitiesByType(TypeFilter.instanceOf(DisplayEntity.TextDisplayEntity.class),
|
||||
entity -> entity.getName().getString().equals(Data.ENTITY_NAME));
|
||||
|
||||
// amount of sit entities purged
|
||||
int count = 0;
|
||||
|
||||
// remove each one & count
|
||||
for (DisplayEntity.TextDisplayEntity entity : list) {
|
||||
remove(entity);
|
||||
count++;
|
||||
}
|
||||
|
||||
// send a message if needed
|
||||
if (message) {
|
||||
player.sendMessage(messageTag().append(Utl.lang("sit!.chat.purged",Utl.lang("sit!.chat.purged.total",count).styled(
|
||||
style -> style.withColor(Colors.LIGHT_GRAY).withItalic(true)
|
||||
)).styled(
|
||||
style -> style.withColor(Colors.GREEN)
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static MutableText messageTag() {
|
||||
return Text.literal("[").append(Text.literal("Sit!").styled(
|
||||
style -> style.withColor(TextColor.parse("#c400ff").result().orElse(TextColor.fromFormatting(Formatting.DARK_PURPLE))))
|
||||
).append("] ");
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a MutableText using the language key, if on server, using the custom lang reader
|
||||
*/
|
||||
public static MutableText lang(String key, Object... args) {
|
||||
if (Data.isClient()) return Text.translatable(key, args);
|
||||
else return LangReader.of(key, args).getTxT();
|
||||
}
|
||||
|
||||
public static class Enum {
|
||||
|
||||
public static <T extends java.lang.Enum<T>> T get(Object enumString, Class<T> enumType) {
|
||||
return get(enumString,enumType,enumType.getEnumConstants()[0]);
|
||||
}
|
||||
/**
|
||||
* gets an enum from a string without returning null
|
||||
* @param enumString the string of the enum
|
||||
* @param enumType the class of enums
|
||||
* @param defaultEnum the enum to return if a match isn't found
|
||||
* @return an enum, if there isn't a match, it returns the first enum
|
||||
*/
|
||||
public static <T extends java.lang.Enum<T>> T get(Object enumString, Class<T> enumType, T defaultEnum) {
|
||||
T[] values = enumType.getEnumConstants();
|
||||
for (T all : values) {
|
||||
// check if there is a match for any of the enum names
|
||||
if (enumString.toString().equals(all.name())) return all;
|
||||
}
|
||||
// if there's no match return the first entry
|
||||
return defaultEnum;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sends the settings packets to the server, if client & in game
|
||||
*/
|
||||
public static void sendSettingsPackets() {
|
||||
if (Data.isClient() && Data.isInGame()) {
|
||||
ClientPlayNetworking.send(new SitPayloads.SettingsPayload(Utl.getGson().toJson(FileData.getSittingConfig())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a Gson with the LenientTypeAdapter
|
||||
*/
|
||||
public static Gson getGson() {
|
||||
return new GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapterFactory(new LenientTypeAdapterFactory())
|
||||
.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* the LenientTypeAdapter, doesn't throw anything when reading a weird JSON entry, good for human entered JSONs
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static class LenientTypeAdapterFactory implements TypeAdapterFactory {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
|
||||
|
||||
// Check if the type is a List, then run the custom list type adapter
|
||||
if (List.class.isAssignableFrom(type.getRawType())) {
|
||||
Type elementType = ((ParameterizedType) type.getType()).getActualTypeArguments()[0];
|
||||
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
|
||||
// the custom adapter
|
||||
return (TypeAdapter<T>) new RemoveNullListTypeAdapter<>(elementAdapter);
|
||||
}
|
||||
|
||||
return new TypeAdapter<>() {
|
||||
// normal writer
|
||||
public void write(JsonWriter out, T value) throws IOException {
|
||||
delegate.write(out, value);
|
||||
}
|
||||
// custom reader
|
||||
public T read(JsonReader in) throws IOException {
|
||||
try {
|
||||
//Try to read value using default TypeAdapter
|
||||
return delegate.read(in);
|
||||
} catch (JsonSyntaxException | MalformedJsonException e) {
|
||||
// don't throw anything if there's a weird JSON, just return null
|
||||
in.skipValue();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* type adapter that doesnt allow null / bad entries
|
||||
*/
|
||||
private static class RemoveNullListTypeAdapter<E> extends TypeAdapter<List<E>> {
|
||||
private final TypeAdapter<E> elementAdapter;
|
||||
|
||||
RemoveNullListTypeAdapter(TypeAdapter<E> elementAdapter) {
|
||||
this.elementAdapter = elementAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, List<E> value) throws IOException {
|
||||
out.beginArray();
|
||||
for (E element : value) {
|
||||
elementAdapter.write(out, element);
|
||||
}
|
||||
out.endArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<E> read(JsonReader in) throws IOException {
|
||||
List<E> list = new ArrayList<>();
|
||||
in.beginArray();
|
||||
while (in.hasNext()) {
|
||||
try {
|
||||
E element = elementAdapter.read(in);
|
||||
// skip null entry
|
||||
if (element == null) continue;
|
||||
list.add(element);
|
||||
} catch (Exception e) {
|
||||
// skip invalid entry
|
||||
in.skipValue();
|
||||
}
|
||||
}
|
||||
in.endArray();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockPos getBlockPosPlayerIsLookingAt(ServerWorld world, PlayerEntity player, double range) {
|
||||
// pos, adjusted to player eye level
|
||||
Vec3d rayStart = player.getPos().add(0, player.getEyeHeight(player.getPose()), 0);
|
||||
// extend ray by the range
|
||||
Vec3d rayEnd = rayStart.add(player.getRotationVector().multiply(range));
|
||||
|
||||
BlockHitResult hitResult = world.raycast(new RaycastContext(rayStart, rayEnd, RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.NONE, ShapeContext.absent()));
|
||||
|
||||
if (hitResult.getType() == HitResult.Type.BLOCK) {
|
||||
return hitResult.getBlockPos();
|
||||
}
|
||||
|
||||
return new BlockPos(player.getBlockPos());
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
107
src/main/resources/assets/sit-oth3r/lang/en_us.json
Normal file
|
@ -0,0 +1,107 @@
|
|||
{
|
||||
"category.sit!": "Sit!",
|
||||
|
||||
"config.entry.exclusion": "Put a `!` in front of a entry to exclude it!",
|
||||
"config.entry.example": "Entry example: %s",
|
||||
|
||||
"config.server": "Server Config",
|
||||
"config.server.description": "Configures the server side settings.",
|
||||
|
||||
"config.server.lang": "Language",
|
||||
"config.server.lang.description": "The language used for the Sit! mod.",
|
||||
|
||||
"config.server.keep-active": "Keep Active",
|
||||
"config.server.keep-active.description": "Toggles if the Sit! entity should stay, even if the player / server is offline. \n When false, the player will not be sitting when logging back in.",
|
||||
|
||||
"config.server.sit-while-seated": "Sit While Seated",
|
||||
"config.server.sit-while-seated.description": "Toggles the ability to sit on another Sit! block while already sitting.",
|
||||
|
||||
"config.server.preset-blocks": "Preset Blocks",
|
||||
"config.server.preset-blocks.description": "Toggles for the default Sit! blocks.",
|
||||
"config.server.preset-blocks.stairs": "Stairs",
|
||||
"config.server.preset-blocks.slabs": "Slabs",
|
||||
"config.server.preset-blocks.carpets": "Carpets",
|
||||
"config.server.preset-blocks.full-blocks": "Full Blocks",
|
||||
|
||||
"config.server.custom-enabled": "Custom",
|
||||
"config.server.custom-enabled.description": "Toggles the use of custom blocks for sitting.",
|
||||
|
||||
"config.server.custom-blocks": "Custom Blocks",
|
||||
"config.server.custom-blocks.description": "The list of custom sitting blocks.",
|
||||
|
||||
"config.server.custom-block.block-ids": "Block IDs",
|
||||
"config.server.custom-block.block-ids.description": "The block id(s) for the custom sitting block.",
|
||||
"config.server.custom-block.block-tags": "Block Tags",
|
||||
"config.server.custom-block.block-tags.description": "The block tag(s) for the custom sitting block.",
|
||||
"config.server.custom-block.blockstates": "Blockstates",
|
||||
"config.server.custom-block.blockstates.description": "The blockstates that the block must have to be a custom sitting block.",
|
||||
"config.server.custom-block.sitting-height": "Sitting Height",
|
||||
"config.server.custom-block.sitting-height.description": "The player sitting height of the custom block.",
|
||||
|
||||
"config.server.blacklisted-blocks": "Blacklisted Blocks",
|
||||
"config.server.blacklisted-blocks.description": "The list of blocks that arent allowed to be sat on.",
|
||||
|
||||
|
||||
"config.sitting": "Sitting Config",
|
||||
"config.sitting.description": "Configures the sitting ability, on the server each player can have their own sitting config when they use the mod.",
|
||||
|
||||
"config.sitting.enabled": "Enabled",
|
||||
"config.sitting.enabled.description": "Toggles the ability to sit.",
|
||||
|
||||
"config.sitting.hand-sitting": "Hand Sitting",
|
||||
"config.sitting.hand-sitting.description": "Toggles the ability to sit using hand interactions.",
|
||||
|
||||
"config.sitting.hand.main": "Main Hand",
|
||||
"config.sitting.hand.main.description": "main hand",
|
||||
"config.sitting.hand.off": "Off Hand",
|
||||
"config.sitting.hand.off.description": "off hand",
|
||||
"config.sitting.hand.description": "Configures %s sitting settings.",
|
||||
|
||||
"config.sitting.hand.requirement": "Sitting Requirement",
|
||||
"config.sitting.hand.requirement.description": "The hand requirement to sit. Eg, if EMPTY, the hand has to be empty",
|
||||
"config.sitting.hand.requirement.description.none": "No requirement to sit.",
|
||||
"config.sitting.hand.requirement.description.empty": "The hand has to be empty to sit.",
|
||||
"config.sitting.hand.requirement.description.filter": "The hand can only sit if the item in the hand matches one of the filters.",
|
||||
|
||||
"config.sitting.hand.filter": "Filter",
|
||||
"config.sitting.hand.filter.description": "The list of items for the filter hand requirement.",
|
||||
|
||||
"config.sitting.hand.filter.block": "Blocks",
|
||||
"config.sitting.hand.filter.block.description": "The blocks default filter.",
|
||||
"config.sitting.hand.filter.food": "Foods",
|
||||
"config.sitting.hand.filter.food.description": "The foods default filter.",
|
||||
"config.sitting.hand.filter.usable": "Usables",
|
||||
"config.sitting.hand.filter.usable.description": "The usables default filter. (Tridents, Shields, Bows)",
|
||||
|
||||
"config.sitting.hand.filter.custom-items": "Custom Items",
|
||||
"config.sitting.hand.filter.custom-items.description": "A list of custom items to add to the filter.",
|
||||
"config.sitting.hand.filter.custom-tags": "Custom Tags",
|
||||
"config.sitting.hand.filter.custom-tags.description": "A list of custom item tags to add to the filter.",
|
||||
|
||||
"sit!.chat.toggle_sit": "%s Sitting!",
|
||||
"sit!.chat.toggle_sit.on": "Enabled",
|
||||
"sit!.chat.toggle_sit.off": "Disabled",
|
||||
"sit!.chat.unsupported": "Sit! is not available on this server.",
|
||||
"sit!.chat.reloaded": "Reloaded the config!",
|
||||
"sit!.chat.purged": "Purged all loaded Sit! entities! %s",
|
||||
"sit!.chat.purged.total": "(%s removed)",
|
||||
|
||||
"key.sit!.toggle": "Toggle Sitting",
|
||||
"key.sit!.sit": "Sit",
|
||||
"key.sit!.config": "Open Config",
|
||||
|
||||
"sit!.screen.config": "Sit! Config",
|
||||
"sit!.gui.button.file": "Open File",
|
||||
"sit!.gui.button.folder": "Open Folder",
|
||||
"sit!.gui.button.reset": "Reset",
|
||||
"sit!.gui.button.issues": "Issues",
|
||||
"sit!.gui.button.donate": "Donate",
|
||||
"sit!.gui.button.revert": "Revert Changes",
|
||||
"sit!.gui.button.save": "Save and Close",
|
||||
"sit!.gui.button.website": "Website",
|
||||
|
||||
"sit!.console.connected": "Connected to Sit! server: %s",
|
||||
"sit!.console.player_settings": "Received custom sitting settings from %s!",
|
||||
|
||||
"modmenu.descriptionTranslation.sit-oth3r": "Adds sitting to minecraft! Endless customizability for hand restrictions and sittable blocks.\n Players can have their own sitting settings when using the Sit! client on the server!"
|
||||
}
|
83
src/main/resources/assets/sit-oth3r/lang/it_it.json
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"category.sit!": "Sit!",
|
||||
"config.entry.exclusion": "Metti un `!` davanti a un campo per escluderlo!",
|
||||
"config.entry.example": "Esempio campo: %s",
|
||||
"config.server": "Configura Server",
|
||||
"config.server.description": "Configura altre impostazioni del server.",
|
||||
"config.server.lang": "Lingua",
|
||||
"config.server.lang.description": "La lingua usata dalla mod Sit!.",
|
||||
"config.server.keep-active": "Mantieni Attivo",
|
||||
"config.server.keep-active.description": "Decidi se l'entità Sit! deve restare, anche se il giocatore / server è offline.",
|
||||
"config.server.sit-while-seated": "Siediti mentre sei seduto",
|
||||
"config.server.sit-while-seated.description": "Decidi se togliere la possibilità di sedersi a un blocco Sit! mentre ti siedi.",
|
||||
"config.server.preset-blocks": "Preset Blocks",
|
||||
"config.server.preset-blocks.description": "Attiva per i blocchi Sit! default.",
|
||||
"config.server.preset-blocks.stairs": "Scale",
|
||||
"config.server.preset-blocks.slabs": "Mezzi blocchi",
|
||||
"config.server.preset-blocks.carpets": "Tappeti",
|
||||
"config.server.preset-blocks.full-blocks": "Blocchi interi",
|
||||
"config.server.custom-enabled": "Custom",
|
||||
"config.server.custom-enabled.description": "Attiva l'uso di blocchi custom per sederti.",
|
||||
"config.server.custom-blocks": "Blocchi Custom",
|
||||
"config.server.custom-blocks.description": "La lista dei blocchi custom per sedersi.",
|
||||
"config.server.custom-block.block-ids": "ID dei blocchi",
|
||||
"config.server.custom-block.block-ids.description": "L'id dei blocchi custom per sedersi.",
|
||||
"config.server.custom-block.block-tags": "Tag dei blocchi",
|
||||
"config.server.custom-block.block-tags.description": "I tag dei blocchi custom per sedersi.",
|
||||
"config.server.custom-block.blockstates": "Stato dei blocchi",
|
||||
"config.server.custom-block.blockstates.description": "Lo stato che un blocco deve avere per potercisi sedere.",
|
||||
"config.server.custom-block.sitting-height": "Altezza per sedersi",
|
||||
"config.server.custom-block.sitting-height.description": "L'altezza del giocatore per sedersi sul blocco custom.",
|
||||
"config.server.blacklisted-blocks": "Blocchi Blacklistati",
|
||||
"config.server.blacklisted-blocks.description": "La lista dei blocchi su cui non puoi sederti.",
|
||||
"config.sitting": "Configura Sedersi",
|
||||
"config.sitting.description": "Configura l'abilità di sedersi, sul server ogni giocatore può avere la propria configurazione quando usano la mod.",
|
||||
"config.sitting.enabled": "Attivato",
|
||||
"config.sitting.enabled.description": "Attiva o disattiva l'abilità di sedersi.",
|
||||
"config.sitting.hand-sitting": "Siediti con la mano",
|
||||
"config.sitting.hand-sitting.description": "Attiva l'abilità di sedersi usando l'interazione della mano.",
|
||||
"config.sitting.hand.main": "Mano principale",
|
||||
"config.sitting.hand.main.description": "mano principale",
|
||||
"config.sitting.hand.off": "Seconda mano",
|
||||
"config.sitting.hand.off.description": "seconda mano",
|
||||
"config.sitting.hand.description": "Configura %s impostazioni per sedersi.",
|
||||
"config.sitting.hand.requirement": "Requisiti per Sedersi",
|
||||
"config.sitting.hand.requirement.description": "I requisiti per sedersi. Ad esempio, se EMPTY, la mano deve essere libera",
|
||||
"config.sitting.hand.requirement.description.none": "Nessun requisito per sedersi.",
|
||||
"config.sitting.hand.requirement.description.empty": "La mano deve essere libera per sedersi.",
|
||||
"config.sitting.hand.requirement.description.filter": "La mano può farti sedere solo se il blocco è in un filtro.",
|
||||
"config.sitting.hand.filter": "Filtro",
|
||||
"config.sitting.hand.filter.description": "La lista di oggetti nel filtro della mano.",
|
||||
"config.sitting.hand.filter.block": "Blocchi",
|
||||
"config.sitting.hand.filter.block.description": "Filtro default per i blocchi.",
|
||||
"config.sitting.hand.filter.food": "Cibi",
|
||||
"config.sitting.hand.filter.food.description": "Il filtro dei cibi default.",
|
||||
"config.sitting.hand.filter.usable": "Usabili",
|
||||
"config.sitting.hand.filter.usable.description": "La lista del filtro Usabili. (Tridenti, Scudi, Archi)",
|
||||
"config.sitting.hand.filter.custom-items": "Oggetti custom",
|
||||
"config.sitting.hand.filter.custom-items.description": "Una lista degli oggetti custom da aggiungere al filtro.",
|
||||
"config.sitting.hand.filter.custom-tags": "Tag Custom",
|
||||
"config.sitting.hand.filter.custom-tags.description": "Una lista di tag di oggetti custom da aggiungere al filtro.",
|
||||
"sit!.chat.toggle_sit": "%s Sedersi!",
|
||||
"sit!.chat.toggle_sit.on": "Attivato",
|
||||
"sit!.chat.toggle_sit.off": "Disattivato",
|
||||
"sit!.chat.unsupported": "Sit! non è disponibile in questo server.",
|
||||
"sit!.chat.reloaded": "Ricaricata la configurazione!",
|
||||
"sit!.chat.purged": "Rimosse tutte le entità Sit! caricate! %s",
|
||||
"sit!.chat.purged.total": "(%s rimosso)",
|
||||
"key.sit!.toggle": "Attiva Sedersi",
|
||||
"key.sit!.sit": "Siediti",
|
||||
"key.sit!.config": "Apri Impostazioni",
|
||||
"sit!.screen.config": "Impostazioni Sit!",
|
||||
"sit!.gui.button.file": "Apri File",
|
||||
"sit!.gui.button.folder": "Apri Cartella",
|
||||
"sit!.gui.button.reset": "Resetta",
|
||||
"sit!.gui.button.issues": "Problemi",
|
||||
"sit!.gui.button.donate": "Dona",
|
||||
"sit!.gui.button.revert": "Annulla i Cambiamenti",
|
||||
"sit!.gui.button.save": "Salva ed Esci",
|
||||
"sit!.gui.button.website": "Sito Web",
|
||||
"sit!.console.connected": "Connesso al server Sit!: %s",
|
||||
"sit!.console.player_settings": "Ricevute impostazioni custom da %s!",
|
||||
"modmenu.descriptionTranslation.sit-oth3r": "Aggiunge l'abilità di sedersi a minecraft! infiniti modi di personalizzare le restrizioni della mano e dei blocchi su cui puoi sederti.\nI giocatori possono avere le loro impostazioni per sedersi quando usano un client Sit! nel server!"
|
||||
}
|
83
src/main/resources/assets/sit-oth3r/lang/pt_br.json
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"category.sit!": "Sit!",
|
||||
"config.entry.exclusion": "Coloque um `!` antes de uma entrada para excluí-la!",
|
||||
"config.entry.example": "Exemplo de entrada: %s",
|
||||
"config.server": "Configuração do Servidor",
|
||||
"config.server.description": "Configure as configurações do lado do servidor.",
|
||||
"config.server.lang": "Idioma",
|
||||
"config.server.lang.description": "A linguagem utilizada para o mod Sit!",
|
||||
"config.server.keep-active": "Manter Ativo",
|
||||
"config.server.keep-active.description": "Ativa ou desativa se a entidade Sit! deve permanecer, mesmo que o jogador ou o servidor esteja offline. \nQuando desativado, o jogador não estará sentado ao fazer login novamente.",
|
||||
"config.server.sit-while-seated": "Sentar Enquanto Está Sentado",
|
||||
"config.server.sit-while-seated.description": "Ativa ou desativa a capacidade de sentar em outro bloco Sit! enquanto já está sentado.",
|
||||
"config.server.preset-blocks": "Blocos predefinidos",
|
||||
"config.server.preset-blocks.description": "Ativa ou desativa os blocos Sit! padrão.",
|
||||
"config.server.preset-blocks.stairs": "Escadas",
|
||||
"config.server.preset-blocks.slabs": "Lajes",
|
||||
"config.server.preset-blocks.carpets": "Tapetes",
|
||||
"config.server.preset-blocks.full-blocks": "Blocos Inteiros",
|
||||
"config.server.custom-enabled": "Customizado",
|
||||
"config.server.custom-enabled.description": "Ativa ou desativa o uso de blocos personalizados para sentar.",
|
||||
"config.server.custom-blocks": "Blocos Personalizados",
|
||||
"config.server.custom-blocks.description": "A lista de blocos personalizados para sentar.",
|
||||
"config.server.custom-block.block-ids": "IDs dos Blocos",
|
||||
"config.server.custom-block.block-ids.description": "O(s) ID(s) do bloco para o bloco personalizado de sentar.",
|
||||
"config.server.custom-block.block-tags": "Tags dos Blocos",
|
||||
"config.server.custom-block.block-tags.description": "A(s) tag(s) do bloco para o bloco personalizado de sentar.",
|
||||
"config.server.custom-block.blockstates": "Estados do bloco",
|
||||
"config.server.custom-block.blockstates.description": "Os estados do bloco que o bloco deve ter para ser um bloco personalizado de sentar.",
|
||||
"config.server.custom-block.sitting-height": "Altura de Sentar",
|
||||
"config.server.custom-block.sitting-height.description": "A altura de sentar do jogador para o bloco personalizado.",
|
||||
"config.server.blacklisted-blocks": "Blocos Bloqueados",
|
||||
"config.server.blacklisted-blocks.description": "A lista de blocos nos quais não é permitido sentar.",
|
||||
"config.sitting": "Configuração de Sentar",
|
||||
"config.sitting.description": "Configura a habilidade de sentar; no servidor, cada jogador pode ter sua própria configuração de sentar ao usar o mod.",
|
||||
"config.sitting.enabled": "Habilitado",
|
||||
"config.sitting.enabled.description": "Alterna a capacidade de sentar.",
|
||||
"config.sitting.hand-sitting": "Sentar com as Mãos",
|
||||
"config.sitting.hand-sitting.description": "Alterna a capacidade de sentar usando interações com a mão.",
|
||||
"config.sitting.hand.main": "Mão Principal",
|
||||
"config.sitting.hand.main.description": "mão principal",
|
||||
"config.sitting.hand.off": "Mão Secundária",
|
||||
"config.sitting.hand.off.description": "mão secundária",
|
||||
"config.sitting.hand.description": "Configura as configurações de sentar do %s.",
|
||||
"config.sitting.hand.requirement": "Requisito para Sentar",
|
||||
"config.sitting.hand.requirement.description": "A exigência da mão para sentar. Por exemplo, se for VAZIA, a mão deve estar vazia.",
|
||||
"config.sitting.hand.requirement.description.none": "Nenhum requisito para sentar.",
|
||||
"config.sitting.hand.requirement.description.empty": "A mão tem que estar vazia para sentar.",
|
||||
"config.sitting.hand.requirement.description.filter": "A mão só pode sentar se o item na mão corresponder a um dos filtros.",
|
||||
"config.sitting.hand.filter": "Filtro",
|
||||
"config.sitting.hand.filter.description": "A lista de itens para a exigência de filtro da mão.",
|
||||
"config.sitting.hand.filter.block": "Blocos",
|
||||
"config.sitting.hand.filter.block.description": "O filtro padrão dos blocos.",
|
||||
"config.sitting.hand.filter.food": "Alimentos",
|
||||
"config.sitting.hand.filter.food.description": "O filtro padrão dos alimentos.",
|
||||
"config.sitting.hand.filter.usable": "Usáveis",
|
||||
"config.sitting.hand.filter.usable.description": "O filtro padrão dos itens utilizáveis. (Tridentes, Escudos, Arcos)",
|
||||
"config.sitting.hand.filter.custom-items": "Itens Customizados",
|
||||
"config.sitting.hand.filter.custom-items.description": "Uma lista de itens customizados para adicionar ao filtro.",
|
||||
"config.sitting.hand.filter.custom-tags": "Tags Customizadas",
|
||||
"config.sitting.hand.filter.custom-tags.description": "Uma lista de tags de itens customizados para adicionar ao filtro.",
|
||||
"sit!.chat.toggle_sit": "%s Sentado!",
|
||||
"sit!.chat.toggle_sit.on": "Habilitado",
|
||||
"sit!.chat.toggle_sit.off": "Desabilitado",
|
||||
"sit!.chat.unsupported": "Sit! não está disponível neste servidor.",
|
||||
"sit!.chat.reloaded": "Configuração recarregada!",
|
||||
"sit!.chat.purged": "Eliminou todas as entidades Sit! carregadas! %s",
|
||||
"sit!.chat.purged.total": "(%s removido)",
|
||||
"key.sit!.toggle": "Alternar Sentar",
|
||||
"key.sit!.sit": "Sentar",
|
||||
"key.sit!.config": "Abrir Configuração",
|
||||
"sit!.screen.config": "Configuração do Sit!",
|
||||
"sit!.gui.button.file": "Abrir Arquivo",
|
||||
"sit!.gui.button.folder": "Abrir Pasta",
|
||||
"sit!.gui.button.reset": "Reiniciar",
|
||||
"sit!.gui.button.issues": "Problemas",
|
||||
"sit!.gui.button.donate": "Doar",
|
||||
"sit!.gui.button.revert": "Reverter Alterações",
|
||||
"sit!.gui.button.save": "Salvar e Fechar",
|
||||
"sit!.gui.button.website": "Website",
|
||||
"sit!.console.connected": "Conectado ao servidor Sit!: %s",
|
||||
"sit!.console.player_settings": "Recebidas configurações de sentar personalizadas de %s!",
|
||||
"modmenu.descriptionTranslation.sit-oth3r": "Adiciona a função de sentar ao Minecraft! Personalização infinita para restrições de mão e blocos onde é possível sentar. Os jogadores podem ter suas próprias configurações de sentar ao usar o cliente Sit! no servidor!"
|
||||
}
|
83
src/main/resources/assets/sit-oth3r/lang/tr_tr.json
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"category.sit!": "Sit!",
|
||||
"config.entry.exclusion": "Bir girdiyi hariç tutmak için önüne '!' koyun!",
|
||||
"config.entry.example": "Girdi örneği: %s",
|
||||
"config.server": "Sunucu Ayarları",
|
||||
"config.server.description": "Sunucu tarafında ayarları yapılandırır.",
|
||||
"config.server.lang": "Dil",
|
||||
"config.server.lang.description": "Sit! modu için kullanılan dil.",
|
||||
"config.server.keep-active": "Aktif Tut",
|
||||
"config.server.keep-active.description": "Oyuncu / sunucu offline olduğunda, varlığın aynı halde kalıp kalmayacağını açar kapatır.\nYanlış olarak ayarlandığında, oyuncu giriş yaptığında oturuyor halde olmayacaktır.",
|
||||
"config.server.sit-while-seated": "Binerken otur",
|
||||
"config.server.sit-while-seated.description": "Halihazırda oturuyorken başka bir Sit! bloğuna oturma özelliğini açar kapatır.",
|
||||
"config.server.preset-blocks": "Önceden Ayarlı Bloklar",
|
||||
"config.server.preset-blocks.description": "Varsayılan Sit! bloklarını açar kapatır.",
|
||||
"config.server.preset-blocks.stairs": "Merdivenler",
|
||||
"config.server.preset-blocks.slabs": "Basamaklar",
|
||||
"config.server.preset-blocks.carpets": "Halılar",
|
||||
"config.server.preset-blocks.full-blocks": "Tam Bloklar",
|
||||
"config.server.custom-enabled": "Özel",
|
||||
"config.server.custom-enabled.description": "Oturma için özel blokların kullanımını açar kapatır.",
|
||||
"config.server.custom-blocks": "Özel Bloklar",
|
||||
"config.server.custom-blocks.description": "Özel oturma bloklarının listesi.",
|
||||
"config.server.custom-block.block-ids": "Blok ID'leri",
|
||||
"config.server.custom-block.block-ids.description": "Özel oturma bloğu için blok id(leri).",
|
||||
"config.server.custom-block.block-tags": "Blok Etiketleri",
|
||||
"config.server.custom-block.block-tags.description": "Özel oturma bloğu için blok etiket(leri).",
|
||||
"config.server.custom-block.blockstates": "Blok durumu",
|
||||
"config.server.custom-block.blockstates.description": "Bloğun özel oturma bloğu olması gerektiğini belirten blok durumu.",
|
||||
"config.server.custom-block.sitting-height": "Oturma Yüksekliği",
|
||||
"config.server.custom-block.sitting-height.description": "Özel blok için oyuncunun oturma yüksekliği.",
|
||||
"config.server.blacklisted-blocks": "Karalistedeki Bloklar",
|
||||
"config.server.blacklisted-blocks.description": "Oturulmasına izin verilmeyen bloklar listesi.",
|
||||
"config.sitting": "Oturma Ayarları",
|
||||
"config.sitting.description": "Oturma özelliğini yapılandırır, sunucuda her oyuncu modu kullandığında kendi oturma yapılandırmasına sahip olabilir.",
|
||||
"config.sitting.enabled": "Aktif",
|
||||
"config.sitting.enabled.description": "Oturma özelliğini açar kapatır.",
|
||||
"config.sitting.hand-sitting": "El ile Oturma",
|
||||
"config.sitting.hand-sitting.description": "El etkileşimlerini kullanarak oturma özelliğini açar kapatır.",
|
||||
"config.sitting.hand.main": "Ana El",
|
||||
"config.sitting.hand.main.description": "oyuncunun kullandığı ana el",
|
||||
"config.sitting.hand.off": "Diğer El",
|
||||
"config.sitting.hand.off.description": "oyuncunun kullandığı diğer el",
|
||||
"config.sitting.hand.description": "%s oturma ayarlarını ayarlar.",
|
||||
"config.sitting.hand.requirement": "Oturma Gereksinimi",
|
||||
"config.sitting.hand.requirement.description": "Oturmak için el gereksinimi. Ör: eğer BOŞ ise oturmak için elin boş olması gerek",
|
||||
"config.sitting.hand.requirement.description.none": "Oturmak için gereksinim yok.",
|
||||
"config.sitting.hand.requirement.description.empty": "Oturmak için elin boş olması gerek.",
|
||||
"config.sitting.hand.requirement.description.filter": "El ile oturmak için, eldeki öğe filtrelerden biriyle eşleşmelidir.",
|
||||
"config.sitting.hand.filter": "Filtre",
|
||||
"config.sitting.hand.filter.description": "El gereksinimi için filtrelenecek eşyaların listesi.",
|
||||
"config.sitting.hand.filter.block": "Bloklar",
|
||||
"config.sitting.hand.filter.block.description": "Blokların varsayılan filtresi.",
|
||||
"config.sitting.hand.filter.food": "Yiyecekler",
|
||||
"config.sitting.hand.filter.food.description": "Yiyeceklerin varsayılan filtresi.",
|
||||
"config.sitting.hand.filter.usable": "Kullanılabilenler",
|
||||
"config.sitting.hand.filter.usable.description": "Kullanılabilenlerin varsayılan listesi. (Mızraklar, Kalkanlar, Yaylar)",
|
||||
"config.sitting.hand.filter.custom-items": "Özel Eşyalar",
|
||||
"config.sitting.hand.filter.custom-items.description": "Filtreye eklenecek özel eşyaların listesi.",
|
||||
"config.sitting.hand.filter.custom-tags": "Özel Etiketler",
|
||||
"config.sitting.hand.filter.custom-tags.description": "Filtreye eklenecek özel etiketlerin listesi.",
|
||||
"sit!.chat.toggle_sit": "%s oturuyor!",
|
||||
"sit!.chat.toggle_sit.on": "Aktif",
|
||||
"sit!.chat.toggle_sit.off": "Pasif",
|
||||
"sit!.chat.unsupported": "Sunucuda Sit! modu mevcut değil.",
|
||||
"sit!.chat.reloaded": "Ayarlamalar yeniden yüklendi!",
|
||||
"sit!.chat.purged": "Yüklenmiş bütün Sit! canlıları yok edildi! %s",
|
||||
"sit!.chat.purged.total": "(%s kaldırıldı)",
|
||||
"key.sit!.toggle": "Oturmayı Aç / Kapat",
|
||||
"key.sit!.sit": "Otur",
|
||||
"key.sit!.config": "Ayarlandırmaları aç",
|
||||
"sit!.screen.config": "Sit! Ayarlandırmaları",
|
||||
"sit!.gui.button.file": "Dosya Aç",
|
||||
"sit!.gui.button.folder": "Klasörü Aç",
|
||||
"sit!.gui.button.reset": "Sıfırla",
|
||||
"sit!.gui.button.issues": "Sorunlar",
|
||||
"sit!.gui.button.donate": "Bağış yap",
|
||||
"sit!.gui.button.revert": "Değişiklikleri Geri Al",
|
||||
"sit!.gui.button.save": "Kaydet ve Kapat",
|
||||
"sit!.gui.button.website": "İnternet Sitesi",
|
||||
"sit!.console.connected": "Sit! sunucusuna bağlanıldı: %s",
|
||||
"sit!.console.player_settings": "Özel oturma ayarları %s alındı!",
|
||||
"modmenu.descriptionTranslation.sit-oth3r": "Minecraft'a oturmayı ekler! El kısıtlamaları ve oturulabilir bloklar için sınırsız özelleştirme.\nOyuncular Sit! modunu kendi client'inde kullanırken sunucuda kendi oturma ayarlarına sahip olabilirler!"
|
||||
}
|
83
src/main/resources/assets/sit-oth3r/lang/zh_tw.json
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"category.sit!": "Sit!",
|
||||
"config.entry.exclusion": "在條目前方加上 `!` 以排除它!",
|
||||
"config.entry.example": "條目範例: %s",
|
||||
"config.server": "伺服器設定",
|
||||
"config.server.description": "設定伺服器端的設定。",
|
||||
"config.server.lang": "語言",
|
||||
"config.server.lang.description": "Sit! 模組使用的語言。",
|
||||
"config.server.keep-active": "保持活動",
|
||||
"config.server.keep-active.description": "切換坐下! 實體是否應該保留,即使玩家/伺服器離線。 \n 當設定為 false 時,玩家在重新登入時將不會坐下。",
|
||||
"config.server.sit-while-seated": "坐下時坐下",
|
||||
"config.server.sit-while-seated.description": "切換在已經坐下的情況下,是否能夠坐在另一個坐下! 方塊上的能力。",
|
||||
"config.server.preset-blocks": "預設方塊",
|
||||
"config.server.preset-blocks.description": "預設 Sit! 方塊的切換。",
|
||||
"config.server.preset-blocks.stairs": "階梯",
|
||||
"config.server.preset-blocks.slabs": "半磚",
|
||||
"config.server.preset-blocks.carpets": "地毯",
|
||||
"config.server.preset-blocks.full-blocks": "完整方塊",
|
||||
"config.server.custom-enabled": "自訂",
|
||||
"config.server.custom-enabled.description": "切換是否使用自訂方塊來坐下。",
|
||||
"config.server.custom-blocks": "自訂方塊",
|
||||
"config.server.custom-blocks.description": "自訂坐下方塊的清單。",
|
||||
"config.server.custom-block.block-ids": "方塊 ID",
|
||||
"config.server.custom-block.block-ids.description": "自訂坐下方塊的方塊 ID。",
|
||||
"config.server.custom-block.block-tags": "方塊標籤",
|
||||
"config.server.custom-block.block-tags.description": "自訂坐下方塊的方塊標籤。",
|
||||
"config.server.custom-block.blockstates": "方塊狀態",
|
||||
"config.server.custom-block.blockstates.description": "方塊必須具備的方塊狀態,才能成為自訂坐下方塊。",
|
||||
"config.server.custom-block.sitting-height": "坐下高度",
|
||||
"config.server.custom-block.sitting-height.description": "自訂方塊的玩家坐下高度。",
|
||||
"config.server.blacklisted-blocks": "黑名單方塊",
|
||||
"config.server.blacklisted-blocks.description": "不允許坐下的方塊清單。",
|
||||
"config.sitting": "坐下設定",
|
||||
"config.sitting.description": "設定坐下能力,在伺服器上,每個玩家在使用模組時都可以擁有自己的坐下設定。",
|
||||
"config.sitting.enabled": "啟用",
|
||||
"config.sitting.enabled.description": "切換坐下能力。",
|
||||
"config.sitting.hand-sitting": "手持坐下",
|
||||
"config.sitting.hand-sitting.description": "切換使用手部互動來坐下的能力。",
|
||||
"config.sitting.hand.main": "慣用手",
|
||||
"config.sitting.hand.main.description": "慣用手",
|
||||
"config.sitting.hand.off": "非慣用手",
|
||||
"config.sitting.hand.off.description": "非慣用手",
|
||||
"config.sitting.hand.description": "設定 %s 坐下設定。",
|
||||
"config.sitting.hand.requirement": "坐下需求",
|
||||
"config.sitting.hand.requirement.description": "坐下的手部需求。例如,如果設定為 EMPTY,則手部必須是空的",
|
||||
"config.sitting.hand.requirement.description.none": "沒有坐下需求。",
|
||||
"config.sitting.hand.requirement.description.empty": "手部必須是空的才能坐下。",
|
||||
"config.sitting.hand.requirement.description.filter": "只有當手持的物品符合其中一個篩選器時,才能坐下。",
|
||||
"config.sitting.hand.filter": "篩選器",
|
||||
"config.sitting.hand.filter.description": "篩選器手部需求的物品清單。",
|
||||
"config.sitting.hand.filter.block": "方塊",
|
||||
"config.sitting.hand.filter.block.description": "方塊的預設篩選器。",
|
||||
"config.sitting.hand.filter.food": "食物",
|
||||
"config.sitting.hand.filter.food.description": "食物的預設篩選器。",
|
||||
"config.sitting.hand.filter.usable": "可使用物品",
|
||||
"config.sitting.hand.filter.usable.description": "可使用物品的預設篩選器。(三叉戟、盾牌、弓)",
|
||||
"config.sitting.hand.filter.custom-items": "自訂物品",
|
||||
"config.sitting.hand.filter.custom-items.description": "要新增到篩選器的自訂物品清單。",
|
||||
"config.sitting.hand.filter.custom-tags": "自訂標籤",
|
||||
"config.sitting.hand.filter.custom-tags.description": "要新增到篩選器的自訂物品標籤清單。",
|
||||
"sit!.chat.toggle_sit": "%s 坐下!",
|
||||
"sit!.chat.toggle_sit.on": "已啟用",
|
||||
"sit!.chat.toggle_sit.off": "已停用",
|
||||
"sit!.chat.unsupported": "此伺服器不支援坐下! 功能。",
|
||||
"sit!.chat.reloaded": "設定已重新載入!",
|
||||
"sit!.chat.purged": "已清除所有已載入的 Sit! 實體! %s",
|
||||
"sit!.chat.purged.total": "(已移除 %s 個)",
|
||||
"key.sit!.toggle": "調整設定",
|
||||
"key.sit!.sit": "坐下",
|
||||
"key.sit!.config": "開啟設定",
|
||||
"sit!.screen.config": "坐下! 設定",
|
||||
"sit!.gui.button.file": "開啟檔案",
|
||||
"sit!.gui.button.folder": "開啟資料夾",
|
||||
"sit!.gui.button.reset": "重置",
|
||||
"sit!.gui.button.issues": "問題",
|
||||
"sit!.gui.button.donate": "贊助",
|
||||
"sit!.gui.button.revert": "還原變更",
|
||||
"sit!.gui.button.save": "儲存並關閉",
|
||||
"sit!.gui.button.website": "網站",
|
||||
"sit!.console.connected": "已連線至 Sit! 伺服器: %s",
|
||||
"sit!.console.player_settings": "已從 %s 收到自訂坐下設定!",
|
||||
"modmenu.descriptionTranslation.sit-oth3r": "在 Minecraft 中加入坐下的動作!可自訂無盡的動作限制和可坐下的方塊。\n當玩家在伺服器上使用 Sit! 用戶端時,可以擁有自己的坐下設定!"
|
||||
}
|
BIN
src/main/resources/assets/sit-oth3r/textures/gui/banner.png
Normal file
After Width: | Height: | Size: 278 KiB |
BIN
src/main/resources/assets/sit-oth3r/textures/gui/fox.png
Normal file
After Width: | Height: | Size: 740 KiB |
After Width: | Height: | Size: 241 B |
After Width: | Height: | Size: 179 B |
After Width: | Height: | Size: 210 B |
After Width: | Height: | Size: 221 B |
After Width: | Height: | Size: 300 B |
After Width: | Height: | Size: 985 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"config.sit.empty": "Empty",
|
||||
"config.sit.restrictive": "Restrictive",
|
||||
"config.sit.none": "None",
|
||||
"config.sit.category.general": "General",
|
||||
"config.sit.category.general.tooltip": "General settings",
|
||||
"config.sit.category.main_hand": "Main Hand",
|
||||
"config.sit.category.main_hand.tooltip": "Main hand settings",
|
||||
"config.sit.category.off_hand": "Off Hand",
|
||||
"config.sit.category.off_hand.tooltip": "Off hand settings",
|
||||
"config.sit.general.keep_active": "Keep Active",
|
||||
"config.sit.general.keep_active.description": "Keeps the entities active even when logging off / shutting down",
|
||||
"config.sit.general.sittable": "Sittable Blocks",
|
||||
"config.sit.general.sittable.description": "Toggle the ability to sit on different block types.",
|
||||
"config.sit.general.sit_while_seated": "Sit While Seated",
|
||||
"config.sit.general.sit_while_seated.description": "Toggle the ability to sit on other blocks while already being seated on one.",
|
||||
"config.sit.general.sittable.stairs": "Stairs",
|
||||
"config.sit.general.sittable.slabs": "Slabs",
|
||||
"config.sit.general.sittable.carpets": "Carpets",
|
||||
"config.sit.general.sittable.full_blocks": "Full Blocks",
|
||||
"config.sit.general.sittable.custom": "Custom",
|
||||
"config.sit.general.sittable.custom.description": "Enables adding custom blocks to sit on.",
|
||||
"config.sit.general.sittable_blocks": "Custom Sittable Blocks",
|
||||
"config.sit.general.sittable_blocks.description": "Add custom sittable blocks!",
|
||||
"config.sit.general.sittable_blocks.description_2": "Example: %s",
|
||||
"config.sit.general.sittable_blocks.description_4": "First entry: custom block",
|
||||
"config.sit.general.sittable_blocks.description_5": "Second entry: sitting height (number from 0-1 eg 0.52)",
|
||||
"config.sit.general.sittable_blocks.description_6": "Third entry: hitbox size (where the player spawns above the entity when dismounting)",
|
||||
"config.sit.general.sittable_blocks.description_7": "Fourth entry (optional): required blockstate to sit (Put a \"!\" to exclude blockstates)",
|
||||
"config.sit.general.sittable_blocks.description_8": "Separate different entries with \"|\"!",
|
||||
"config.sit.hand": "Hand Settings",
|
||||
"config.sit.hand.requirements": "Requirements",
|
||||
"config.sit.hand.requirements.description": "Hand requirements for sitting.",
|
||||
"config.sit.hand.requirements.description_2": "Empty = hand has to be empty",
|
||||
"config.sit.hand.requirements.description_3": "Restrictive = set restrictions for hand state",
|
||||
"config.sit.hand.requirements.description_4": "None = can sit whenever",
|
||||
"config.sit.hand.restrictions": "Restrictions",
|
||||
"config.sit.hand.restrictions.description": "Toggle preset hand restrictions for sitting.",
|
||||
"config.sit.hand.restrictions.blocks": "Blocks",
|
||||
"config.sit.hand.restrictions.food": "Food",
|
||||
"config.sit.hand.restrictions.usable": "Usable",
|
||||
"config.sit.hand.restrictions.usable.description": "eg. bows, tridents, shield",
|
||||
"config.sit.hand.whitelist": "Whitelist",
|
||||
"config.sit.hand.whitelist.description": "Make a custom whitelist for items that the player can use to sit with.",
|
||||
"config.sit.hand.blacklist": "Blacklist",
|
||||
"config.sit.hand.blacklist.description": "Make a custom blacklist for items that the player can't use to sit with.",
|
||||
"config.sit.hand.list.description": "Example: ",
|
||||
"config.sit.hand.list.description_2": "\"minecraft:torch\"",
|
||||
"key.sit.command.reloaded": "Reloaded the config!",
|
||||
"key.sit.command.purged": "Purged all active chair entities!"
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"config.sit.empty": "Vacía",
|
||||
"config.sit.restrictive": "Restrictiva",
|
||||
"config.sit.none": "Ninguna",
|
||||
"config.sit.category.general": "General",
|
||||
"config.sit.category.general.tooltip": "Configuración general",
|
||||
"config.sit.category.main_hand": "Mano principal",
|
||||
"config.sit.category.main_hand.tooltip": "Ajustes de la mano principal",
|
||||
"config.sit.category.off_hand": "Mano secundaria",
|
||||
"config.sit.category.off_hand.tooltip": "Ajustes de la mano secundaria",
|
||||
"config.sit.general.keep_active": "Mantener activo",
|
||||
"config.sit.general.keep_active.description": "Mantener entidades activas incluso al cerrar sesión o al apagar el servidor",
|
||||
"config.sit.general.sittable": "Bloques aptos para sentarse",
|
||||
"config.sit.general.sittable.description": "Activa/Desactiva los tipos de bloques en los que se puede sentar.",
|
||||
"config.sit.general.sit_while_seated": "Cambiar de asiento",
|
||||
"config.sit.general.sit_while_seated.description": "Permite cambiar de asiento estando sentado.",
|
||||
"config.sit.general.sittable.stairs": "Escaleras",
|
||||
"config.sit.general.sittable.slabs": "Losas",
|
||||
"config.sit.general.sittable.carpets": "Alfombras",
|
||||
"config.sit.general.sittable.full_blocks": "Bloques Enteros",
|
||||
"config.sit.general.sittable.custom": "Personalizados",
|
||||
"config.sit.general.sittable.custom.description": "Permitir sentarse en los bloques personalizados.",
|
||||
"config.sit.general.sittable_blocks": "Bloques Personalizados",
|
||||
"config.sit.general.sittable_blocks.description": "¡Añadir bloques personalizados para sentarse!",
|
||||
"config.sit.general.sittable_blocks.description_2": "Ejemplo: %s",
|
||||
"config.sit.general.sittable_blocks.description_4": "Primera entrada: bloque personalizado",
|
||||
"config.sit.general.sittable_blocks.description_5": "Segunda entrada: altura del asiento (número entre 0 y 1, por ejemplo, 0.52)",
|
||||
"config.sit.general.sittable_blocks.description_6": "Tercera entrada: Altura del bloque (en que altura del bloque el jugador aparece al pararse)",
|
||||
"config.sit.general.sittable_blocks.description_7": "Cuarta entrada (opcional): estado del bloque requerido para sentarse (Usa una exclamación (!) para excluir estados)",
|
||||
"config.sit.general.sittable_blocks.description_8": "¡Separar diferentes entradas con \"|\"!",
|
||||
"config.sit.hand": "Configuración de mano",
|
||||
"config.sit.hand.requirements": "Requisitos",
|
||||
"config.sit.hand.requirements.description": "Requisitos de la mano para sentarse.",
|
||||
"config.sit.hand.requirements.description_2": "Vacía = la mano debe estar vacía",
|
||||
"config.sit.hand.requirements.description_3": "Restrictiva = establecer restricciones para el estado de la mano",
|
||||
"config.sit.hand.requirements.description_4": "Ninguna = sin restricciones ni requisitos",
|
||||
"config.sit.hand.restrictions": "Restricciones",
|
||||
"config.sit.hand.restrictions.description": "Activa/Desactiva las restricciones preestablecidas de la mano para sentarse.",
|
||||
"config.sit.hand.restrictions.blocks": "Bloques",
|
||||
"config.sit.hand.restrictions.food": "Comida",
|
||||
"config.sit.hand.restrictions.usable": "Utilizable",
|
||||
"config.sit.hand.restrictions.usable.description": "Ejemplos: arcos, tridentes, escudo",
|
||||
"config.sit.hand.whitelist": "Lista blanca",
|
||||
"config.sit.hand.whitelist.description": "Crea una lista blanca personalizada para objetos con los que el jugador puede sentarse.",
|
||||
"config.sit.hand.blacklist": "Lista negra",
|
||||
"config.sit.hand.blacklist.description": "Crea una lista negra personalizada para objetos con los que el jugador no puede sentarse.",
|
||||
"config.sit.hand.list.description": "Ejemplo: ",
|
||||
"config.sit.hand.list.description_2": "\"minecraft:torch\"",
|
||||
"key.sit.command.reloaded": "¡Configuración recargada!",
|
||||
"key.sit.command.purged": "¡Se purgaron a todas las entidades activas de sillas!"
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"config.sit.empty": "Пусто",
|
||||
"config.sit.restrictive": "Ограничение",
|
||||
"config.sit.none": "Нет",
|
||||
"config.sit.category.general": "Общий",
|
||||
"config.sit.category.general.tooltip": "Основные настройки",
|
||||
"config.sit.category.main_hand": "Главная рука",
|
||||
"config.sit.category.main_hand.tooltip": "Настройки главной руки",
|
||||
"config.sit.category.off_hand": "Левая рука",
|
||||
"config.sit.category.off_hand.tooltip": "Настройки левой руки",
|
||||
"config.sit.general.keep_active": "Оставлять активным",
|
||||
"config.sit.general.keep_active.description": "Оставлять сущности активными даже при выходе из системы / выключении",
|
||||
"config.sit.general.sittable": "Блоки, для сидения",
|
||||
"config.sit.general.sittable.description": "Вкл/выкл возможность сидеть на разных типах блоков.",
|
||||
"config.sit.general.sit_while_seated": "Пересаживание на другой блок",
|
||||
"config.sit.general.sit_while_seated.description": "Вкл/выкл возможность пересесть на другой блок, когда уже сидишь.",
|
||||
"config.sit.general.sittable.stairs": "Ступени",
|
||||
"config.sit.general.sittable.slabs": "Полублоки",
|
||||
"config.sit.general.sittable.carpets": "Ковры",
|
||||
"config.sit.general.sittable.full_blocks": "Полные блоки",
|
||||
"config.sit.general.sittable.custom": "Другие блоки",
|
||||
"config.sit.general.sittable.custom.description": "Позволяет добавить собственные блоки, на которые можно сесть.",
|
||||
"config.sit.general.sittable_blocks": "Собственные блоки для сидения",
|
||||
"config.sit.general.sittable_blocks.description": "Добавь свой блок для сидения!",
|
||||
"config.sit.general.sittable_blocks.description_2": "Пример: %s",
|
||||
"config.sit.general.sittable_blocks.description_4": "Первый вход: собственный блок",
|
||||
"config.sit.general.sittable_blocks.description_5": "Второй вход: высота сидения (число от 0 до 1, например 0.52)",
|
||||
"config.sit.general.sittable_blocks.description_6": "Третий вход: размер хитбокса (место, где игрок появляется над объектом при спешивании)",
|
||||
"config.sit.general.sittable_blocks.description_7": "Четвертый вход (опционально): требуемое состояние блока для сидения (Вставьте \"!\" для исключения состояния блоков)",
|
||||
"config.sit.general.sittable_blocks.description_8": "Разделяйте разные входы знаком \"|\"!",
|
||||
"config.sit.hand": "Настройки руки",
|
||||
"config.sit.hand.requirements": "Требования",
|
||||
"config.sit.hand.requirements.description": "Что нужно, чтобы сесть.",
|
||||
"config.sit.hand.requirements.description_2": "Пусто = рука должна быть пуста",
|
||||
"config.sit.hand.requirements.description_3": "Ограниченный = установить ограничения для состояния руки",
|
||||
"config.sit.hand.requirements.description_4": "Ничего = можно сеть когда угодно",
|
||||
"config.sit.hand.restrictions": "Ограничения",
|
||||
"config.sit.hand.restrictions.description": "Вкл/выкл пресет ограничений руки, для возможности сидеть.",
|
||||
"config.sit.hand.restrictions.blocks": "Блоки",
|
||||
"config.sit.hand.restrictions.food": "Еда",
|
||||
"config.sit.hand.restrictions.usable": "Доступный",
|
||||
"config.sit.hand.restrictions.usable.description": "например луки, трезубцы, щиты",
|
||||
"config.sit.hand.whitelist": "Белый список",
|
||||
"config.sit.hand.whitelist.description": "Создай свой белый список предметов, которые игрок может использовать, чтобы сесть.",
|
||||
"config.sit.hand.blacklist": "Черный список",
|
||||
"config.sit.hand.blacklist.description": "Создай свой черный список предметов, которые игрок не может использовать, чтобы сесть.",
|
||||
"config.sit.hand.list.description": "Пример: ",
|
||||
"config.sit.hand.list.description_2": "\"minecraft:torch\"",
|
||||
"key.sit.command.reloaded": "Конфигурация перезагружена!",
|
||||
"key.sit.command.purged": "Очищены все сущности-сидения!"
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "oth3r-sit",
|
||||
"id": "sit-oth3r",
|
||||
"version": "${version}",
|
||||
"name": "Sit!",
|
||||
"description": "Adds sitting to minecraft! Endless customizability for hand restrictions and sittable blocks.",
|
||||
"description": "Adds sitting to minecraft! Endless customizability for hand restrictions and sittable blocks.\n Players can have their own sitting settings when using the Sit! client on the server!",
|
||||
"authors": [
|
||||
"Oth3r"
|
||||
],
|
||||
|
@ -12,7 +12,7 @@
|
|||
"sources": "https://github.com/Oth3r/Sit"
|
||||
},
|
||||
"license": "LGPL-3.0-only",
|
||||
"icon": "assets/sit/icon.png",
|
||||
"icon": "assets/sit-oth3r/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
|
@ -22,17 +22,19 @@
|
|||
"one.oth3r.sit.SitClient"
|
||||
],
|
||||
"modmenu": [
|
||||
"one.oth3r.sit.ModMenu"
|
||||
"one.oth3r.sit.screen.ModMenu"
|
||||
]
|
||||
},
|
||||
"depends": {
|
||||
"fabricloader": ">=0.14.21",
|
||||
"minecraft": "=${minecraft_version}",
|
||||
"java": ">=17",
|
||||
"fabric-api": "*"
|
||||
"minecraft": ">=${min_minecraft_version} <=${minecraft_version}",
|
||||
"fabric": "*"
|
||||
},
|
||||
"suggests": {
|
||||
"yet-another-config-lib": "*",
|
||||
"modmenu": "*"
|
||||
}
|
||||
},
|
||||
"accessWidener": "sit!.accesswidener",
|
||||
"mixins": [
|
||||
"sit!.mixins.json"
|
||||
]
|
||||
}
|
3
src/main/resources/sit!.accesswidener
Normal file
|
@ -0,0 +1,3 @@
|
|||
accessWidener v2 named
|
||||
|
||||
accessible field net/minecraft/state/State PROPERTY_MAP_PRINTER Ljava/util/function/Function;
|
13
src/main/resources/sit!.mixins.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "one.oth3r.sit.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"ReloadCommandMixin",
|
||||
"TextDisplayDismountMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|