diff --git a/build.gradle.kts b/build.gradle.kts index 8ab41227..d276dee6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -55,9 +55,10 @@ dependencies { minecraft("com.mojang:minecraft:${property("minecraft_version")}") mappings(loom.officialMojangMappings()) - implementation("org.luaj:luaj-jse:3.0.1") - include("org.luaj:luaj-jse:3.0.1") - shadowModImpl("org.luaj:luaj-jse:3.0.1") + val luaj = "local:luaj-jse:3.0.2" + implementation(luaj) + include(luaj) + shadowModImpl(luaj) modImplementation("net.fabricmc:fabric-loader:${property("loader_version")}") modImplementation("net.fabricmc.fabric-api:fabric-api:${property("fabric_version")}") diff --git a/gradle.properties b/gradle.properties index 7c5d5c16..fb21c9d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ yarn_mappings=1.21.11+build.4 loader_version=0.18.4 # Mod Properties -mod_version=1.21.11_1.2.1.5.0 +mod_version=1.21.11_1.2.1.5.1 maven_group=com.nekiplay.hypixelcry archives_base_name=hypixel-cry diff --git a/libs/luaj-jse-3.0.2.jar b/libs/luaj-jse-3.0.2.jar new file mode 100644 index 00000000..87440a25 Binary files /dev/null and b/libs/luaj-jse-3.0.2.jar differ diff --git a/src/main/kotlin/com/nekiplay/hypixelcry/features/commands/impl/LuaCommand.kt b/src/main/kotlin/com/nekiplay/hypixelcry/features/commands/impl/LuaCommand.kt index 43ec8f58..5be66f5a 100644 --- a/src/main/kotlin/com/nekiplay/hypixelcry/features/commands/impl/LuaCommand.kt +++ b/src/main/kotlin/com/nekiplay/hypixelcry/features/commands/impl/LuaCommand.kt @@ -11,8 +11,13 @@ import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource import net.minecraft.client.Minecraft import net.minecraft.commands.CommandBuildContext import net.minecraft.network.chat.Component +import org.luaj.vm2.compiler.DumpState +import org.luaj.vm2.compiler.LuaC import java.awt.Desktop +import java.io.ByteArrayOutputStream import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream import java.util.concurrent.CompletableFuture @@ -21,6 +26,10 @@ object LuaCommand { suggestScriptFiles(builder) } + private val SOURCE_SCRIPT_SUGGESTION_PROVIDER = SuggestionProvider { _, builder -> + suggestSourceFiles(builder) + } + private val LOADED_SCRIPT_SUGGESTION_PROVIDER = SuggestionProvider { _, builder -> suggestLoadedScripts(builder) } @@ -83,6 +92,16 @@ object LuaCommand { 1 } ) + .then(ClientCommandManager.literal("compile") + .then(ClientCommandManager.argument("name", StringArgumentType.string()) + .suggests(SOURCE_SCRIPT_SUGGESTION_PROVIDER) + .executes { context -> + val name = StringArgumentType.getString(context, "name") + compileLuaScript(context.source, name) + 1 + } + ) + ) dispatcher.register(luaCommand) } @@ -181,6 +200,28 @@ object LuaCommand { return builder.buildFuture() } + private fun suggestSourceFiles(builder: SuggestionsBuilder): CompletableFuture { + val scriptsDir = File("config/hypixelcry/scripts") + + if (!scriptsDir.exists()) { + return builder.buildFuture() + } + + val input = builder.remainingLowerCase + val scriptFiles = scriptsDir.listFiles { file -> + file.isFile && file.name.endsWith(".lua") + } ?: emptyArray() + + scriptFiles.forEach { file -> + val name = file.nameWithoutExtension + if (name.lowercase().startsWith(input)) { + builder.suggest(name) + } + } + + return builder.buildFuture() + } + private fun suggestLoadedScripts(builder: SuggestionsBuilder): CompletableFuture { val luaManager = HypixelCry.LUA_MANAGER val loadedScripts = luaManager.getLoadedScripts() @@ -347,6 +388,40 @@ object LuaCommand { /** * Рекурсивная отрисовка (остается без изменений из предыдущего ответа) */ + private fun compileLuaScript(source: FabricClientCommandSource, name: String) { + val scriptsDir = File("config/hypixelcry/scripts") + + if (!scriptsDir.exists()) { + source.sendFeedback(Component.literal("${HypixelCry.PREFIX}§cScripts directory does not exist.")) + return + } + + val sourceFile = if (name.endsWith(".lua")) File(scriptsDir, name) + else File(scriptsDir, "$name.lua") + + if (!sourceFile.exists()) { + source.sendFeedback(Component.literal("${HypixelCry.PREFIX}§cSource file §e${sourceFile.name} §cnot found.")) + return + } + + val outputFile = File(scriptsDir, "${sourceFile.nameWithoutExtension}.luac") + + try { + val inputStream = FileInputStream(sourceFile) + val proto = LuaC.instance.compile(inputStream, sourceFile.name) + inputStream.close() + + val outputStream = FileOutputStream(outputFile) + DumpState.dump(proto, outputStream, false) + outputStream.close() + + source.sendFeedback(Component.literal("${HypixelCry.PREFIX}§aCompiled §e${sourceFile.name} §a→ §e${outputFile.name} §7(${outputFile.length()} bytes)")) + } catch (e: Exception) { + source.sendFeedback(Component.literal("${HypixelCry.PREFIX}§cCompilation error: ${e.message}")) + e.printStackTrace() + } + } + private fun renderBeautifulTree( source: FabricClientCommandSource, name: String, diff --git a/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/LuaScript.kt b/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/LuaScript.kt index 262f56b2..97b3a8e3 100644 --- a/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/LuaScript.kt +++ b/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/LuaScript.kt @@ -8,7 +8,6 @@ import com.mojang.brigadier.tree.CommandNode import com.mojang.brigadier.tree.RootCommandNode import com.nekiplay.hypixelcry.HypixelCry import com.nekiplay.hypixelcry.features.lua.objects.datatypes.LuaItemStack -import com.nekiplay.hypixelcry.features.lua.objects.datatypes.LuaLong import com.nekiplay.hypixelcry.features.lua.objects.datatypes.core.LuaBlockPos import com.nekiplay.hypixelcry.features.lua.objects.datatypes.core.LuaDirection import com.nekiplay.hypixelcry.features.lua.objects.datatypes.core.LuaVector3d @@ -42,9 +41,11 @@ import net.minecraft.commands.SharedSuggestionProvider import net.minecraft.commands.synchronization.ArgumentTypeInfos import net.minecraft.core.BlockPos import net.minecraft.core.Direction +import net.minecraft.core.Holder import net.minecraft.network.chat.Component import net.minecraft.network.protocol.game.ClientboundCommandsPacket import net.minecraft.resources.Identifier +import net.minecraft.sounds.SoundEvent import net.minecraft.world.InteractionHand import net.minecraft.world.item.ItemStack import net.minecraft.world.phys.Vec3 @@ -83,6 +84,7 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { private val imguiRenderCallbacks = ArrayList() private val inventoryItemChangeCallbacks = ArrayList() private val particleCallbacks = ArrayList() + private val soundCallbacks = ArrayList() // Packet events private val serverSideRotationCallbacks = ArrayList() @@ -138,13 +140,6 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { } private fun registerEventRegistrationFunctions() { - scriptGlobals.set("registerUnloadCallback", object : VarArgFunction() { - override fun invoke(args: Varargs): Varargs { - val callback = args.arg(1) - return LuaValue.valueOf(addScriptUnloadCallback(callback)) - } - }) - scriptGlobals.set("registerUnloadCallback", object : OneArgFunction() { override fun call(callback: LuaValue): LuaValue { if (!callback.isfunction()) return FALSE @@ -154,6 +149,16 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { } }) + scriptGlobals.set("registerSoundPlay", object : VarArgFunction() { + override fun invoke(args: Varargs): Varargs { + val callback = args.arg(1) + if (!callback.isfunction()) return FALSE + synchronized(callbacksLock) { + return valueOf(soundCallbacks.add(callback)) + } + } + }) + scriptGlobals.set("registerSpawnParticle", object : VarArgFunction() { override fun invoke(args: Varargs): Varargs { val callback = args.arg(1) @@ -347,6 +352,16 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { } private fun registerEventUnregistrationFunctions() { + scriptGlobals.set("unregisterSoundPlay", object : VarArgFunction() { + override fun invoke(args: Varargs): Varargs { + val callback = args.arg(1) + if (!callback.isfunction()) return FALSE + synchronized(callbacksLock) { + return valueOf(soundCallbacks.remove(callback)) + } + } + }) + scriptGlobals.set("unregisterSpawnParticle", object : VarArgFunction() { override fun invoke(args: Varargs): Varargs { val callback = args.arg(1) @@ -834,6 +849,33 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { return allow } + fun onSoundPlay(sound: Holder, x: Double, y: Double, z: Double, pitch: Double, volume: Double): Boolean { + var allow = true + val callbacks = synchronized(callbacksLock) { + soundCallbacks.toTypedArray() + } + + val t = LuaValue.tableOf() + t.set("name", LuaValue.valueOf(sound.registeredName)) + t.set("position", LuaVector3d(Vec3(x, y, z))) + t.set("pitch", LuaValue.valueOf(pitch)) + t.set("volume", LuaValue.valueOf(volume)) + + + for (callback in callbacks) { + try { + val res = callback.call(sound.registeredName, ) + if (res.isboolean() && !res.toboolean()) { + allow = false + } + } catch (e: Exception) { + HypixelCry.LOGGER.error("${HypixelCry.LOG_PREFIX}Error in sound play callback in ${scriptName}", e) + } + } + return allow + } + + fun onAttackBlock(pos: BlockPos, direction: Direction, hand: InteractionHand): Boolean { var allow = true val callbacks = synchronized(callbacksLock) { @@ -1068,8 +1110,7 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { } // Packet events - fun onSpawnParticleEvent(id: Int, x: Double, y: Double, z: Double, xDist: Float, yDist: Float, zDist: Float, maxSpeed: Float, count: Int): Boolean { - var allow = true + fun onSpawnParticleEvent(id: Int, x: Double, y: Double, z: Double, xDist: Float, yDist: Float, zDist: Float, maxSpeed: Float, count: Int) { val callbacks = synchronized(callbacksLock) { particleCallbacks.toTypedArray() } @@ -1092,7 +1133,6 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { HypixelCry.LOGGER.error("${HypixelCry.LOG_PREFIX}Error in particle callback in ${scriptName}: ${e.message}") } } - return allow } fun onServerSideRotationEvent(yaw: Float, pitch: Float): Boolean { @@ -1123,7 +1163,7 @@ class LuaScript(val scriptName: String, private val luaManager: LuaManager) { for (callback in callbacks) { try { - callback.call(LuaLong(dayTime), LuaLong(gameTime), LuaValue.valueOf(tickDayTime)) + callback.call(LuaValue.valueOf(dayTime), LuaValue.valueOf(gameTime), LuaValue.valueOf(tickDayTime)) } catch (e: Exception) { HypixelCry.LOGGER.error("${HypixelCry.LOG_PREFIX}Error in server side time callback in ${scriptName}: ${e.message}") } diff --git a/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/objects/datatypes/LuaLong.kt b/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/objects/datatypes/LuaLong.kt deleted file mode 100644 index 1d102e04..00000000 --- a/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/objects/datatypes/LuaLong.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.nekiplay.hypixelcry.features.lua.objects.datatypes - -import org.luaj.vm2.LuaValue - -class LuaLong(val value: Long) : LuaValue() { - override fun type(): Int = LuaValue.TUSERDATA - override fun typename(): String = "long" - override fun tojstring(): String = value.toString() - override fun toString(): String = value.toString() - - override fun todouble(): Double = value.toDouble() - override fun toint(): Int = value.toInt() - override fun tolong(): Long = value - - override fun add(rhs: LuaValue): LuaValue = LuaLong(value + rhs.tolong()) - override fun sub(rhs: LuaValue): LuaValue = LuaLong(value - rhs.tolong()) - - override fun checklong(): Long = value -} \ No newline at end of file diff --git a/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/objects/misc/FFILib.kt b/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/objects/misc/FFILib.kt index e9e79942..109eb968 100644 --- a/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/objects/misc/FFILib.kt +++ b/src/main/kotlin/com/nekiplay/hypixelcry/features/lua/objects/misc/FFILib.kt @@ -1,16 +1,11 @@ package com.nekiplay.hypixelcry.features.lua.objects.misc -import com.nekiplay.hypixelcry.HypixelCry -import com.nekiplay.hypixelcry.features.lua.objects.datatypes.LuaLong import com.sun.jna.Callback import com.sun.jna.Memory import com.sun.jna.Native import com.sun.jna.NativeLibrary import com.sun.jna.Pointer import com.sun.jna.CallbackReference -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource -import net.minecraft.client.Minecraft -import net.minecraft.network.chat.Component import org.luaj.vm2.LuaNumber import org.luaj.vm2.LuaString import com.sun.jna.Function as JnaFunction @@ -22,7 +17,6 @@ import org.luaj.vm2.lib.OneArgFunction import org.luaj.vm2.lib.ThreeArgFunction import org.luaj.vm2.lib.TwoArgFunction import org.luaj.vm2.lib.VarArgFunction -import java.io.File import java.lang.ref.Cleaner import java.lang.ref.WeakReference import java.util.concurrent.ConcurrentHashMap @@ -509,24 +503,13 @@ class FFILib : LuaTable() { private fun convertArgToLua(arg: Any, type: CType?, ffi: FFILib): LuaValue { return when (arg) { is Int -> valueOf(arg.toDouble()) - is Long -> valueOf(arg.toDouble()) + is Long -> valueOf(arg) is Float -> valueOf(arg.toDouble()) is Double -> valueOf(arg) is Pointer -> CData(arg, typeRegistry["ptr"]!!, ffi) else -> NIL } } - - private fun convertReturnFromLuaInt(res: LuaValue, returnType: CType?): Int { - if (res.isnil()) return 0 - return when (returnType?.name) { - "void" -> 0 - "int" -> res.checkint() - "long" -> res.checklong().toInt() - "float", "double" -> res.checkdouble().toInt() - else -> if (res.isnumber()) res.toint() else 0 - } - } } inner class GcFunction : TwoArgFunction() { diff --git a/src/main/kotlin/com/nekiplay/hypixelcry/features/modules/impl/misc/LuaEvents.kt b/src/main/kotlin/com/nekiplay/hypixelcry/features/modules/impl/misc/LuaEvents.kt index 58159a15..40998ace 100644 --- a/src/main/kotlin/com/nekiplay/hypixelcry/features/modules/impl/misc/LuaEvents.kt +++ b/src/main/kotlin/com/nekiplay/hypixelcry/features/modules/impl/misc/LuaEvents.kt @@ -44,6 +44,7 @@ import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket import net.minecraft.network.protocol.game.ClientboundPlayerRotationPacket import net.minecraft.network.protocol.game.ClientboundRespawnPacket import net.minecraft.network.protocol.game.ClientboundSetTimePacket +import net.minecraft.network.protocol.game.ClientboundSoundPacket import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionResult import net.minecraft.world.entity.player.Player @@ -286,6 +287,14 @@ object LuaEvents : ClientModule() { } } + is ClientboundSoundPacket -> { + val packet = event.packet as ClientboundSoundPacket + + LUA_MANAGER.scripts.values.forEach { script -> + script.onSoundPlay(packet.sound, packet.x, packet.y, packet.z, packet.pitch.toDouble(), packet.volume.toDouble()) + } + } + is ClientboundBlockUpdatePacket -> { val packet = event.packet as ClientboundBlockUpdatePacket diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index f3877524..51382968 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "hypixelcry", - "version": "1.2.1.5.0", + "version": "1.2.1.5.1", "name": "Neo Scripts", "description": "", "authors": [