Add support for other mods using /locraw
This commit is contained in:
21
src/main/java/moe/nea/firmament/mixins/MixinChatHud.java
Normal file
21
src/main/java/moe/nea/firmament/mixins/MixinChatHud.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package moe.nea.firmament.mixins;
|
||||||
|
|
||||||
|
import moe.nea.firmament.events.ClientChatLineReceivedEvent;
|
||||||
|
import net.minecraft.client.gui.hud.ChatHud;
|
||||||
|
import net.minecraft.client.gui.hud.MessageIndicator;
|
||||||
|
import net.minecraft.network.message.MessageSignatureData;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
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(ChatHud.class)
|
||||||
|
public class MixinChatHud {
|
||||||
|
@Inject(at = @At("HEAD"), method = "addMessage(Lnet/minecraft/text/Text;Lnet/minecraft/network/message/MessageSignatureData;ILnet/minecraft/client/gui/hud/MessageIndicator;Z)V", cancellable = true)
|
||||||
|
public void onAddMessage(Text message, MessageSignatureData signature, int ticks, MessageIndicator indicator, boolean refresh, CallbackInfo ci) {
|
||||||
|
if (ClientChatLineReceivedEvent.Companion.publish(new ClientChatLineReceivedEvent(message)).getCancelled()) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,8 +18,10 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.mixins;
|
package moe.nea.firmament.mixins;
|
||||||
|
|
||||||
|
import moe.nea.firmament.events.OutgoingPacketEvent;
|
||||||
import moe.nea.firmament.events.ParticleSpawnEvent;
|
import moe.nea.firmament.events.ParticleSpawnEvent;
|
||||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||||
|
import net.minecraft.network.packet.Packet;
|
||||||
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
|
import net.minecraft.network.packet.s2c.play.ParticleS2CPacket;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -38,4 +40,11 @@ public class MixinClientPacketHandler {
|
|||||||
packet.isLongDistance()
|
packet.isLongDistance()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
public void onSendPacket(Packet<?> packet, CallbackInfo ci) {
|
||||||
|
if (OutgoingPacketEvent.Companion.publish(new OutgoingPacketEvent(packet)).getCancelled()) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
|
import net.minecraft.text.Text
|
||||||
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Published just before a message is added to the chat gui. Cancelling only prevents rendering, not logging to the
|
||||||
|
* console.
|
||||||
|
*/
|
||||||
|
data class ClientChatLineReceivedEvent(val text: Text) : FirmamentEvent.Cancellable() {
|
||||||
|
val unformattedString = text.unformattedString
|
||||||
|
|
||||||
|
companion object : FirmamentEventBus<ClientChatLineReceivedEvent>()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
|
import net.minecraft.network.packet.Packet
|
||||||
|
|
||||||
|
data class OutgoingPacketEvent(val packet: Packet<*>) : FirmamentEvent.Cancellable() {
|
||||||
|
companion object : FirmamentEventBus<OutgoingPacketEvent>()
|
||||||
|
}
|
||||||
@@ -23,9 +23,9 @@ import moe.nea.firmament.util.unformattedString
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This event gets published whenever the client receives a chat message from the server.
|
* This event gets published whenever the client receives a chat message from the server.
|
||||||
*/
|
* This event is cancellable, but should not get cancelled. Use [ClientChatLineReceivedEvent] for that instead. */
|
||||||
data class ServerChatLineReceivedEvent(val text: Text) : FirmamentEvent.Cancellable() {
|
data class ServerChatLineReceivedEvent(val text: Text) : FirmamentEvent.Cancellable() {
|
||||||
companion object : FirmamentEventBus<ServerChatLineReceivedEvent>()
|
|
||||||
|
|
||||||
val unformattedString = text.unformattedString
|
val unformattedString = text.unformattedString
|
||||||
|
|
||||||
|
companion object : FirmamentEventBus<ServerChatLineReceivedEvent>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,49 +18,81 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.util
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
import java.util.UUID
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.events.ClientChatLineReceivedEvent
|
||||||
|
import moe.nea.firmament.events.OutgoingPacketEvent
|
||||||
import moe.nea.firmament.events.ServerChatLineReceivedEvent
|
import moe.nea.firmament.events.ServerChatLineReceivedEvent
|
||||||
import moe.nea.firmament.events.SkyblockServerUpdateEvent
|
import moe.nea.firmament.events.SkyblockServerUpdateEvent
|
||||||
import moe.nea.firmament.events.WorldReadyEvent
|
import moe.nea.firmament.events.WorldReadyEvent
|
||||||
|
|
||||||
object SBData {
|
object SBData {
|
||||||
val profileRegex = "(?:Your profile was changed to: |You are playing on profile: )(.+)".toRegex()
|
private val profileRegex = "Profile ID: ([a-z0-9\\-]+)".toRegex()
|
||||||
var profileCuteName: String? = null
|
var profileId: UUID? = null
|
||||||
|
|
||||||
private var lastLocrawSent = Timer()
|
private var lastLocrawSent = Timer()
|
||||||
|
private val anyLocrawSent = Timer()
|
||||||
private val locrawRoundtripTime: Duration = 5.seconds
|
private val locrawRoundtripTime: Duration = 5.seconds
|
||||||
|
private var hasReceivedProfile = false
|
||||||
|
private var hasSentLocraw = false
|
||||||
var locraw: Locraw? = null
|
var locraw: Locraw? = null
|
||||||
val skyblockLocation get() = locraw?.skyblockLocation
|
val skyblockLocation: String? get() = locraw?.skyblockLocation
|
||||||
|
val hasValidLocraw get() = locraw?.server !in listOf("limbo", null)
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
|
OutgoingPacketEvent.subscribe { event ->
|
||||||
|
if (event.packet is CommandExecutionC2SPacket && event.packet.command == "locraw") {
|
||||||
|
anyLocrawSent.markNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
ServerChatLineReceivedEvent.subscribe { event ->
|
ServerChatLineReceivedEvent.subscribe { event ->
|
||||||
val profileMatch = profileRegex.matchEntire(event.unformattedString)
|
val profileMatch = profileRegex.matchEntire(event.unformattedString)
|
||||||
if (profileMatch != null) {
|
if (profileMatch != null) {
|
||||||
profileCuteName = profileMatch.groupValues[1]
|
try {
|
||||||
|
profileId = UUID.fromString(profileMatch.groupValues[1])
|
||||||
|
hasReceivedProfile = true
|
||||||
|
if (!hasValidLocraw && !hasSentLocraw && anyLocrawSent.timePassed() > locrawRoundtripTime) {
|
||||||
|
sendLocraw()
|
||||||
|
}
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
profileId = null
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (event.unformattedString.startsWith("{")) {
|
if (event.unformattedString.startsWith("{")) {
|
||||||
if (tryReceiveLocraw(event.unformattedString) && lastLocrawSent.timePassed() < locrawRoundtripTime) {
|
if (tryReceiveLocraw(event.unformattedString)) {
|
||||||
lastLocrawSent.markFarPast()
|
if (!hasValidLocraw && !hasSentLocraw && hasReceivedProfile) {
|
||||||
event.cancel()
|
sendLocraw()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ClientChatLineReceivedEvent.subscribe { event ->
|
||||||
|
if (event.unformattedString.startsWith("{") && tryReceiveLocraw(event.unformattedString) && lastLocrawSent.timePassed() < locrawRoundtripTime) {
|
||||||
|
lastLocrawSent.markFarPast()
|
||||||
|
event.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WorldReadyEvent.subscribe {
|
WorldReadyEvent.subscribe {
|
||||||
sendLocraw()
|
|
||||||
locraw = null
|
locraw = null
|
||||||
|
hasSentLocraw = false
|
||||||
|
hasReceivedProfile = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryReceiveLocraw(unformattedString: String): Boolean = try {
|
private fun tryReceiveLocraw(unformattedString: String, update: Boolean = true): Boolean = try {
|
||||||
val lastLocraw = locraw
|
val lastLocraw = locraw
|
||||||
locraw = Firmament.json.decodeFromString<Locraw>(unformattedString)
|
val n = Firmament.json.decodeFromString<Locraw>(unformattedString)
|
||||||
SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, locraw))
|
if (update) {
|
||||||
|
locraw = n
|
||||||
|
SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, locraw))
|
||||||
|
}
|
||||||
true
|
true
|
||||||
} catch (e: SerializationException) {
|
} catch (e: SerializationException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@@ -71,6 +103,7 @@ object SBData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun sendLocraw() {
|
fun sendLocraw() {
|
||||||
|
hasSentLocraw = true
|
||||||
lastLocrawSent.markNow()
|
lastLocrawSent.markNow()
|
||||||
val nh = MC.player?.networkHandler ?: return
|
val nh = MC.player?.networkHandler ?: return
|
||||||
nh.sendChatCommand("locraw")
|
nh.sendChatCommand("locraw")
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package moe.nea.firmament.util.data
|
package moe.nea.firmament.util.data
|
||||||
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.util.UUID
|
||||||
import kotlinx.serialization.KSerializer
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlin.io.path.createDirectories
|
import kotlin.io.path.createDirectories
|
||||||
import kotlin.io.path.deleteExisting
|
import kotlin.io.path.deleteExisting
|
||||||
@@ -37,10 +38,10 @@ abstract class ProfileSpecificDataHolder<S>(
|
|||||||
private val configDefault: () -> S
|
private val configDefault: () -> S
|
||||||
) : IDataHolder<S?> {
|
) : IDataHolder<S?> {
|
||||||
|
|
||||||
var allConfigs: MutableMap<String, S>
|
var allConfigs: MutableMap<UUID, S>
|
||||||
|
|
||||||
override val data: S?
|
override val data: S?
|
||||||
get() = SBData.profileCuteName?.let {
|
get() = SBData.profileId?.let {
|
||||||
allConfigs.computeIfAbsent(it) { configDefault() }
|
allConfigs.computeIfAbsent(it) { configDefault() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ abstract class ProfileSpecificDataHolder<S>(
|
|||||||
|
|
||||||
private val configDirectory: Path get() = Firmament.CONFIG_DIR.resolve("profiles").resolve(configName)
|
private val configDirectory: Path get() = Firmament.CONFIG_DIR.resolve("profiles").resolve(configName)
|
||||||
|
|
||||||
private fun readValues(): MutableMap<String, S> {
|
private fun readValues(): MutableMap<UUID, S> {
|
||||||
if (!configDirectory.exists()) {
|
if (!configDirectory.exists()) {
|
||||||
configDirectory.createDirectories()
|
configDirectory.createDirectories()
|
||||||
}
|
}
|
||||||
@@ -61,7 +62,7 @@ abstract class ProfileSpecificDataHolder<S>(
|
|||||||
.filter { it.extension == "json" }
|
.filter { it.extension == "json" }
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
try {
|
try {
|
||||||
it.nameWithoutExtension to Firmament.json.decodeFromString(dataSerializer, it.readText())
|
UUID.fromString(it.nameWithoutExtension) to Firmament.json.decodeFromString(dataSerializer, it.readText())
|
||||||
} catch (e: Exception) { /* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/
|
} catch (e: Exception) { /* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/
|
||||||
IDataHolder.badLoads.add(configName)
|
IDataHolder.badLoads.add(configName)
|
||||||
Firmament.logger.error(
|
Firmament.logger.error(
|
||||||
@@ -79,7 +80,7 @@ abstract class ProfileSpecificDataHolder<S>(
|
|||||||
}
|
}
|
||||||
val c = allConfigs
|
val c = allConfigs
|
||||||
configDirectory.listDirectoryEntries().forEach {
|
configDirectory.listDirectoryEntries().forEach {
|
||||||
if (it.nameWithoutExtension !in c) {
|
if (it.nameWithoutExtension !in c.mapKeys { it.toString() }) {
|
||||||
it.deleteExisting()
|
it.deleteExisting()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user