diff --git a/.gitignore b/.gitignore index 80fadd79..93dfca86 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .gradle/ build/ out/ +.kotlin/ # idea .idea/ diff --git a/build.gradle.kts b/build.gradle.kts index 69b018e1..ac54b08f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,20 +1,19 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { alias(libs.plugins.kotlin) alias(libs.plugins.loom) alias(libs.plugins.detekt) alias(libs.plugins.git.hooks) - alias(libs.plugins.shadow) `maven-publish` } -val props = properties - val modId: String by project val modName: String by project val modVersion: String by project val mavenGroup: String by project -base.archivesBaseName = modId +base.archivesName.set(modId) version = "$modVersion${getVersionMetadata()}" group = mavenGroup @@ -38,8 +37,6 @@ loom { } } -configurations.implementation.get().extendsFrom(configurations.shadow.get()) - fun DependencyHandlerScope.modImplementationAndInclude(dep: Any) { modImplementation(dep) include(dep) @@ -54,6 +51,10 @@ repositories { mavenLocal() } +val includeImplementation: Configuration by configurations.creating { + configurations.implementation.configure { extendsFrom(this@creating) } +} + dependencies { // To change the versions see the libs.versions.toml @@ -75,22 +76,21 @@ dependencies { modImplementation(libs.fabric.kotlin) // Database - shadow(libs.exposed.core) - shadow(libs.exposed.dao) - shadow(libs.exposed.jdbc) - shadow(libs.exposed.java.time) - shadow(libs.sqlite.jdbc) + includeImplementation(libs.exposed.core) + includeImplementation(libs.exposed.dao) + includeImplementation(libs.exposed.java.time) + includeImplementation(libs.exposed.jdbc) + includeImplementation(libs.exposed.migration) + includeImplementation(libs.sqlite.jdbc) // Config - shadow(libs.konf.core) - shadow(libs.konf.toml) + includeImplementation(libs.konf.core) + includeImplementation(libs.konf.toml) detektPlugins(libs.detekt.formatting) } tasks { - val javaVersion = JavaVersion.VERSION_21 - processResources { inputs.property("id", modId) inputs.property("name", modName) @@ -110,70 +110,20 @@ tasks { } } - withType { - options.encoding = "UTF-8" - sourceCompatibility = javaVersion.toString() - targetCompatibility = javaVersion.toString() - options.release.set(javaVersion.toString().toInt()) - } - - compileKotlin { - kotlinOptions { - jvmTarget = javaVersion.toString() - } - } - jar { from("LICENSE") } +} - java { - toolchain { languageVersion.set(JavaLanguageVersion.of(javaVersion.toString())) } - sourceCompatibility = javaVersion - targetCompatibility = javaVersion - withSourcesJar() - } - - remapJar { - dependsOn(shadowJar) - input.set(shadowJar.get().archiveFile) - } - - shadowJar { - from("LICENSE") - - configurations = listOf( - project.configurations.shadow.get() - ) - archiveClassifier.set("dev-all") - - exclude("kotlin/**", "kotlinx/**", "javax/**") - exclude("org/checkerframework/**", "org/intellij/**", "org/jetbrains/annotations/**") - exclude("com/google/gson/**") - exclude("net/kyori/**") - exclude("org/slf4j/**") - - val relocPath = "com.github.quiltservertools.libs." - relocate("com.fasterxml", relocPath + "com.fasterxml") - relocate("com.moandjiezana.toml", relocPath + "com.moandjiezana.toml") - relocate("javassist", relocPath + "javassist") - // Relocate each apache lib separately as just org.apache.commons will relocate things that aren't shadowed and break stuff - relocate("org.apache.commons.lang3", relocPath + "org.apache.commons.lang3") - relocate("org.apache.commons.text", relocPath + "org.apache.commons.text") - relocate("org.reflections", relocPath + "org.reflections") - // it appears you cannot relocate sqlite due to the native libraries - // relocate("org.sqlite", relocPath + "org.sqlite") - } +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + withSourcesJar() +} - compileKotlin { - kotlinOptions { - jvmTarget = javaVersion.toString() - } - } - compileTestKotlin { - kotlinOptions { - jvmTarget = javaVersion.toString() - } +kotlin { + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) } } @@ -194,7 +144,7 @@ publishing { detekt { buildUponDefaultConfig = true autoCorrect = true - config = rootProject.files("detekt.yml") + config.setFrom(rootProject.files("detekt.yml")) } gitHooks { @@ -219,3 +169,42 @@ fun getVersionMetadata(): String { // No tracking information could be found about the build return "+local" } + +afterEvaluate { + dependencies { + handleIncludes(includeImplementation) + } +} + +/* Thanks to https://github.com/jakobkmar for original script */ +fun DependencyHandlerScope.includeTransitive( + dependencies: Set, + minecraftLibs: Set, + kotlinDependency: ResolvedDependency, + checkedDependencies: MutableSet = HashSet() +) { + dependencies.forEach { + if (checkedDependencies.contains(it) || it.moduleGroup == "org.jetbrains.kotlin" || it.moduleGroup == "org.jetbrains.kotlinx") return@forEach + + if (kotlinDependency.children.any { dep -> dep.name == it.name }) { + println("Skipping -> ${it.name} (already in fabric-language-kotlin)") + } else if (minecraftLibs.any { dep -> dep.moduleGroup == it.moduleGroup && dep.moduleName == it.moduleName }) { + println("Skipping -> ${it.name} (already in minecraft)") + } else { + include(it.name) + println("Including -> ${it.name}") + } + checkedDependencies += it + + includeTransitive(it.children, minecraftLibs, kotlinDependency, checkedDependencies) + } +} + +fun DependencyHandlerScope.handleIncludes(configuration: Configuration) { + includeTransitive( + configuration.resolvedConfiguration.firstLevelModuleDependencies, + configurations.minecraftLibraries.get().resolvedConfiguration.firstLevelModuleDependencies, + configurations.modImplementation.get().resolvedConfiguration.firstLevelModuleDependencies + .first { it.moduleGroup == "net.fabricmc" && it.moduleName == "fabric-language-kotlin" }, + ) +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b415..cea7a793 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/libs.versions.toml b/libs.versions.toml index c030e3ba..d9c8e90c 100644 --- a/libs.versions.toml +++ b/libs.versions.toml @@ -6,21 +6,19 @@ fabric-loader = "0.16.9" fabric-api = "0.110.5+1.21.4" # Kotlin -kotlin = "2.0.0" +kotlin = "2.1.0" # Also modrinth version in gradle.properties -fabric-kotlin = "1.11.0+kotlin.2.0.0" +fabric-kotlin = "1.13.0+kotlin.2.1.0" fabric-permissions = "0.3.3" translations = "2.4.0+1.21.2-rc1" -exposed = "0.46.0" -sqlite-jdbc = "3.44.1.0" +exposed = "0.58.0" +sqlite-jdbc = "3.47.2.0" konf = "1.1.2" -wdmcf = "1.0.2" - -detect = "1.23.6" +detekt = "1.23.7" [libraries] minecraft = { module = "net.minecraft:minecraft", version.ref = "minecraft" } @@ -35,20 +33,17 @@ translations = { module = "xyz.nucleoid:server-translations-api", version.ref = exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" } exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" } -exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } exposed-java-time = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" } +exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } +exposed-migration = { module = "org.jetbrains.exposed:exposed-migration", version.ref = "exposed" } sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqlite-jdbc" } konf-core = { module = "com.uchuhimo:konf-core", version.ref = "konf"} konf-toml = { module = "com.uchuhimo:konf-toml", version.ref = "konf"} -detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detect" } - -wdmcf = { module = "me.bymartrixx:wdmcf", version.ref = "wdmcf" } +detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" } [plugins] kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } -detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detect" } -loom = { id = "fabric-loom", version = "1.7.+" } +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } +loom = { id = "fabric-loom", version = "1.9.+" } git_hooks = { id = "com.github.jakemarsden.git-hooks", version = "0.0.2" } -# https://github.com/johnrengelman/shadow/issues/894 -shadow = { id = "io.github.goooler.shadow", version = "8.1.7" } diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/HoeItemMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/HoeItemMixin.java index ef9bcbd7..c735cd76 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/HoeItemMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/HoeItemMixin.java @@ -7,6 +7,7 @@ import net.minecraft.item.ItemConvertible; import net.minecraft.item.ItemUsageContext; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -24,6 +25,7 @@ private static void logHoeInteraction(BlockState state, ItemConvertible itemConv log(state, context); } + @Unique private static void log(BlockState state, ItemUsageContext context) { var player = context.getPlayer(); if (player != null) { diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/SlotMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/SlotMixin.java index cf797b50..66554518 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/SlotMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/SlotMixin.java @@ -21,7 +21,9 @@ @Mixin(Slot.class) public abstract class SlotMixin implements HandledSlot { + @Unique private ScreenHandler handler = null; + @Unique private ItemStack oldStack = null; @Shadow diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/BedBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/BedBlockMixin.java index d1f56d25..73b73ccc 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/BedBlockMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/BedBlockMixin.java @@ -2,10 +2,10 @@ import com.github.quiltservertools.ledger.callbacks.BlockBreakCallback; import com.github.quiltservertools.ledger.utility.Sources; +import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.block.BedBlock; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.enums.BedPart; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.hit.BlockHitResult; @@ -16,20 +16,19 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(BedBlock.class) public abstract class BedBlockMixin { @Unique private BlockEntity oldBlockEntity = null; - @Inject(method = "onBreak", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z"), locals = LocalCapture.CAPTURE_FAILEXCEPTION) - public void storeBlockEntity(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfoReturnable cir, BedPart bedPart, BlockPos blockPos, BlockState blockState) { + @Inject(method = "onBreak", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z")) + public void storeBlockEntity(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfoReturnable cir, @Local(ordinal = 1) BlockPos blockPos) { oldBlockEntity = world.getBlockEntity(blockPos); } - @Inject(method = "onBreak", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION) - public void logBedBreak(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfoReturnable cir, BedPart bedPart, BlockPos blockPos, BlockState blockState) { + @Inject(method = "onBreak", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z", shift = At.Shift.AFTER)) + public void logBedBreak(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfoReturnable cir, @Local(ordinal = 1) BlockPos blockPos, @Local(ordinal = 1) BlockState blockState) { BlockBreakCallback.EVENT.invoker().breakBlock(world, blockPos, blockState, oldBlockEntity, player); } diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/ButtonBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/ButtonBlockMixin.java new file mode 100644 index 00000000..c319844e --- /dev/null +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/ButtonBlockMixin.java @@ -0,0 +1,36 @@ +package com.github.quiltservertools.ledger.mixin.blocks; + +import com.github.quiltservertools.ledger.callbacks.BlockChangeCallback; +import net.minecraft.block.BlockState; +import net.minecraft.block.ButtonBlock; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArgs; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.invoke.arg.Args; + +@Mixin(ButtonBlock.class) +public abstract class ButtonBlockMixin { + @Unique + private PlayerEntity activePlayer; + + @Inject(method = "onUse", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/ButtonBlock;powerOn(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/player/PlayerEntity;)V")) + public void logButtonClick(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit, CallbackInfoReturnable cir) { + activePlayer = player; + } + + @ModifyArgs(method = "powerOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z")) + public void logLeverUse(Args args, BlockState state, World world, BlockPos pos, PlayerEntity playerEntity) { + if (activePlayer == null) return; + + BlockState newState = args.get(1); + BlockChangeCallback.EVENT.invoker().changeBlock(world, pos, state, newState, null, null, activePlayer); + } +} diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/CarvedPumpkinBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/CarvedPumpkinBlockMixin.java index 467e0026..8857ed05 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/CarvedPumpkinBlockMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/CarvedPumpkinBlockMixin.java @@ -2,6 +2,7 @@ import com.github.quiltservertools.ledger.callbacks.BlockBreakCallback; import com.github.quiltservertools.ledger.utility.Sources; +import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.block.CarvedPumpkinBlock; import net.minecraft.block.pattern.BlockPattern; import net.minecraft.block.pattern.CachedBlockPosition; @@ -10,12 +11,11 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(CarvedPumpkinBlock.class) public abstract class CarvedPumpkinBlockMixin { - @Inject(method = "breakPatternBlocks", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION) - private static void logStatueBreak(World world, BlockPattern.Result patternResult, CallbackInfo ci, int i, int j, CachedBlockPosition cachedBlockPosition) { + @Inject(method = "breakPatternBlocks", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z", shift = At.Shift.AFTER)) + private static void logStatueBreak(World world, BlockPattern.Result patternResult, CallbackInfo ci, @Local CachedBlockPosition cachedBlockPosition) { if (cachedBlockPosition.getBlockState().isAir()) { return; } diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/DecoratedPotBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/DecoratedPotBlockMixin.java new file mode 100644 index 00000000..6af1d31c --- /dev/null +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/DecoratedPotBlockMixin.java @@ -0,0 +1,43 @@ +package com.github.quiltservertools.ledger.mixin.blocks; + +import com.github.quiltservertools.ledger.callbacks.BlockBreakCallback; +import com.github.quiltservertools.ledger.callbacks.ItemInsertCallback; +import com.github.quiltservertools.ledger.utility.Sources; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.block.BlockState; +import net.minecraft.block.DecoratedPotBlock; +import net.minecraft.block.entity.DecoratedPotBlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(DecoratedPotBlock.class) +public abstract class DecoratedPotBlockMixin { + @Inject(method = "onUseWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/entity/DecoratedPotBlockEntity;markDirty()V")) + public void logItemInsert(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit, CallbackInfoReturnable cir, @Local DecoratedPotBlockEntity decoratedPotBlockEntity) { + ItemInsertCallback.EVENT.invoker().insert(stack.copyWithCount(1), pos, (ServerWorld) world, Sources.PLAYER, (ServerPlayerEntity) player); + } + + @Inject(method = "onProjectileHit", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z")) + public void logProjectileHit(World world, BlockState state, BlockHitResult hit, ProjectileEntity projectile, CallbackInfo ci) { + if (world.getBlockEntity(hit.getBlockPos()) instanceof DecoratedPotBlockEntity decoratedPotBlockEntity) { + if (projectile.getOwner() instanceof ServerPlayerEntity player) { + BlockBreakCallback.EVENT.invoker().breakBlock(world, hit.getBlockPos(), state, decoratedPotBlockEntity, Sources.PLAYER, player); + } else { + BlockBreakCallback.EVENT.invoker().breakBlock(world, hit.getBlockPos(), state, decoratedPotBlockEntity, Sources.PROJECTILE); + } + } + } +} diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/FireBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/FireBlockMixin.java index 3e7bb097..97488026 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/FireBlockMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/FireBlockMixin.java @@ -2,6 +2,7 @@ import com.github.quiltservertools.ledger.callbacks.BlockBreakCallback; import com.github.quiltservertools.ledger.utility.Sources; +import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.FireBlock; @@ -12,7 +13,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(FireBlock.class) public abstract class FireBlockMixin { @@ -21,10 +21,9 @@ public abstract class FireBlockMixin { at = @At( value = "INVOKE", target = "Lnet/minecraft/world/World;removeBlock(Lnet/minecraft/util/math/BlockPos;Z)Z" - ), - locals = LocalCapture.CAPTURE_FAILEXCEPTION + ) ) - private void ledgerBlockBurnBreakInvoker(World world, BlockPos pos, int spreadFactor, Random random, int currentAge, CallbackInfo ci, int i, BlockState blockState) { + private void ledgerBlockBurnBreakInvoker(World world, BlockPos pos, int spreadFactor, Random random, int currentAge, CallbackInfo ci, @Local BlockState blockState) { if (blockState.getBlock() != Blocks.FIRE) { BlockBreakCallback.EVENT.invoker().breakBlock(world, pos, blockState, world.getBlockEntity(pos) != null ? world.getBlockEntity(pos) : null, Sources.FIRE); } @@ -35,10 +34,9 @@ private void ledgerBlockBurnBreakInvoker(World world, BlockPos pos, int spreadFa at = @At( value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z" - ), - locals = LocalCapture.CAPTURE_FAILEXCEPTION + ) ) - private void ledgerBlockBurnReplaceInvoker(World world, BlockPos pos, int spreadFactor, Random random, int currentAge, CallbackInfo ci, int i, BlockState blockState) { + private void ledgerBlockBurnReplaceInvoker(World world, BlockPos pos, int spreadFactor, Random random, int currentAge, CallbackInfo ci, @Local BlockState blockState) { if (blockState.getBlock() != Blocks.FIRE) { BlockBreakCallback.EVENT.invoker().breakBlock(world, pos, blockState, world.getBlockEntity(pos) != null ? world.getBlockEntity(pos) : null, Sources.FIRE); } diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/JukeBoxBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/JukeboxBlockMixin.java similarity index 97% rename from src/main/java/com/github/quiltservertools/ledger/mixin/blocks/JukeBoxBlockMixin.java rename to src/main/java/com/github/quiltservertools/ledger/mixin/blocks/JukeboxBlockMixin.java index 8902569c..ba5c5799 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/JukeBoxBlockMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/JukeboxBlockMixin.java @@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(JukeboxBlock.class) -public abstract class JukeBoxBlockMixin { +public abstract class JukeboxBlockMixin { @Shadow @Final diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/SpongeBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/SpongeBlockMixin.java index e7cd9485..0ba3f52b 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/SpongeBlockMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/SpongeBlockMixin.java @@ -8,6 +8,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -16,6 +17,7 @@ @Mixin(SpongeBlock.class) public abstract class SpongeBlockMixin { + @Unique private BlockState oldBlockState; @Inject(method = "method_49829", at = @At(value = "INVOKE", @@ -43,7 +45,7 @@ public void ledgerStoreState(World world, BlockPos pos, CallbackInfo ci) { target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;I)Z")) public void ledgerLogSpongeToWetSponge(World world, BlockPos pos, CallbackInfo ci) { BlockState newBlockState = world.getBlockState(pos); - if (oldBlockState == newBlockState) {return;} // if the sponge is already wet dont log + if (oldBlockState == newBlockState) {return;} // if the sponge is already wet don't log BlockChangeCallback.EVENT.invoker().changeBlock(world, pos, oldBlockState, newBlockState, null, null, Sources.WET); // logs if sponge comes into contact with water. } diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/CauldronBehaviorMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/CauldronBehaviorMixin.java index 4cc4acc8..9415ffb1 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/CauldronBehaviorMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/CauldronBehaviorMixin.java @@ -13,6 +13,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -50,6 +51,7 @@ private static void ledgerLogBottleFillEmptyCauldron(BlockState state, World wor ledgerLogFillCauldron(world, pos, state, world.getBlockState(pos), player); } + @Unique private static void ledgerLogDrainCauldron(World world, BlockPos pos, BlockState oldState, PlayerEntity player) { BlockChangeCallback.EVENT.invoker().changeBlock( world, @@ -62,6 +64,7 @@ private static void ledgerLogDrainCauldron(World world, BlockPos pos, BlockState player); } + @Unique private static void ledgerLogFillCauldron(World world, BlockPos pos, BlockState oldState, BlockState newState, PlayerEntity player) { BlockChangeCallback.EVENT.invoker().changeBlock( world, diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/LeveledCauldronBlockMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/LeveledCauldronBlockMixin.java index a615d709..9243d766 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/LeveledCauldronBlockMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/cauldron/LeveledCauldronBlockMixin.java @@ -11,6 +11,7 @@ import net.minecraft.world.World; import net.minecraft.world.biome.Biome; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -18,6 +19,7 @@ @Mixin(LeveledCauldronBlock.class) public abstract class LeveledCauldronBlockMixin { + @Unique private static PlayerEntity playerEntity; @Inject(method = "decrementFluidLevel", at = @At(value = "INVOKE", diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/lectern/LecternScreenHandlerMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/lectern/LecternScreenHandlerMixin.java index f15f07e0..3e283eae 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/lectern/LecternScreenHandlerMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/blocks/lectern/LecternScreenHandlerMixin.java @@ -3,6 +3,7 @@ import com.github.quiltservertools.ledger.callbacks.ItemRemoveCallback; import com.github.quiltservertools.ledger.utility.PlayerLecternHook; import com.github.quiltservertools.ledger.utility.Sources; +import com.llamalad7.mixinextras.sugar.Local; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; @@ -12,12 +13,11 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(LecternScreenHandler.class) public class LecternScreenHandlerMixin { - @Inject(method = "onButtonClick", at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/Inventory;markDirty()V"), locals = LocalCapture.CAPTURE_FAILEXCEPTION) - public void logPickBook(PlayerEntity player, int id, CallbackInfoReturnable cir, ItemStack itemStack) { + @Inject(method = "onButtonClick", at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/Inventory;markDirty()V")) + public void logPickBook(PlayerEntity player, int id, CallbackInfoReturnable cir, @Local ItemStack itemStack) { ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player; BlockEntity blockEntity = PlayerLecternHook.getActiveHandlers().get(player); ItemRemoveCallback.EVENT.invoker().remove(itemStack, blockEntity.getPos(), serverPlayer.getServerWorld(), Sources.PLAYER, serverPlayer); diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/entities/ItemFrameEntityMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/entities/ItemFrameEntityMixin.java index a44c696a..eb678e19 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/entities/ItemFrameEntityMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/entities/ItemFrameEntityMixin.java @@ -12,7 +12,6 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; -import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; diff --git a/src/main/java/com/github/quiltservertools/ledger/mixin/entities/LightningEntityMixin.java b/src/main/java/com/github/quiltservertools/ledger/mixin/entities/LightningEntityMixin.java index 1ab58f67..2da2d966 100644 --- a/src/main/java/com/github/quiltservertools/ledger/mixin/entities/LightningEntityMixin.java +++ b/src/main/java/com/github/quiltservertools/ledger/mixin/entities/LightningEntityMixin.java @@ -10,7 +10,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(LightningEntity.class) public abstract class LightningEntityMixin { diff --git a/src/main/kotlin/com/github/quiltservertools/ledger/Ledger.kt b/src/main/kotlin/com/github/quiltservertools/ledger/Ledger.kt index e84465ac..e677d8d5 100644 --- a/src/main/kotlin/com/github/quiltservertools/ledger/Ledger.kt +++ b/src/main/kotlin/com/github/quiltservertools/ledger/Ledger.kt @@ -71,7 +71,7 @@ object Ledger : DedicatedServerModInitializer, CoroutineScope { if (!Files.exists(FabricLoader.getInstance().configDir.resolve(CONFIG_PATH))) { logInfo("No config file, Creating") Files.copy( - FabricLoader.getInstance().getModContainer(MOD_ID).get().getPath(CONFIG_PATH), + FabricLoader.getInstance().getModContainer(MOD_ID).get().findPath(CONFIG_PATH).get(), FabricLoader.getInstance().configDir.resolve(CONFIG_PATH) ) } diff --git a/src/main/kotlin/com/github/quiltservertools/ledger/database/DatabaseManager.kt b/src/main/kotlin/com/github/quiltservertools/ledger/database/DatabaseManager.kt index 8a2ccd7c..d1f4e055 100644 --- a/src/main/kotlin/com/github/quiltservertools/ledger/database/DatabaseManager.kt +++ b/src/main/kotlin/com/github/quiltservertools/ledger/database/DatabaseManager.kt @@ -1,5 +1,6 @@ package com.github.quiltservertools.ledger.database +import MigrationUtils import com.github.quiltservertools.ledger.Ledger import com.github.quiltservertools.ledger.actions.ActionType import com.github.quiltservertools.ledger.actionutils.ActionSearchParams @@ -33,7 +34,6 @@ import org.jetbrains.exposed.sql.Column import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.Op import org.jetbrains.exposed.sql.Query -import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.inSubQuery @@ -81,6 +81,11 @@ object DatabaseManager { private val cache = DatabaseCacheService private var databaseContext = Dispatchers.IO + CoroutineName("Ledger Database") + private val ledgerLogger = object : SqlLogger { + override fun log(context: StatementContext, transaction: Transaction) { + Ledger.logger.info("SQL: ${context.expandArgs(transaction)}") + } + } @OptIn(ExperimentalCoroutinesApi::class, DelicateCoroutinesApi::class) fun setup(dataSource: DataSource?) { @@ -96,20 +101,16 @@ object DatabaseManager { val dbFilepath = config.getDatabasePath().resolve("ledger.sqlite").pathString return SQLiteDataSource( SQLiteConfig().apply { - setJournalMode(SQLiteConfig.JournalMode.WAL) - } + setJournalMode(SQLiteConfig.JournalMode.WAL) + } ).apply { url = "jdbc:sqlite:$dbFilepath" } } fun ensureTables() = transaction { - addLogger(object : SqlLogger { - override fun log(context: StatementContext, transaction: Transaction) { - Ledger.logger.info("SQL: ${context.expandArgs(transaction)}") - } - }) - SchemaUtils.createMissingTablesAndColumns( + addLogger(ledgerLogger) + MigrationUtils.statementsRequiredForDatabaseMigration( Tables.Players, Tables.Actions, Tables.ActionIdentifiers, @@ -117,7 +118,7 @@ object DatabaseManager { Tables.Sources, Tables.Worlds, withLogs = true - ) + ).forEach(::exec) logInfo("Tables created") } @@ -143,8 +144,7 @@ object DatabaseManager { execute { Ledger.logger.info("Purging actions older than ${config[DatabaseSpec.autoPurgeDays]} days") val deleted = Tables.Actions.deleteWhere { - Tables.Actions.timestamp lessEq Instant.now() - .minus(config[DatabaseSpec.autoPurgeDays].toLong(), ChronoUnit.DAYS) + timestamp lessEq Instant.now().minus(config[DatabaseSpec.autoPurgeDays].toLong(), ChronoUnit.DAYS) } Ledger.logger.info("Successfully purged $deleted actions") } @@ -414,16 +414,12 @@ object DatabaseManager { } return newSuspendedTransaction(context = databaseContext, db = database) { - repetitionAttempts = MAX_QUERY_RETRIES - minRepetitionDelay = MIN_RETRY_DELAY - maxRepetitionDelay = MAX_RETRY_DELAY + maxAttempts = MAX_QUERY_RETRIES + minRetryDelay = MIN_RETRY_DELAY + maxRetryDelay = MAX_RETRY_DELAY if (Ledger.config[DatabaseSpec.logSQL]) { - addLogger(object : SqlLogger { - override fun log(context: StatementContext, transaction: Transaction) { - Ledger.logger.info("SQL: ${context.expandArgs(transaction)}") - } - }) + addLogger(ledgerLogger) } body(this) } @@ -500,8 +496,7 @@ object DatabaseManager { if (totalActions == 0L) return SearchResults(actions, params, page, 0) query = query.orderBy(Tables.Actions.id, SortOrder.DESC) - query = query.limit( - config[SearchSpec.pageSize], + query = query.limit(config[SearchSpec.pageSize]).offset( (config[SearchSpec.pageSize] * (page - 1)).toLong() ) // TODO better pagination without offset - probably doesn't matter as most people stay on first few pages @@ -527,7 +522,7 @@ object DatabaseManager { { Tables.Actions.oldObjectId }, { Tables.oldObjectTable[Tables.ObjectIdentifiers.id] } ) - .innerJoin(Tables.ObjectIdentifiers, { Tables.Actions.objectId }, { Tables.ObjectIdentifiers.id }) + .innerJoin(Tables.ObjectIdentifiers, { Tables.Actions.objectId }, { id }) .innerJoin(Tables.Sources) .selectAll() } @@ -563,7 +558,7 @@ object DatabaseManager { table: EntityClass>, column: Column ): Int? { - cache.getIfPresent(obj)?.let { return it } + cache.getIfPresent(obj!!)?.let { return it } return table.find { column eq mapper.apply(obj) }.firstOrNull()?.id?.value?.also { cache.put(obj, it) } @@ -592,7 +587,7 @@ object DatabaseManager { table.insertAndGetId { it[column] = mapper.apply(obj) } - ].id.value.also { cache.put(obj, it) } + ].id.value.also { cache.put(obj!!, it) } } private fun getOrCreatePlayerId(playerId: UUID): Int = @@ -665,8 +660,7 @@ object DatabaseManager { // Workaround because can't delete from a join in exposed https://kotlinlang.slack.com/archives/C0CG7E0A1/p1605866974117400 private fun Transaction.purgeActions(params: ActionSearchParams) = Tables.Actions .deleteWhere { - Tables.Actions.id inSubQuery Tables.Actions.select(Tables.Actions.id) - .where(buildQueryParams(params)) + id inSubQuery Tables.Actions.select(id).where(buildQueryParams(params)) } private fun Transaction.selectPlayers(players: Set): List { diff --git a/src/main/resources/data/ledger/lang/be_by.json b/src/main/resources/data/ledger/lang/be_by.json new file mode 100644 index 00000000..4015a107 --- /dev/null +++ b/src/main/resources/data/ledger/lang/be_by.json @@ -0,0 +1,78 @@ +{ + "text.ledger.header.search.pos": "--- Пошук журналаў на %s ---", + "text.ledger.header.search": "------ Пошук журналаў ------", + "text.ledger.header.status": "------ Ledger ------", + + "text.ledger.footer.search": "------- %s [Старонка %s з %s] %s -------", + "text.ledger.footer.page_forward": ">>", + "text.ledger.footer.page_forward.hover": "Наступная старонка", + "text.ledger.footer.page_backward": "<<", + "text.ledger.footer.page_backward.hover": "Мінулая старонка", + + "text.ledger.status.queue": "Чэрга базы дадзеных: %s", + "text.ledger.status.queue.busy": "Занята", + "text.ledger.status.queue.empty": "Пуста", + "text.ledger.status.version": "Версія: %s", + "text.ledger.status.discord": "Discord: %s", + "text.ledger.status.discord.join": "Націсніце, каб далучыцца", + "text.ledger.status.db_type": "Тып базы дадзеных: %s", + "text.ledger.status.wiki": "Кіраўніцтва: %s", + "text.ledger.status.wiki.view": "Націсніце для прагляду", + + "text.ledger.preview.start": "Пачатак папярэдняга прагляду", + + "text.ledger.action_message": "%1$s %2$s %3$s %4$s %5$s", + "text.ledger.action_message.time_diff": "%s таму", + "text.ledger.action_message.location.hover": "Націсніце, каб тэлепартавацца", + "text.ledger.action_message.with": "з", + + "text.ledger.rollback.start": "Адкат %s дзеянняў", + "text.ledger.rollback.finish": "Адкат завершаны", + "text.ledger.rollback.fail": "Не ўдалося адкаціць %s x%s", + + "text.ledger.restore.start": "Аднаўленне %s дзеянняў", + "text.ledger.restore.finish": "Аднаўленне завершана", + "text.ledger.restore.fail": "Не ўдалося аднавіць %s x%s", + + "text.ledger.inspect.toggle": "Рэжым агляду: %s", + "text.ledger.inspect.on": "Уключаны", + "text.ledger.inspect.off": "Выключаны", + + "text.ledger.database.busy": "Базы дадзеных зараз занята. Гэта можа заняць некаторы час", + + "error.ledger.no_cached_params": "Няма кэшаванага пошуку. Паспрабуйце спачатку пашукаць", + "error.ledger.command.no_results": "Няма рэзультатаў для гэтага пошуку", + "error.ledger.no_more_pages": "Больш няма старонак", + "error.ledger.unknown_param": "Невядомы параметр %s", + "error.ledger.no_preview": "Няма цякучага папярэдняга прагляду", + "error.ledger.unspecific.range": "Калі ласка, укажыце дыяпазон.", + "error.ledger.unspecific.range_to_big": "Максімальны дыяпазон складае %s.", + "error.ledger.unspecific.source_or_time": "Калі ласка, укажыце крыніцу або час (пасля).", + + "text.ledger.action.block-place": "паставіў", + "text.ledger.action.block-break": "зламаў", + "text.ledger.action.block-change": "змяніў", + "text.ledger.action.item-insert": "паклаў", + "text.ledger.action.item-remove": "узяў", + "text.ledger.action.item-pick-up": "падабраў", + "text.ledger.action.item-drop": "скінуў", + "text.ledger.action.entity-kill": "забіў", + "text.ledger.action.entity-change": "змяніў", + + "text.ledger.parameter.action.description": "Фільтраваць па тыпу выкананага дзеяння.", + "text.ledger.parameter.after.description": "Фільтраваць па часе (пасля вызначанага часу).", + "text.ledger.parameter.before.description": "Фільтраваць па часе (да вызначанага часу). Звычайна варта выкарыстоўваць пасля.", + "text.ledger.parameter.object.description": "Фільтраваць па аб'ектах. Гэта можа быць блок, прадмет або сутнасць.", + "text.ledger.parameter.range.description": "Фільтраваць па месцазнаходжанне (квадратны радыус вакол вашага месцазнаходжання).", + "text.ledger.parameter.rolledback.description": "Фільтраваць па адкачаным стане.", + "text.ledger.parameter.source.description": "Фільтраваць па крыніцы (імя гульца або крыніца з '@').", + "text.ledger.parameter.world.description": "Фільтраваць па ўказаным свеце.", + + "text.ledger.network.protocols_mismatched": "Несумяшчальнасць версіі пратакола: версія пратакола мода Ledger %d, а версія кліента %d", + "text.ledger.network.no_mod_info": "Немагчыма вызначыць інфармацыю пра мод для вашага кліента", + + "text.ledger.purge.starting": "------ Пачатак чысткі ------", + "text.ledger.purge.complete": "------ Чыстка завершана ------", + + "text.ledger.player.result": "%1$s: Упершыню далучыўся %2$s. Апошні раз далучыўся: %3$s" +} \ No newline at end of file diff --git a/src/main/resources/data/ledger/lang/be_latn.json b/src/main/resources/data/ledger/lang/be_latn.json new file mode 100644 index 00000000..df5cff42 --- /dev/null +++ b/src/main/resources/data/ledger/lang/be_latn.json @@ -0,0 +1,78 @@ +{ + "text.ledger.header.search.pos": "--- Pošuk žurnalaŭ na %s ---", + "text.ledger.header.search": "------ Pošuk žurnalaŭ ------", + "text.ledger.header.status": "------ Ledger ------", + + "text.ledger.footer.search": "------- %s [Staronka %s z %s] %s -------", + "text.ledger.footer.page_forward": ">>", + "text.ledger.footer.page_forward.hover": "Nastupnaja staronka", + "text.ledger.footer.page_backward": "<<", + "text.ledger.footer.page_backward.hover": "Minulaja staronka", + + "text.ledger.status.queue": "Čerha bazy dadzienych: %s", + "text.ledger.status.queue.busy": "Zaniata", + "text.ledger.status.queue.empty": "Pusta", + "text.ledger.status.version": "Viersija: %s", + "text.ledger.status.discord": "Discord: %s", + "text.ledger.status.discord.join": "Nacisnicie, kab dalučycca", + "text.ledger.status.db_type": "Typ bazy dadzienych: %s", + "text.ledger.status.wiki": "Kiraŭnictva: %s", + "text.ledger.status.wiki.view": "Nacisnicie dlia prahliadu", + + "text.ledger.preview.start": "Pačatak papiaredniaha prahliadu", + + "text.ledger.action_message": "%1$s %2$s %3$s %4$s %5$s", + "text.ledger.action_message.time_diff": "%s tamu", + "text.ledger.action_message.location.hover": "Nacisnicie, kab teliepartavacca", + "text.ledger.action_message.with": "z", + + "text.ledger.rollback.start": "Adkat %s dziejanniaŭ", + "text.ledger.rollback.finish": "Adkat zavieršany", + "text.ledger.rollback.fail": "Nie ŭdalosia adkacić %s x%s", + + "text.ledger.restore.start": "Adnaŭliennie %s dziejanniaŭ", + "text.ledger.restore.finish": "Adnaŭliennie zavieršana", + "text.ledger.restore.fail": "Nie ŭdalosia adnavić %s x%s", + + "text.ledger.inspect.toggle": "Režym ahliadu: %s", + "text.ledger.inspect.on": "Ukliučany", + "text.ledger.inspect.off": "Vykliučany", + + "text.ledger.database.busy": "Bazy dadzienych zaraz zaniata. Heta moža zaniać niekatory čas", + + "error.ledger.no_cached_params": "Niama kešavanaha pošuku. Pasprabujcie spačatku pašukać", + "error.ledger.command.no_results": "Niama rezuĺtataŭ dlia hetaha pošuku", + "error.ledger.no_more_pages": "Boĺš niama staronak", + "error.ledger.unknown_param": "Nieviadomy paramietr %s", + "error.ledger.no_preview": "Niama ciakučaha papiaredniaha prahliadu", + "error.ledger.unspecific.range": "Kali laska, ukažycie dyjapazon.", + "error.ledger.unspecific.range_to_big": "Maksimaĺny dyjapazon skladaje %s.", + "error.ledger.unspecific.source_or_time": "Kali laska, ukažycie krynicu abo čas (paslia).", + + "text.ledger.action.block-place": "pastaviŭ", + "text.ledger.action.block-break": "zlamaŭ", + "text.ledger.action.block-change": "zmianiŭ", + "text.ledger.action.item-insert": "paklaŭ", + "text.ledger.action.item-remove": "uziaŭ", + "text.ledger.action.item-pick-up": "padabraŭ", + "text.ledger.action.item-drop": "skinuŭ", + "text.ledger.action.entity-kill": "zabiŭ", + "text.ledger.action.entity-change": "zmianiŭ", + + "text.ledger.parameter.action.description": "Fiĺtravać pa typu vykananaha dziejannia.", + "text.ledger.parameter.after.description": "Fiĺtravać pa časie (paslia vyznačanaha času).", + "text.ledger.parameter.before.description": "Fiĺtravać pa časie (da vyznačanaha času). Zvyčajna varta vykarystoŭvać paslia.", + "text.ledger.parameter.object.description": "Fiĺtravać pa abjektach. Heta moža być blok, pradmiet abo sutnasć.", + "text.ledger.parameter.range.description": "Fiĺtravać pa miescaznachodžannie (kvadratny radyus vakol vašaha miescaznachodžannia).", + "text.ledger.parameter.rolledback.description": "Fiĺtravać pa adkačanym stanie.", + "text.ledger.parameter.source.description": "Fiĺtravać pa krynicy (imia huĺca abo krynica z ’@’).", + "text.ledger.parameter.world.description": "Fiĺtravać pa ŭkazanym sviecie.", + + "text.ledger.network.protocols_mismatched": "Niesumiaščaĺnasć viersii pratakola: viersija pratakola moda Ledger %d, a viersija klijenta %d", + "text.ledger.network.no_mod_info": "Niemahčyma vyznačyć infarmacyju pra mod dlia vašaha klijenta", + + "text.ledger.purge.starting": "------ Pačatak čystki ------", + "text.ledger.purge.complete": "------ Čystka zavieršana ------", + + "text.ledger.player.result": "%1$s: Upieršyniu dalučyŭsia %2$s. Apošni raz dalučyŭsia: %3$s" +} \ No newline at end of file diff --git a/src/main/resources/data/ledger/lang/uk_ua.json b/src/main/resources/data/ledger/lang/uk_ua.json index b083ce33..73757ed1 100644 --- a/src/main/resources/data/ledger/lang/uk_ua.json +++ b/src/main/resources/data/ledger/lang/uk_ua.json @@ -13,7 +13,7 @@ "text.ledger.status.queue.busy": "Зайнято", "text.ledger.status.queue.empty": "Порожньо", "text.ledger.status.version": "Версія: %s", - "text.ledger.status.discord": "Дискорд: %s", + "text.ledger.status.discord": "Discord: %s", "text.ledger.status.discord.join": "Натисніть, щоб приєднатися", "text.ledger.status.db_type": "Тип бази даних: %s", "text.ledger.status.wiki": "Керівництво: %s", @@ -45,22 +45,34 @@ "error.ledger.no_more_pages": "Більше немає сторінок", "error.ledger.unknown_param": "Невідомий параметр %s", "error.ledger.no_preview": "Немає поточного попереднього перегляду", + "error.ledger.unspecific.range": "Будь ласка, вкажіть діапазон.", + "error.ledger.unspecific.range_to_big": "Максимальний діапазон становить %s.", + "error.ledger.unspecific.source_or_time": "Будь ласка, вкажіть джерело або час (після).", "text.ledger.action.block-place": "розмістив", "text.ledger.action.block-break": "зламав", "text.ledger.action.block-change": "змінив", - "text.ledger.action.item-insert": "додав", - "text.ledger.action.item-remove": "видалив", + "text.ledger.action.item-insert": "поклав", + "text.ledger.action.item-remove": "взяв", "text.ledger.action.item-pick-up": "підібрав", "text.ledger.action.item-drop": "скинув", "text.ledger.action.entity-kill": "вбив", "text.ledger.action.entity-change": "змінив", - "text.ledger.network.protocols_mismatched": "Невідповідність версій протоколу: клієнтський мод – це версія протоколу Ledger %d, а версія клієнта – %d", - "text.ledger.network.no_mod_info": "Неможливо визначити інформацію для вашого клієнтського моду", + "text.ledger.parameter.action.description": "Фільтрувати за типом виконаної дії.", + "text.ledger.parameter.after.description": "Фільтрувати за часом (після вказаного часу).", + "text.ledger.parameter.before.description": "Фільтрувати за часом (до вказаного часу). Зазвичай слід використовувати після.", + "text.ledger.parameter.object.description": "Фільтрувати за об'єктом. Це може бути блок, предмет або сутність.", + "text.ledger.parameter.range.description": "Фільтрувати за локацією (квадратний радіус навколо вашого місця розташування).", + "text.ledger.parameter.rolledback.description": "Фільтрувати за відкоченим станом.", + "text.ledger.parameter.source.description": "Фільтрувати за джерелом (ім'я гравця або джерело з '@').", + "text.ledger.parameter.world.description": "Фільтрувати за вказаним виміром.", + + "text.ledger.network.protocols_mismatched": "Несумісність версій протоколу: версія протоколу моду Ledger %d, а версія клієнта %d", + "text.ledger.network.no_mod_info": "Неможливо визначити інформацію про мод для вашого клієнтського моду", "text.ledger.purge.starting": "------ Початок очищення ------", - "text.ledger.purge.complete": "------ Очищення завершене ------", + "text.ledger.purge.complete": "------ Очищення завершено ------", - "text.ledger.player.result": "%1$s: Вперше приєднався: %2$s. Востаннє приєднався: %3$s" + "text.ledger.player.result": "%1$s: Вперше приєднався %2$s. Востаннє приєднався: %3$s" } \ No newline at end of file diff --git a/src/main/resources/ledger.mixins.json b/src/main/resources/ledger.mixins.json index f9077a96..512c4737 100644 --- a/src/main/resources/ledger.mixins.json +++ b/src/main/resources/ledger.mixins.json @@ -12,7 +12,7 @@ "CampfireBlockEntityMixin", "DoubleInventoryMixin", "DyeItemMixin", - "ExplosionImplMixin", + "ExplosionImplMixin", "FillCommandMixin", "FlintAndSteelItemMixin", "FrostWalkerEnchantmentMixin", @@ -30,6 +30,7 @@ "blocks.AbstractPlantStemBlockMixin", "blocks.BambooBlockMixin", "blocks.BedBlockMixin", + "blocks.ButtonBlockMixin", "blocks.CactusBlockMixin", "blocks.CakeBlockMixin", "blocks.CampfireBlockMixin", @@ -39,6 +40,7 @@ "blocks.ChorusPlantBlockMixin", "blocks.ComparatorBlockMixin", "blocks.DaylightDetectorBlockMixin", + "blocks.DecoratedPotBlockMixin", "blocks.DoorBlockMixin", "blocks.FarmlandBlockMixin", "blocks.FenceGateBlockMixin", @@ -46,7 +48,7 @@ "blocks.FlowerPotBlockMixin", "blocks.FluidBlockMixin", "blocks.IceBlockMixin", - "blocks.JukeBoxBlockMixin", + "blocks.JukeboxBlockMixin", "blocks.LeavesBlockMixin", "blocks.LeverBlockMixin", "blocks.LilyPadBlockMixin", @@ -84,11 +86,11 @@ "entities.ItemFrameEntityMixin", "entities.LightningEntityMixin", "entities.LivingEntityMixin", - "entities.ServerPlayerEntityMixin", + "entities.MobEntityMixin", "entities.RavagerEntityMixin", + "entities.ServerPlayerEntityMixin", "entities.SheepEntityMixin", "entities.SnowGolemEntityMixin", - "entities.MobEntityMixin", "entities.WolfEntityMixin", "entities.silverfish.CallForHelpGoalMixin", "entities.silverfish.WanderAndInfestGoalMixin",