forked from virt-mirrors/Sit
complete rewrite
This commit is contained in:
parent
d059cd4b8d
commit
1316686d85
24 changed files with 1808 additions and 871 deletions
|
@ -9,7 +9,7 @@ yarn_mappings=1.21+build.1
|
|||
loader_version=0.15.11
|
||||
|
||||
# Mod Properties
|
||||
mod_version=1.1.6+1.21
|
||||
mod_version=1.2.0.0+1.21
|
||||
maven_group=one.oth3r
|
||||
archives_base_name=sit!
|
||||
|
||||
|
|
|
@ -1,270 +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.registry.Registries;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.UseAction;
|
||||
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.HandType;
|
||||
import one.oth3r.sit.Utl.PlayerSettings;
|
||||
import one.oth3r.sit.Utl.PlayerSettings.Setting;
|
||||
|
||||
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(HandType.main,player.getMainHandStack());
|
||||
itemMap.put(HandType.off,player.getOffHandStack());
|
||||
// if sneaking cant sit
|
||||
if (player.isSneaking()) return false;
|
||||
// for both hands
|
||||
for (HandType type:HandType.values()) {
|
||||
ItemStack targetStack = itemMap.get(type);
|
||||
// if req is empty and the item isn't empty, false
|
||||
if (PlayerSettings.getRequirement(player,type).equals(config.HandRequirement.empty) && !targetStack.isEmpty()) return false;
|
||||
// if req is restrictive
|
||||
if (PlayerSettings.getRequirement(player,type).equals(config.HandRequirement.restrictive)) {
|
||||
// if item is in blacklist, false
|
||||
if (checkList(PlayerSettings.getList(player,type,Setting.blacklist),targetStack)) return false;
|
||||
// if item is NOT in whitelist
|
||||
if (!checkList(PlayerSettings.getList(player,type,Setting.whitelist),targetStack)) {
|
||||
// if block is restricted and items is block, false, ect
|
||||
if (PlayerSettings.getToggle(player,type,Setting.block) && (targetStack.getItem() instanceof BlockItem)) return false;
|
||||
if (PlayerSettings.getToggle(player,type,Setting.food) && food.contains(targetStack.getUseAction())) return false;
|
||||
if (PlayerSettings.getToggle(player,type,Setting.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.isEmpty()) {
|
||||
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 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, PlayerSettings.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) -> {
|
||||
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();
|
||||
if (!checkLogic(player)) return ActionResult.PASS;
|
||||
// todo interactions entity to make the hitbox?
|
||||
// make the entity first before checking to make sure the blocks around are fine
|
||||
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 ActionResult.PASS;
|
||||
entities.get(player).setRemoved(Entity.RemovalReason.DISCARDED);
|
||||
entities.remove(player);
|
||||
}
|
||||
player.getServerWorld().spawnEntity(entity);
|
||||
player.startRiding(entity);
|
||||
entities.put(player,entity);
|
||||
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());
|
||||
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,194 +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;
|
||||
|
||||
public class ModMenu implements ModMenuApi {
|
||||
private static MutableText lang(String key, Object... args) {
|
||||
return Utl.lang("config."+key,args);
|
||||
}
|
||||
@Override
|
||||
public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||
return parent -> YetAnotherConfigLib.createBuilder().save(config::save)
|
||||
.title(Text.of("Sit!"))
|
||||
.category(ConfigCategory.createBuilder()
|
||||
.name(lang("category.general"))
|
||||
.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())
|
||||
.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("example",
|
||||
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.withColor(TextColor.fromFormatting(Formatting.GRAY)))))
|
||||
.append("\n\n").append(lang("general.sittable_blocks.description.2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
.append("\n").append(lang("general.sittable_blocks.description.3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED))))
|
||||
.append("\n").append(lang("general.sittable_blocks.description.4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
.append("\n").append(lang("general.sittable_blocks.description.5").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD))))
|
||||
.append("\n\n").append(lang("general.sittable_blocks.description.6").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"))
|
||||
.option(Option.<config.HandRequirement>createBuilder()
|
||||
.name(lang("hand.requirement"))
|
||||
.description(OptionDescription.of(lang("hand.requirement.description")
|
||||
.append("\n\n").append(lang("hand.requirement.description.2",lang("hand.requirement.empty")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
.append("\n").append(lang("hand.requirement.description.3",lang("hand.requirement.restrictive")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
.append("\n").append(lang("hand.requirement.description.4",lang("hand.requirement.none")).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 -> lang("hand.requirement."+v.toString())))
|
||||
.build())
|
||||
.group(OptionGroup.createBuilder()
|
||||
.name(lang("hand.restriction"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.description")))
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restriction.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.restriction.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.restriction.usable"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.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.restriction.whitelist"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
.append("\n\n").append(lang("example",
|
||||
Text.empty().append(Utl.Assets.LIST).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.restriction.blacklist"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
.append("\n\n").append(lang("example",
|
||||
Text.empty().append(Utl.Assets.LIST).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"))
|
||||
.option(Option.<config.HandRequirement>createBuilder()
|
||||
.name(lang("hand.requirement"))
|
||||
.description(OptionDescription.of(lang("hand.requirement.description")
|
||||
.append("\n\n").append(lang("hand.requirement.description.2",lang("hand.requirement.empty")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
.append("\n").append(lang("hand.requirement.description.3",lang("hand.requirement.restrictive")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
.append("\n").append(lang("hand.requirement.description.4",lang("hand.requirement.none")).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 -> lang("hand.requirement."+v.toString())))
|
||||
.build())
|
||||
.group(OptionGroup.createBuilder()
|
||||
.name(lang("hand.restriction"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.description")))
|
||||
.option(Option.<Boolean>createBuilder()
|
||||
.name(lang("hand.restriction.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.restriction.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.restriction.usable"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.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.restriction.whitelist"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
.append("\n\n").append(lang("example",
|
||||
Text.empty().append(Utl.Assets.LIST).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.restriction.blacklist"))
|
||||
.description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
.append("\n\n").append(lang("example",
|
||||
Text.empty().append(Utl.Assets.LIST).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);
|
||||
}
|
||||
}
|
|
@ -5,10 +5,15 @@ 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.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import one.oth3r.sit.file.Data;
|
||||
import one.oth3r.sit.packet.SitPayloads;
|
||||
import one.oth3r.sit.utl.Events;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -16,31 +21,29 @@ import java.lang.reflect.Type;
|
|||
import java.util.HashMap;
|
||||
|
||||
public class Sit implements ModInitializer {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("sit");
|
||||
public static final String MOD_ID = "oth3r-sit";
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||
public static String CONFIG_DIR = FabricLoader.getInstance().getConfigDir().toFile()+"/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;
|
||||
|
||||
public static boolean client = false;
|
||||
public static boolean singleplayer = 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();
|
||||
Data.loadFiles(true);
|
||||
Events.registerCommon();
|
||||
|
||||
//PACKETS
|
||||
ServerPlayNetworking.registerGlobalReceiver(PacketBuilder.getIdentifier(),
|
||||
(server, player, handler, buf, responseSender) -> {
|
||||
// copy to not throw errors
|
||||
PacketBuilder packet = new PacketBuilder(buf.copy());
|
||||
server.execute(() -> {
|
||||
PayloadTypeRegistry.playC2S().register(SitPayloads.SettingsPayload.ID, SitPayloads.SettingsPayload.CODEC);
|
||||
ServerPlayNetworking.registerGlobalReceiver(SitPayloads.SettingsPayload.ID,((payload, context) -> server.execute(() -> {
|
||||
Type hashMapToken = new TypeToken<HashMap<String, Object>>() {}.getType();
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
playerSettings.put(player,gson.fromJson(packet.getMessage(),hashMapToken));
|
||||
});
|
||||
});
|
||||
playerSettings.put(context.player(),gson.fromJson(payload.value(),hashMapToken));
|
||||
})));
|
||||
}
|
||||
}
|
|
@ -1,25 +1,40 @@
|
|||
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.file.Data;
|
||||
import one.oth3r.sit.packet.SitPayloads;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
public class SitClient implements ClientModInitializer {
|
||||
public static boolean inGame = false;
|
||||
private static boolean IN_GAME = false;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
Sit.isClient = true;
|
||||
Sit.client = true;
|
||||
|
||||
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
|
||||
inGame = true;
|
||||
IN_GAME = true;
|
||||
if (client.isInSingleplayer()) Sit.singleplayer = true;
|
||||
// send a data packet whenever joining a server
|
||||
client.execute(SitClient::sendPackets);
|
||||
sendSettingsPackets();
|
||||
});
|
||||
// reset inGame
|
||||
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> inGame = false);
|
||||
|
||||
// reset cashed things
|
||||
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> {
|
||||
IN_GAME = false;
|
||||
if (Sit.singleplayer) {
|
||||
// flip the single player switch
|
||||
Sit.singleplayer = false;
|
||||
}
|
||||
public static void sendPackets() {
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
new PacketBuilder(gson.toJson(Utl.PlayerSettings.getHandSettings())).send();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* sends the settings packets to the server
|
||||
*/
|
||||
public static void sendSettingsPackets() {
|
||||
if (IN_GAME) ClientPlayNetworking.send(new SitPayloads.SettingsPayload(Utl.getGson().toJson(Data.getHandConfig())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,74 +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 net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class Utl {
|
||||
public static MutableText lang(String key, Object... args) {
|
||||
if (Sit.isClient) return Text.translatable(key, args);
|
||||
else return LangReader.of(key, args).getTxT();
|
||||
}
|
||||
public enum HandType {
|
||||
main,
|
||||
off
|
||||
}
|
||||
public static class PlayerSettings {
|
||||
public enum Setting {
|
||||
requirement,
|
||||
block,
|
||||
food,
|
||||
usable,
|
||||
whitelist,
|
||||
blacklist
|
||||
}
|
||||
/**
|
||||
* Gets a HashMap of all player configurable settings.
|
||||
* @return a map with player hand settings.
|
||||
*/
|
||||
public static HashMap<String,String> getHandSettings() {
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
HashMap<String,String> settings = new HashMap<>();
|
||||
// main hand
|
||||
settings.put("hand.main."+Setting.requirement,String.valueOf(config.mainReq));
|
||||
settings.put("hand.main."+Setting.block,String.valueOf(config.mainBlock));
|
||||
settings.put("hand.main."+Setting.food,String.valueOf(config.mainFood));
|
||||
settings.put("hand.main."+Setting.usable,String.valueOf(config.mainUsable));
|
||||
settings.put("hand.main."+Setting.whitelist,gson.toJson(config.mainWhitelist));
|
||||
settings.put("hand.main."+Setting.blacklist,gson.toJson(config.mainBlacklist));
|
||||
// copy but offhand
|
||||
settings.put("hand.off."+Setting.requirement,String.valueOf(config.offReq));
|
||||
settings.put("hand.off."+Setting.block,String.valueOf(config.offBlock));
|
||||
settings.put("hand.off."+Setting.food,String.valueOf(config.offFood));
|
||||
settings.put("hand.off."+Setting.usable,String.valueOf(config.offUsable));
|
||||
settings.put("hand.off."+Setting.whitelist,gson.toJson(config.offWhitelist));
|
||||
settings.put("hand.off."+Setting.blacklist,gson.toJson(config.offBlacklist));
|
||||
return settings;
|
||||
}
|
||||
// returns specific items from the player config
|
||||
public static config.HandRequirement getRequirement(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, Setting setting) {
|
||||
Type listType = new TypeToken<ArrayList<String>>() {}.getType();
|
||||
return new Gson().fromJson(Sit.playerSettings.get(player).get("hand."+type+"."+setting),listType);
|
||||
}
|
||||
public static boolean getToggle(ServerPlayerEntity player, HandType type, Setting setting) {
|
||||
return Boolean.parseBoolean(Sit.playerSettings.get(player).get("hand."+type+"."+setting));
|
||||
}
|
||||
}
|
||||
public static class Assets {
|
||||
public static final String CUSTOM_BLOCKS = "\"minecraft:campfire|0.255|1|lit=false\"";
|
||||
public static final String REQUIREMENT_OPTIONS = String.format("%s, %s, %s",
|
||||
config.HandRequirement.empty,config.HandRequirement.restrictive,config.HandRequirement.none);
|
||||
public static final String LIST = "\"minecraft:torch\"";
|
||||
}
|
||||
}
|
|
@ -1,21 +1,20 @@
|
|||
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.entity.EntityType;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
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 net.minecraft.world.World;
|
||||
import one.oth3r.sit.utl.Logic;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
import one.oth3r.sit.file.Data;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
@ -29,11 +28,13 @@ 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
|
||||
|
@ -45,48 +46,37 @@ public class SitCommand {
|
|||
String[] args = arg.split(" ");
|
||||
if (args[0].equalsIgnoreCase("sit"))
|
||||
args = arg.replaceFirst("sit ", "").split(" ");
|
||||
|
||||
// if console
|
||||
if (player == null) {
|
||||
if (args[0].equalsIgnoreCase("reload")) {
|
||||
config.load();
|
||||
Logic.reload();
|
||||
Sit.LOGGER.info(Utl.lang("msg.reloaded").getString());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("sit")) {
|
||||
// todo make the command target the block that the player is looking at, if not looking at a block default to below
|
||||
BlockPos pos = player.getBlockPos();
|
||||
|
||||
if (!(player.getY() -((int) player.getY()) > 0.00)) {
|
||||
pos = pos.add(0,-1,0);
|
||||
}
|
||||
World world = player.getWorld();
|
||||
|
||||
// if already sitting, ignore
|
||||
if (Events.entities.containsKey(player)) return 1;
|
||||
// make entity first to check the blocks
|
||||
DisplayEntity.TextDisplayEntity entity = new DisplayEntity.TextDisplayEntity(EntityType.TEXT_DISPLAY,player.getServerWorld());
|
||||
Events.setEntity(pos,world,entity);
|
||||
if (Events.checkBlocks(pos,world,Events.isAboveBlockheight(entity))) {
|
||||
player.getServerWorld().spawnEntity(entity);
|
||||
player.startRiding(entity);
|
||||
Events.entities.put(player,entity);
|
||||
return 1;
|
||||
}
|
||||
if (Data.getSitEntity(player) != null) return 1;
|
||||
|
||||
// try to make the player sit
|
||||
Logic.sit(player,pos,null);
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("reload")) {
|
||||
config.load();
|
||||
Logic.reload();
|
||||
player.sendMessage(Utl.lang("msg.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(Utl.lang("msg.purged"));
|
||||
} catch (CommandSyntaxException e) {
|
||||
player.sendMessage(Utl.lang("msg.purged"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (args[0].equalsIgnoreCase("purgeChairEntities")) Utl.Entity.purge(player,true);
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,256 +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 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) {}
|
||||
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 Utl.lang("config."+key, args).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");
|
||||
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# "+ Utl.lang("config."+
|
||||
"general.sittable_blocks.description")
|
||||
.append("\n# ").append(lang("example",Utl.Assets.CUSTOM_BLOCKS))
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description.2"))
|
||||
.append("\n# ").append(lang("general.sittable_blocks.description.3"))
|
||||
.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")).getString());
|
||||
file.write("\ncustom-blocks="+gson.toJson(customBlocks));
|
||||
file.write("\n\n# "+lang("hand"));
|
||||
file.write("\n# "+ Utl.lang("config."+
|
||||
"hand.requirement.description")
|
||||
.append("\n# ").append(lang("hand.requirement.description.2",HandRequirement.empty))
|
||||
.append("\n# ").append(lang("hand.requirement.description.3",HandRequirement.restrictive))
|
||||
.append("\n# ").append(lang("hand.requirement.description.4",HandRequirement.none)).getString());
|
||||
file.write("\n# "+lang("hand.requirement.options",Utl.Assets.REQUIREMENT_OPTIONS));
|
||||
file.write("\nhand.main.requirement=" + mainReq);
|
||||
file.write("\n#");
|
||||
file.write("\nhand.off.requirement=" + offReq);
|
||||
|
||||
file.write("\n\n# "+lang("hand.restriction"));
|
||||
file.write("\n# "+lang("hand.restriction.description"));
|
||||
file.write("\nhand.main.block=" + mainBlock);
|
||||
file.write("\nhand.main.food=" + mainFood);
|
||||
file.write("\nhand.main.usable=" + mainUsable);
|
||||
file.write("\n#");
|
||||
file.write("\nhand.off.block=" + offBlock);
|
||||
file.write("\nhand.off.food=" + offFood);
|
||||
file.write("\nhand.off.usable=" + offUsable);
|
||||
|
||||
file.write("\n\n# "+lang("hand.restriction.list"));
|
||||
file.write("\n# "+lang("hand.restriction.list.description"));
|
||||
file.write("\n# "+lang("example",Utl.Assets.LIST));
|
||||
file.write("\nhand.main.whitelist="+gson.toJson(mainWhitelist));
|
||||
file.write("\nhand.main.blacklist="+gson.toJson(mainBlacklist));
|
||||
file.write("\n#");
|
||||
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 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<>();
|
||||
}
|
||||
}
|
92
src/main/java/one/oth3r/sit/file/CustomBlock.java
Normal file
92
src/main/java/one/oth3r/sit/file/CustomBlock.java
Normal file
|
@ -0,0 +1,92 @@
|
|||
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.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<>();
|
||||
@SerializedName("sittingHeight")
|
||||
private Double sittingHeight = 0.5;
|
||||
|
||||
public CustomBlock() {}
|
||||
|
||||
public CustomBlock(ArrayList<String> blockIds, ArrayList<String> blockTags, ArrayList<String> blockStates, Double sittingHeight) {
|
||||
this.blockIds = blockIds;
|
||||
this.blockTags = blockTags;
|
||||
this.blockStates = blockStates;
|
||||
this.sittingHeight = sittingHeight;
|
||||
}
|
||||
|
||||
public ArrayList<String> getBlockIds() {
|
||||
return blockIds;
|
||||
}
|
||||
|
||||
public ArrayList<String> getBlockTags() {
|
||||
return blockTags;
|
||||
}
|
||||
|
||||
public ArrayList<String> getBlockStates() {
|
||||
return blockStates;
|
||||
}
|
||||
|
||||
public Double getSittingHeight() {
|
||||
return sittingHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, and it is contained in the block, return false
|
||||
if (state.startsWith("!") && blockState.toString().contains(state.substring(1))) return false;
|
||||
// else check if the blockstate matches, if not return false
|
||||
else if (!blockState.toString().contains(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;
|
||||
}
|
||||
// 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.of(tag.substring(1))))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
102
src/main/java/one/oth3r/sit/file/Data.java
Normal file
102
src/main/java/one/oth3r/sit/file/Data.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Data {
|
||||
/**
|
||||
* Sit! config file
|
||||
*/
|
||||
private static ServerConfig serverConfig = new ServerConfig();
|
||||
|
||||
public static ServerConfig getServerConfig() {
|
||||
return new ServerConfig(serverConfig);
|
||||
}
|
||||
|
||||
public static void setServerConfig(ServerConfig newServerConfig) {
|
||||
serverConfig = new ServerConfig(newServerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default hand config for all new players
|
||||
*/
|
||||
private static HandConfig handConfig = new HandConfig();
|
||||
|
||||
public static HandConfig getHandConfig() {
|
||||
return new HandConfig(handConfig);
|
||||
}
|
||||
|
||||
public static void setHandConfig(HandConfig newHandConfig) {
|
||||
handConfig = new HandConfig(newHandConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* the hand config stored per player on the server
|
||||
*/
|
||||
private static final HashMap<ServerPlayerEntity, HandConfig> playerSettings = new HashMap<>();
|
||||
|
||||
public static void clearPlayerSettings() {
|
||||
playerSettings.clear();
|
||||
}
|
||||
|
||||
public static void setPlayerSetting(ServerPlayerEntity player, HandConfig config) {
|
||||
playerSettings.put(player, config);
|
||||
}
|
||||
|
||||
public static void removePlayerSetting(ServerPlayerEntity player) {
|
||||
playerSettings.remove(player);
|
||||
}
|
||||
|
||||
public static HandConfig getPlayerSetting(ServerPlayerEntity player) {
|
||||
return playerSettings.getOrDefault(player,handConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* a list of players who just joined, to check if they are mounted to a Sit! entity
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* loads all config files to memory
|
||||
* @param tryLegacy try to load the legacy file, usually only used on server startup
|
||||
*/
|
||||
public static void loadFiles(boolean tryLegacy) {
|
||||
ServerConfig.load(tryLegacy);
|
||||
HandConfig.load();
|
||||
}
|
||||
}
|
97
src/main/java/one/oth3r/sit/file/HandConfig.java
Normal file
97
src/main/java/one/oth3r/sit/file/HandConfig.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import net.minecraft.util.Hand;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
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 HandConfig {
|
||||
|
||||
@SerializedName("version")
|
||||
private Double version = 1.0;
|
||||
@SerializedName("hand-sitting")
|
||||
private boolean handSitting = true;
|
||||
@SerializedName("main-hand")
|
||||
private HandSetting mainHand = new HandSetting(HandSetting.SittingRequirement.EMPTY, new HandSetting.Filter());
|
||||
@SerializedName("off-hand")
|
||||
private HandSetting offHand = new HandSetting(HandSetting.SittingRequirement.FILTER,
|
||||
new HandSetting.Filter(false,true,false,new ArrayList<>(),new ArrayList<>())); // todo fill out some fox examples sake
|
||||
|
||||
public HandConfig() {}
|
||||
|
||||
public HandConfig(double version, boolean handSitting, HandSetting mainHand, HandSetting offHand) {
|
||||
this.version = version;
|
||||
this.handSitting = handSitting;
|
||||
this.mainHand = mainHand;
|
||||
this.offHand = offHand;
|
||||
}
|
||||
|
||||
public HandConfig(HandConfig handConfig) {
|
||||
this.version = handConfig.version;
|
||||
this.handSitting = handConfig.handSitting;
|
||||
this.mainHand = handConfig.mainHand;
|
||||
this.offHand = handConfig.offHand;
|
||||
}
|
||||
|
||||
public Double getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public boolean canSitWithHand() {
|
||||
return handSitting;
|
||||
}
|
||||
|
||||
public HandSetting getHand(Hand handType) {
|
||||
return handType.equals(Hand.MAIN_HAND) ? mainHand : offHand;
|
||||
}
|
||||
|
||||
public HandSetting getMainHand() {
|
||||
return mainHand;
|
||||
}
|
||||
|
||||
public HandSetting getOffHand() {
|
||||
return offHand;
|
||||
}
|
||||
|
||||
public static File getFile() {
|
||||
return new File(Sit.CONFIG_DIR+"hand-config.json");
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the Config file to Data
|
||||
*/
|
||||
public static void load() {
|
||||
|
||||
File file = getFile();
|
||||
if (!file.exists()) save();
|
||||
// try reading the file
|
||||
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
Updater.HandConfigFile.run(reader);
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.error(String.format("ERROR LOADING '%s`: %s", file.getName(),e.getMessage()));
|
||||
}
|
||||
// save after loading
|
||||
save();
|
||||
}
|
||||
|
||||
/**
|
||||
* saves Data.config to config.json
|
||||
*/
|
||||
public static void save() {
|
||||
if (!getFile().exists()) {
|
||||
Sit.LOGGER.info(String.format("Creating new `%s`", getFile().getName()));
|
||||
}
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(getFile().toPath(), StandardCharsets.UTF_8)) {
|
||||
writer.write(Utl.getGson().toJson(Data.getHandConfig()));
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.error(String.format("ERROR SAVING '%s`: %s", getFile().getName(), e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
79
src/main/java/one/oth3r/sit/file/HandSetting.java
Normal file
79
src/main/java/one/oth3r/sit/file/HandSetting.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HandSetting {
|
||||
|
||||
public boolean mainBlock;
|
||||
@SerializedName("requirement")
|
||||
private SittingRequirement sittingRequirement = SittingRequirement.NONE;
|
||||
@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("block")
|
||||
private boolean block = false;
|
||||
@SerializedName("food")
|
||||
private boolean food = false;
|
||||
@SerializedName("usable")
|
||||
private boolean usable = false;
|
||||
@SerializedName("custom-items")
|
||||
private ArrayList<String> customItems = new ArrayList<>();
|
||||
@SerializedName("custom-tags")
|
||||
private ArrayList<String> customTags = new ArrayList<>();
|
||||
|
||||
public Filter() {}
|
||||
|
||||
public Filter(boolean block, boolean food, boolean usable, ArrayList<String> customItems, ArrayList<String> customTags) {
|
||||
this.block = block;
|
||||
this.food = food;
|
||||
this.usable = usable;
|
||||
this.customItems = customItems;
|
||||
this.customTags = customTags;
|
||||
}
|
||||
|
||||
public boolean isBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public boolean isFood() {
|
||||
return food;
|
||||
}
|
||||
|
||||
public boolean isUsable() {
|
||||
return usable;
|
||||
}
|
||||
|
||||
public ArrayList<String> getCustomItems() {
|
||||
return customItems;
|
||||
}
|
||||
|
||||
public ArrayList<String> getCustomTags() {
|
||||
return customTags;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
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 java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
@ -75,20 +75,30 @@ public class LangReader {
|
|||
public static LangReader of(String translationKey, Object... placeholders) {
|
||||
return new LangReader(translationKey, placeholders);
|
||||
}
|
||||
|
||||
public static void loadLanguageFile() {
|
||||
try {
|
||||
ClassLoader classLoader = Sit.class.getClassLoader();
|
||||
InputStream inputStream = classLoader.getResourceAsStream("assets/sit/lang/"+ Config.lang+".json");
|
||||
try {
|
||||
InputStream inputStream = classLoader.getResourceAsStream("assets/sit/lang/"+ Data.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/lang/"+ new ServerConfig().getLang() +".json");
|
||||
//todo error message and reset back 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 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();
|
||||
Sit.LOGGER.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
public static String getLanguageValue(String key) {
|
177
src/main/java/one/oth3r/sit/file/ServerConfig.java
Normal file
177
src/main/java/one/oth3r/sit/file/ServerConfig.java
Normal file
|
@ -0,0 +1,177 @@
|
|||
package one.oth3r.sit.file;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
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;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ServerConfig {
|
||||
|
||||
@SerializedName("version")
|
||||
private Double version = 2.0;
|
||||
@SerializedName("lang")
|
||||
private String lang = "en_us";
|
||||
@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<CustomBlock> customBlocks = new ArrayList<>();
|
||||
@SerializedName("blacklisted-blocks")
|
||||
private ArrayList<String> blacklistedBlocks = new ArrayList<>();
|
||||
|
||||
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.customBlocks = serverConfig.customBlocks;
|
||||
this.blacklistedBlocks = serverConfig.blacklistedBlocks;
|
||||
}
|
||||
|
||||
public ServerConfig(Double version, String lang, boolean keepActive, boolean sitWhileSeated, PresetBlocks presetBlocks, boolean customEnabled, ArrayList<CustomBlock> customBlocks, ArrayList<String> blacklistedBlocks) {
|
||||
this.version = version;
|
||||
this.lang = lang;
|
||||
this.keepActive = keepActive;
|
||||
this.sitWhileSeated = sitWhileSeated;
|
||||
this.presetBlocks = presetBlocks;
|
||||
this.customEnabled = customEnabled;
|
||||
this.customBlocks = customBlocks;
|
||||
this.blacklistedBlocks = blacklistedBlocks;
|
||||
}
|
||||
|
||||
public Double getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getLang() {
|
||||
return lang;
|
||||
}
|
||||
|
||||
public boolean isKeepActive() {
|
||||
return keepActive;
|
||||
}
|
||||
|
||||
public boolean isSitWhileSeated() {
|
||||
return sitWhileSeated;
|
||||
}
|
||||
|
||||
public PresetBlocks getPresetBlocks() {
|
||||
return presetBlocks;
|
||||
}
|
||||
|
||||
public Boolean isCustomEnabled() {
|
||||
return customEnabled;
|
||||
}
|
||||
|
||||
public ArrayList<CustomBlock> getCustomBlocks() {
|
||||
return customBlocks;
|
||||
}
|
||||
|
||||
public ArrayList<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static File getFile() {
|
||||
return new File(Sit.CONFIG_DIR+"server-config.json");
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the directionhud Config file to Data.config
|
||||
*/
|
||||
public static void load(boolean tryLegacy) {
|
||||
|
||||
File file = getFile();
|
||||
if (!file.exists()) {
|
||||
// try to make the config directory
|
||||
try {
|
||||
Files.createDirectories(Paths.get(Sit.CONFIG_DIR));
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.error("Failed to create config directory. Canceling all config loading...");
|
||||
return;
|
||||
}
|
||||
// if loading from legacy, try checking the old config directory for the file
|
||||
if (tryLegacy && Updater.ServerConfigFile.Legacy.getLegacyFile().exists()) {
|
||||
Sit.LOGGER.info("Updating Sit!.properties to sit!/config.json");
|
||||
Updater.ServerConfigFile.Legacy.run();
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
Updater.ServerConfigFile.run(reader);
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.error(String.format("ERROR LOADING '%s`: %s", file.getName(),e.getMessage()));
|
||||
}
|
||||
// save after loading
|
||||
save();
|
||||
}
|
||||
|
||||
/**
|
||||
* saves Data.config to config.json
|
||||
*/
|
||||
public static void save() {
|
||||
if (!getFile().exists()) {
|
||||
Sit.LOGGER.info(String.format("Creating new `%s`", getFile().getName()));
|
||||
}
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(getFile().toPath(), StandardCharsets.UTF_8)) {
|
||||
writer.write(Utl.getGson().toJson(Data.getServerConfig()));
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.info(String.format("ERROR SAVING '%s`: %s", getFile().getName(), e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
288
src/main/java/one/oth3r/sit/file/Updater.java
Normal file
288
src/main/java/one/oth3r/sit/file/Updater.java
Normal file
|
@ -0,0 +1,288 @@
|
|||
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.minecraft.util.Hand;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.utl.Utl;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
|
||||
public class Updater {
|
||||
|
||||
public static class HandConfigFile {
|
||||
|
||||
/**
|
||||
* runs the updater from the file reader and sets the loaded settings when finished
|
||||
* @param reader the file reader
|
||||
* @throws NullPointerException if the file is null
|
||||
*/
|
||||
public static void run(BufferedReader reader)
|
||||
throws NullPointerException {
|
||||
// try to read the json
|
||||
HandConfig handConfig;
|
||||
try {
|
||||
handConfig = Utl.getGson().fromJson(reader, HandConfig.class);
|
||||
} catch (Exception e) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
// throw null if the fileData is null or version is null
|
||||
if (handConfig == null) throw new NullPointerException();
|
||||
|
||||
// get the file version
|
||||
Double version = handConfig.getVersion();
|
||||
|
||||
// if there's no version, throw
|
||||
if (version == null) throw new NullPointerException();
|
||||
|
||||
// update the config (using the non-null version)
|
||||
handConfig = update(handConfig);
|
||||
|
||||
// set the config in the mod data
|
||||
Data.setHandConfig(handConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the file
|
||||
*/
|
||||
public static HandConfig update(HandConfig old) {
|
||||
HandConfig serverConfig = new HandConfig(old);
|
||||
return serverConfig;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerConfigFile {
|
||||
public static final double VERSION = 1.0;
|
||||
|
||||
/**
|
||||
* runs the updater from the file reader and sets the loaded settings when finished
|
||||
* @param reader the file reader
|
||||
* @throws NullPointerException if the file is null
|
||||
*/
|
||||
public static void run(BufferedReader reader)
|
||||
throws NullPointerException {
|
||||
// try to read the json
|
||||
ServerConfig serverConfig;
|
||||
try {
|
||||
serverConfig = Utl.getGson().fromJson(reader, ServerConfig.class);
|
||||
} catch (Exception e) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
// throw null if the fileData is null or version is null
|
||||
if (serverConfig == null) throw new NullPointerException();
|
||||
|
||||
// get the file version
|
||||
Double version = serverConfig.getVersion();
|
||||
|
||||
// if there's no version, throw
|
||||
if (version == null) throw new NullPointerException();
|
||||
|
||||
// update the config (using the non-null version)
|
||||
serverConfig = update(serverConfig);
|
||||
|
||||
System.out.println("updated");
|
||||
System.out.println(serverConfig.getBlacklistedBlocks());
|
||||
|
||||
// set the config in the mod data
|
||||
Data.setServerConfig(serverConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the file
|
||||
*/
|
||||
public static ServerConfig update(ServerConfig old) {
|
||||
ServerConfig serverConfig = new ServerConfig(old);
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
public 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(Sit.CONFIG_DIR.substring(0,Sit.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(VERSION));
|
||||
|
||||
// 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) {
|
||||
Sit.LOGGER.error("Error loading legacy config file: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// delete the old file
|
||||
try {
|
||||
Files.delete(file.toPath());
|
||||
Sit.LOGGER.info("Deleted " + file.getName());
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.error("Failed to delete the old Sit! config.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a list of custom blocks from the legacy way of entering custom sit blocks
|
||||
*/
|
||||
private static ArrayList<CustomBlock> getCustomBlocks(ArrayList<String> fix) {
|
||||
//eg. minecraft:campfire|.46|1|lit=false
|
||||
ArrayList<CustomBlock> 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 CustomBlock(
|
||||
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 {
|
||||
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
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.isSitWhileSeated()))),
|
||||
new ServerConfig.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<>()
|
||||
);
|
||||
|
||||
HandConfig defaultHandConfig = new HandConfig();
|
||||
|
||||
HandConfig handConfig = null;
|
||||
try {
|
||||
handConfig = new HandConfig(
|
||||
1.0, Boolean.parseBoolean((String) properties.computeIfAbsent("hand.sitting", a -> String.valueOf(defaultHandConfig.canSitWithHand()))),
|
||||
new HandSetting(
|
||||
Utl.Enum.get(properties.computeIfAbsent("hand.main.requirement", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getSittingRequirement())),HandSetting.SittingRequirement.class,HandSetting.SittingRequirement.FILTER),
|
||||
new HandSetting.Filter(
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.block", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getFilter().isBlock()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.food", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getFilter().isFood()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("hand.main.usable", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getFilter().isUsable()))),
|
||||
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(
|
||||
Utl.Enum.get(properties.computeIfAbsent("hand.off.requirement", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getSittingRequirement())),HandSetting.SittingRequirement.class,HandSetting.SittingRequirement.FILTER),
|
||||
new HandSetting.Filter(
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.block", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getFilter().isBlock()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.food", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getFilter().isFood()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("hand.off.usable", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getFilter().isUsable()))),
|
||||
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 {
|
||||
handConfig = new HandConfig(
|
||||
1.0, defaultHandConfig.canSitWithHand(),
|
||||
new HandSetting(
|
||||
Utl.Enum.get(properties.computeIfAbsent("main-hand-requirement", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getSittingRequirement())),HandSetting.SittingRequirement.class,HandSetting.SittingRequirement.FILTER),
|
||||
new HandSetting.Filter(
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-block", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getFilter().isBlock()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-food", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getFilter().isFood()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-usable", a -> String.valueOf(defaultHandConfig.getHand(Hand.MAIN_HAND).getFilter().isUsable()))),
|
||||
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(
|
||||
Utl.Enum.get(properties.computeIfAbsent("off-hand-requirement", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getSittingRequirement())),HandSetting.SittingRequirement.class,HandSetting.SittingRequirement.FILTER),
|
||||
new HandSetting.Filter(
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-block", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getFilter().isBlock()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-food", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getFilter().isFood()))),
|
||||
Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-usable", a -> String.valueOf(defaultHandConfig.getHand(Hand.OFF_HAND).getFilter().isUsable()))),
|
||||
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) {}
|
||||
}
|
||||
|
||||
Data.setServerConfig(serverConfig);
|
||||
Data.setHandConfig(handConfig);
|
||||
ServerConfig.save();
|
||||
HandConfig.save();
|
||||
} catch (Exception e) {
|
||||
Sit.LOGGER.error("Error loading legacy config: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
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 class TextDisplayDismountMixin extends DisplayEntity {
|
||||
|
||||
public TextDisplayDismountMixin(EntityType<?> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshData(boolean shouldLerp, float lerpProgress) {}
|
||||
|
||||
@Override
|
||||
public Vec3d updatePassengerForDismount(LivingEntity passenger) {
|
||||
int[][] offset = Dismounting.getDismountOffsets(Direction.NORTH);
|
||||
// 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;
|
||||
}
|
||||
}
|
|
@ -7,10 +7,10 @@ import net.minecraft.network.packet.CustomPayload;
|
|||
import net.minecraft.util.Identifier;
|
||||
import one.oth3r.sit.Sit;
|
||||
|
||||
public class CustomPayloads {
|
||||
public class SitPayloads {
|
||||
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 Id<SettingsPayload> ID = new Id<>(Identifier.of(Sit.MOD_ID,"settings_v2.0"));
|
||||
|
||||
public static final PacketCodec<RegistryByteBuf, SettingsPayload> CODEC = PacketCodecs.STRING.xmap(SettingsPayload::new, SettingsPayload::value).cast();
|
||||
|
||||
|
@ -18,10 +18,5 @@ public class CustomPayloads {
|
|||
public Id<SettingsPayload> getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
185
src/main/java/one/oth3r/sit/screen/ModMenu.java
Normal file
185
src/main/java/one/oth3r/sit/screen/ModMenu.java
Normal file
|
@ -0,0 +1,185 @@
|
|||
package one.oth3r.sit.screen;
|
||||
|
||||
import com.terraformersmc.modmenu.api.ModMenuApi;
|
||||
|
||||
public class ModMenu implements ModMenuApi {
|
||||
// private static MutableText lang(String key, Object... args) {
|
||||
// return Utl.lang("config."+key,args);
|
||||
// }
|
||||
// @Override
|
||||
// public ConfigScreenFactory<?> getModConfigScreenFactory() {
|
||||
// return parent -> YetAnotherConfigLib.createBuilder().save(config::save)
|
||||
// .title(Text.of("Sit!"))
|
||||
// .category(ConfigCategory.createBuilder()
|
||||
// .name(lang("category.general"))
|
||||
// .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())
|
||||
// .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("example",
|
||||
// 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.withColor(TextColor.fromFormatting(Formatting.GRAY)))))
|
||||
// .append("\n\n").append(lang("general.sittable_blocks.description.2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
// .append("\n").append(lang("general.sittable_blocks.description.3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED))))
|
||||
// .append("\n").append(lang("general.sittable_blocks.description.4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
// .append("\n").append(lang("general.sittable_blocks.description.5").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD))))
|
||||
// .append("\n\n").append(lang("general.sittable_blocks.description.6").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"))
|
||||
// .option(Option.<config.HandRequirement>createBuilder()
|
||||
// .name(lang("hand.requirement"))
|
||||
// .description(OptionDescription.of(lang("hand.requirement.description")
|
||||
// .append("\n\n").append(lang("hand.requirement.description.2",lang("hand.requirement.empty")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
// .append("\n").append(lang("hand.requirement.description.3",lang("hand.requirement.restrictive")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
// .append("\n").append(lang("hand.requirement.description.4",lang("hand.requirement.none")).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 -> lang("hand.requirement."+v.toString())))
|
||||
// .build())
|
||||
// .group(OptionGroup.createBuilder()
|
||||
// .name(lang("hand.restriction"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.description")))
|
||||
// .option(Option.<Boolean>createBuilder()
|
||||
// .name(lang("hand.restriction.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.restriction.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.restriction.usable"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.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.restriction.whitelist"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
// .append("\n\n").append(lang("example",
|
||||
// Text.empty().append(Utl.Assets.LIST).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.restriction.blacklist"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
// .append("\n\n").append(lang("example",
|
||||
// Text.empty().append(Utl.Assets.LIST).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"))
|
||||
// .option(Option.<config.HandRequirement>createBuilder()
|
||||
// .name(lang("hand.requirement"))
|
||||
// .description(OptionDescription.of(lang("hand.requirement.description")
|
||||
// .append("\n\n").append(lang("hand.requirement.description.2",lang("hand.requirement.empty")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))))
|
||||
// .append("\n").append(lang("hand.requirement.description.3",lang("hand.requirement.restrictive")).styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))))
|
||||
// .append("\n").append(lang("hand.requirement.description.4",lang("hand.requirement.none")).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 -> lang("hand.requirement."+v.toString())))
|
||||
// .build())
|
||||
// .group(OptionGroup.createBuilder()
|
||||
// .name(lang("hand.restriction"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.description")))
|
||||
// .option(Option.<Boolean>createBuilder()
|
||||
// .name(lang("hand.restriction.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.restriction.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.restriction.usable"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.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.restriction.whitelist"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
// .append("\n\n").append(lang("example",
|
||||
// Text.empty().append(Utl.Assets.LIST).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.restriction.blacklist"))
|
||||
// .description(OptionDescription.of(lang("hand.restriction.list.description")
|
||||
// .append("\n\n").append(lang("example",
|
||||
// Text.empty().append(Utl.Assets.LIST).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);
|
||||
// }
|
||||
}
|
69
src/main/java/one/oth3r/sit/utl/Events.java
Normal file
69
src/main/java/one/oth3r/sit/utl/Events.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
package one.oth3r.sit.utl;
|
||||
|
||||
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.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.command.SitCommand;
|
||||
import one.oth3r.sit.file.Data;
|
||||
|
||||
public class Events {
|
||||
|
||||
public static void playerConnections() {
|
||||
// PLAYER JOIN
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
||||
Data.setPlayerSetting(handler.player,Data.getHandConfig());
|
||||
Data.setCheckPlayer(handler.player, 5);
|
||||
});
|
||||
|
||||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||
// if keep is off, remove the entity
|
||||
if (!Data.getServerConfig().isKeepActive()) {
|
||||
Logic.removeEntity(handler.player);
|
||||
}
|
||||
Data.removePlayerSetting(handler.player);
|
||||
});
|
||||
}
|
||||
|
||||
public static void server() {
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(s -> {
|
||||
Sit.server = s;
|
||||
Sit.commandManager = s.getCommandManager();
|
||||
|
||||
// right click on block event
|
||||
UseBlockCallback.EVENT.register((pl, world, hand, hitResult) -> {
|
||||
// get the server player
|
||||
ServerPlayerEntity player = Sit.server.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 all player settings (singleplayer and such)
|
||||
Data.clearPlayerSettings();
|
||||
});
|
||||
}
|
||||
|
||||
public static void misc() {
|
||||
// loop setup
|
||||
ServerTickEvents.END_SERVER_TICK.register(minecraftServer -> minecraftServer.execute(LoopManager::tick));
|
||||
|
||||
// command setup
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> SitCommand.register(dispatcher));
|
||||
}
|
||||
|
||||
public static void registerCommon() {
|
||||
playerConnections();
|
||||
server();
|
||||
}
|
||||
}
|
117
src/main/java/one/oth3r/sit/utl/Logic.java
Normal file
117
src/main/java/one/oth3r/sit/utl/Logic.java
Normal file
|
@ -0,0 +1,117 @@
|
|||
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.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import one.oth3r.sit.file.Data;
|
||||
import one.oth3r.sit.file.HandConfig;
|
||||
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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
HandConfig handConfig = Data.getPlayerSetting(player);
|
||||
// if can't sit with hand, false
|
||||
if (!handConfig.canSitWithHand()) return false;
|
||||
|
||||
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 = handConfig.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 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
// 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);
|
||||
|
||||
// check if both poses are obstructed or not
|
||||
return Utl.isNotObstructed(entity.getWorld(),pos1) && Utl.isNotObstructed(entity.getWorld(),pos2);
|
||||
}
|
||||
|
||||
/**
|
||||
* reloads the config files
|
||||
*/
|
||||
public static void reload() {
|
||||
Data.loadFiles(false);
|
||||
}
|
||||
|
||||
}
|
56
src/main/java/one/oth3r/sit/utl/LoopManager.java
Normal file
56
src/main/java/one/oth3r/sit/utl/LoopManager.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
package one.oth3r.sit.utl;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.decoration.DisplayEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.file.Data;
|
||||
|
||||
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
|
||||
// todo 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)
|
||||
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(Sit.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
367
src/main/java/one/oth3r/sit/utl/Utl.java
Normal file
367
src/main/java/one/oth3r/sit/utl/Utl.java
Normal file
|
@ -0,0 +1,367 @@
|
|||
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.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.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.tag.TagKey;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.TypeFilter;
|
||||
import net.minecraft.util.UseAction;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import one.oth3r.sit.Sit;
|
||||
import one.oth3r.sit.file.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Utl {
|
||||
|
||||
/**
|
||||
* check if a block is obstructed (no collision / custom list)
|
||||
* @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();
|
||||
}
|
||||
|
||||
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.49;
|
||||
public static final double CARPET = 0.05;
|
||||
|
||||
/**
|
||||
* 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 theres nothing
|
||||
if (itemStack.isEmpty()) return true;
|
||||
|
||||
String itemId = Registries.ITEM.getId(itemStack.getItem()).toString();
|
||||
// check the custom item ids
|
||||
for (String id : filter.getCustomItems()) {
|
||||
// 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;
|
||||
}
|
||||
// check the custom item tags
|
||||
for (String tag : filter.getCustomTags()) {
|
||||
// substring to remove # and if needed, !
|
||||
// if there is a math for the NOT(!) tag, return false
|
||||
if (tag.startsWith("!") && itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), Identifier.of(tag.substring(2))))) return false;
|
||||
// if there is a match, return true
|
||||
if (itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), Identifier.of(tag.substring(1))))) 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);
|
||||
|
||||
// try the default conditions
|
||||
if (filter.isBlock() && itemStack.getItem() instanceof BlockItem) return true;
|
||||
if (filter.isFood() && food.contains(itemStack.getUseAction())) return true;
|
||||
if (filter.isUsable() && !notUsable.contains(itemStack.getUseAction())) return true;
|
||||
|
||||
// if nothing else is met, the item is filtered out
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a block ID (namespace, 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 = Data.getServerConfig();
|
||||
Block block = blockState.getBlock();
|
||||
|
||||
// only if custom is enabled
|
||||
if (config.isCustomEnabled()) {
|
||||
// if the block is on the blacklist, false
|
||||
if (config.getBlacklistedBlocks().contains(getBlockID(blockState))) return null;
|
||||
|
||||
for (CustomBlock customBlock : config.getCustomBlocks()) {
|
||||
// if the block is valid, true
|
||||
if (customBlock.isValid(blockState)) return customBlock.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)
|
||||
// make sure there isn't an action for the block IF the hit isn't null (manual command / no right click check)
|
||||
&& (hit == null || !blockState.onUse(player.getWorld(), player, hit).isAccepted())) return 1.0;
|
||||
|
||||
// at the end, return false
|
||||
return null;
|
||||
}
|
||||
|
||||
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.setCustomName(Text.of(Sit.ENTITY_NAME));
|
||||
entity.setCustomNameVisible(false);
|
||||
entity.setInvulnerable(true);
|
||||
entity.setInvisible(true);
|
||||
|
||||
entity.updatePositionAndAngles(blockPos.getX()+.5, blockPos.getY()+sitHeight, blockPos.getZ()+.5, 0, 0);
|
||||
|
||||
// // 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);
|
||||
|
||||
// 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) {
|
||||
player.getServerWorld().spawnEntity(entity);
|
||||
player.startRiding(entity);
|
||||
// add the entity to the list
|
||||
Data.addSitEntity(player, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes all sit entities loaded on the server
|
||||
*/
|
||||
public static void purge(ServerPlayerEntity player, boolean message) {
|
||||
// todo test if it can 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(Sit.ENTITY_NAME));
|
||||
|
||||
// remove each one
|
||||
for (DisplayEntity.TextDisplayEntity entity : list) {
|
||||
remove(entity);
|
||||
}
|
||||
|
||||
// send a message if needed
|
||||
if (message) {
|
||||
// todo maybe a count for the message for debuging
|
||||
player.sendMessage(Utl.lang("msg.purged"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static MutableText lang(String key, Object... args) {
|
||||
if (Sit.client) return Text.translatable(key, args);
|
||||
else return LangReader.of(key, args).getTxT();
|
||||
}
|
||||
|
||||
// public static class ConfigExamples {
|
||||
// public static final String CUSTOM_BLOCKS = "\"minecraft:campfire|0.255|1|lit=false\"";
|
||||
// public static final String REQUIREMENT_OPTIONS = String.format("%s, %s, %s",
|
||||
// configFile.HandRequirement.empty,configFile.HandRequirement.restrictive,configFile.HandRequirement.none);
|
||||
// public static final String LIST = "\"minecraft:torch\"";
|
||||
// }
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public static class LenientTypeAdapterFactory implements TypeAdapterFactory {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@
|
|||
"one.oth3r.sit.SitClient"
|
||||
],
|
||||
"modmenu": [
|
||||
"one.oth3r.sit.ModMenu"
|
||||
"one.oth3r.sit.screen.ModMenu"
|
||||
]
|
||||
},
|
||||
"depends": {
|
||||
|
@ -34,5 +34,8 @@
|
|||
"suggests": {
|
||||
"yet-another-config-lib": "*",
|
||||
"modmenu": "*"
|
||||
}
|
||||
},
|
||||
"mixins": [
|
||||
"sit!.mixins.json"
|
||||
]
|
||||
}
|
12
src/main/resources/sit!.mixins.json
Normal file
12
src/main/resources/sit!.mixins.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "one.oth3r.sit.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"TextDisplayDismountMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue