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