Fairy souls
This commit is contained in:
@@ -4,3 +4,11 @@
|
||||
|
||||
### Building your own
|
||||
|
||||
Use Java 17.
|
||||
|
||||
This depends on [neurepoparsing](https://git.nea.moe/nea/neurepoparsing/). Please clone that repository and make it available in your local maven repository using `./gradlew publishToMavenLocal`. This will be automated at a later stage.
|
||||
|
||||
|
||||
Afterwards, running `./gradlew build` will create a mod jar in `build/libs`
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ plugins {
|
||||
id("dev.architectury.loom") version "0.12.0.+"
|
||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||
id("moe.nea.licenseextractificator") version "fffc76c"
|
||||
id("com.github.eutro.hierarchical-lang") version "1.1.3"
|
||||
id("io.github.juuxel.loom-quiltflower") version "1.7.2"
|
||||
id("io.github.juuxel.loom-quiltflower") version "1.7.3"
|
||||
}
|
||||
|
||||
loom {
|
||||
@@ -24,6 +23,12 @@ loom {
|
||||
property("notenoughupdates.debug", "true")
|
||||
}
|
||||
}
|
||||
runs {
|
||||
named("client") {
|
||||
vmArg("-XX:+AllowEnhancedClassRedefinition")
|
||||
vmArg("-XX:HotswapAgent=fatjar")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -59,12 +64,16 @@ dependencies {
|
||||
modImplementation("net.fabricmc:fabric-loader:${project.property("fabric_loader_version")}")
|
||||
modApi("net.fabricmc.fabric-api:fabric-api:${project.property("fabric_api_version")}")
|
||||
modImplementation("net.fabricmc:fabric-language-kotlin:${project.property("fabric_kotlin_version")}")
|
||||
modApi("dev.architectury:architectury:6.2.46")
|
||||
|
||||
// Actual dependencies
|
||||
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api:${rootProject.property("rei_version")}")
|
||||
modCompileOnly("me.shedaniel:RoughlyEnoughItems-api:${rootProject.property("rei_version")}") {
|
||||
exclude(module = "architectury")
|
||||
exclude(module = "architectury-fabric")
|
||||
}
|
||||
shadowMe("io.github.moulberry:neurepoparser:0.0.1")
|
||||
shadowMe("com.github.hypfvieh:dbus-java-core:4.1.0")
|
||||
shadowMe("com.github.hypfvieh:dbus-java-transport-native-unixsocket:4.1.0")
|
||||
shadowMe("com.github.hypfvieh:dbus-java-core:${rootProject.property("dbus_java_version")}")
|
||||
shadowMe("com.github.hypfvieh:dbus-java-transport-native-unixsocket:${rootProject.property("dbus_java_version")}")
|
||||
fun ktor(mod: String) = "io.ktor:ktor-$mod-jvm:${project.property("ktor_version")}"
|
||||
|
||||
transInclude(implementation(ktor("client-core"))!!)
|
||||
@@ -74,7 +83,11 @@ dependencies {
|
||||
modImplementation(include("io.github.cottonmc:LibGui:${project.property("libgui_version")}")!!)
|
||||
|
||||
// Dev environment preinstalled mods
|
||||
modRuntimeOnly("me.shedaniel:RoughlyEnoughItems-fabric:${project.property("rei_version")}")
|
||||
modRuntimeOnly("dev.architectury:architectury-fabric:6.2.46")
|
||||
modRuntimeOnly("me.shedaniel:RoughlyEnoughItems-fabric:${project.property("rei_version")}") {
|
||||
exclude(module = "architectury")
|
||||
exclude(module = "architectury-fabric")
|
||||
}
|
||||
modRuntimeOnly("me.djtheredstoner:DevAuth-fabric:${project.property("devauth_version")}")
|
||||
modRuntimeOnly("maven.modrinth:modmenu:${project.property("modmenu_version")}")
|
||||
|
||||
@@ -126,7 +139,7 @@ tasks.processResources {
|
||||
)
|
||||
}
|
||||
filesMatching("**/lang/*.json") {
|
||||
flattenJson(this)
|
||||
// flattenJson(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,15 +8,15 @@ archives_base_name=notenoughupdates
|
||||
mod_version=1.0.0
|
||||
maven_group=moe.nea.notenoughupdates
|
||||
|
||||
architectury_version=5.10.33
|
||||
|
||||
fabric_loader_version=0.14.8
|
||||
fabric_api_version=0.58.0+1.19
|
||||
fabric_loader_version=0.14.9
|
||||
fabric_api_version=0.60.0+1.19.2
|
||||
fabric_kotlin_version=1.8.2+kotlin.1.7.10
|
||||
yarn_version=1.19.2+build.9
|
||||
|
||||
libgui_version=6.0.0+1.19
|
||||
rei_version=9.1.518
|
||||
libgui_version=6.1.0+1.19
|
||||
rei_version=9.1.537
|
||||
devauth_version=1.0.0
|
||||
modmenu_version=4.0.4
|
||||
modmenu_version=4.0.6
|
||||
ktor_version=2.0.3
|
||||
|
||||
dbus_java_version=4.2.0
|
||||
|
||||
@@ -5,12 +5,8 @@ import io.ktor.client.*
|
||||
import io.ktor.client.plugins.*
|
||||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import moe.nea.notenoughupdates.commands.registerNeuCommand
|
||||
import moe.nea.notenoughupdates.dbus.NEUDbusObject
|
||||
import moe.nea.notenoughupdates.repo.RepoManager
|
||||
import moe.nea.notenoughupdates.util.ConfigHolder
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import net.fabricmc.api.ClientModInitializer
|
||||
import net.fabricmc.api.ModInitializer
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback
|
||||
@@ -19,13 +15,18 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
|
||||
import net.fabricmc.loader.api.FabricLoader
|
||||
import net.fabricmc.loader.api.Version
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata
|
||||
import net.minecraft.command.CommandRegistryAccess
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import net.minecraft.command.CommandRegistryAccess
|
||||
import moe.nea.notenoughupdates.commands.registerNeuCommand
|
||||
import moe.nea.notenoughupdates.dbus.NEUDbusObject
|
||||
import moe.nea.notenoughupdates.features.FeatureManager
|
||||
import moe.nea.notenoughupdates.repo.RepoManager
|
||||
import moe.nea.notenoughupdates.util.SBData
|
||||
import moe.nea.notenoughupdates.util.config.IConfigHolder
|
||||
|
||||
object NotEnoughUpdates : ModInitializer, ClientModInitializer {
|
||||
const val MOD_ID = "notenoughupdates"
|
||||
@@ -59,7 +60,6 @@ object NotEnoughUpdates : ModInitializer, ClientModInitializer {
|
||||
.build()
|
||||
val coroutineScope =
|
||||
CoroutineScope(EmptyCoroutineContext + CoroutineName("NotEnoughUpdates")) + SupervisorJob(globalJob)
|
||||
val coroutineScopeIo = coroutineScope + Dispatchers.IO + SupervisorJob(globalJob)
|
||||
|
||||
private fun registerCommands(
|
||||
dispatcher: CommandDispatcher<FabricClientCommandSource>,
|
||||
@@ -72,8 +72,9 @@ object NotEnoughUpdates : ModInitializer, ClientModInitializer {
|
||||
override fun onInitialize() {
|
||||
dbusConnection.requestBusName("moe.nea.notenoughupdates")
|
||||
dbusConnection.exportObject(NEUDbusObject)
|
||||
ConfigHolder.registerEvents()
|
||||
IConfigHolder.registerEvents()
|
||||
RepoManager.initialize()
|
||||
SBData.init()
|
||||
FeatureManager.autoload()
|
||||
ClientCommandRegistrationCallback.EVENT.register(this::registerCommands)
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
|
||||
|
||||
@@ -2,11 +2,12 @@ package moe.nea.notenoughupdates.commands
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import io.github.cottonmc.cotton.gui.client.CottonClientScreen
|
||||
import moe.nea.notenoughupdates.gui.repoGui
|
||||
import moe.nea.notenoughupdates.repo.RepoManager
|
||||
import moe.nea.notenoughupdates.util.ScreenUtil.setScreenLater
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.notenoughupdates.gui.repoGui
|
||||
import moe.nea.notenoughupdates.repo.RepoManager
|
||||
import moe.nea.notenoughupdates.util.SBData
|
||||
import moe.nea.notenoughupdates.util.ScreenUtil.setScreenLater
|
||||
|
||||
|
||||
fun neuCommand() = literal("neu") {
|
||||
@@ -27,6 +28,23 @@ fun neuCommand() = literal("neu") {
|
||||
setScreenLater(CottonClientScreen(repoGui()))
|
||||
}
|
||||
}
|
||||
thenLiteral("dev") {
|
||||
val sbData = thenLiteral("sbdata") {
|
||||
thenExecute {
|
||||
source.sendFeedback(Text.translatable("notenoughupdates.sbinfo.profile", SBData.profileCuteName))
|
||||
val locrawInfo = SBData.locraw
|
||||
if (locrawInfo == null) {
|
||||
source.sendFeedback(Text.translatable("notenoughupdates.sbinfo.nolocraw"))
|
||||
} else {
|
||||
source.sendFeedback(Text.translatable("notenoughupdates.sbinfo.server", locrawInfo.server))
|
||||
source.sendFeedback(Text.translatable("notenoughupdates.sbinfo.gametype", locrawInfo.gametype))
|
||||
source.sendFeedback(Text.translatable("notenoughupdates.sbinfo.mode", locrawInfo.mode))
|
||||
source.sendFeedback(Text.translatable("notenoughupdates.sbinfo.map", locrawInfo.map))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,36 @@
|
||||
package moe.nea.notenoughupdates.events
|
||||
|
||||
/**
|
||||
* An event that can be fired by a [NEUEventBus].
|
||||
*
|
||||
* Typically, that event bus is implemented as a companion object
|
||||
*
|
||||
* ```
|
||||
* class SomeEvent : NEUEvent() {
|
||||
* companion object : NEUEventBus<SomeEvent>()
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
abstract class NEUEvent {
|
||||
/**
|
||||
* A [NEUEvent] that can be [cancelled]
|
||||
*/
|
||||
abstract class Cancellable : NEUEvent() {
|
||||
/**
|
||||
* Cancels this is event.
|
||||
*
|
||||
* @see cancelled
|
||||
*/
|
||||
fun cancel() {
|
||||
cancelled = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this event is cancelled.
|
||||
*
|
||||
* Cancelled events will bypass handlers unless otherwise specified and will prevent the action that this
|
||||
* event was originally fired for.
|
||||
*/
|
||||
var cancelled: Boolean = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
package moe.nea.notenoughupdates.events
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
|
||||
/**
|
||||
* A pubsub event bus.
|
||||
*
|
||||
* [subscribe] to events [publish]ed on this event bus.
|
||||
* Subscriptions may not necessarily be delivered in the order or registering.
|
||||
*/
|
||||
open class NEUEventBus<T : NEUEvent> {
|
||||
data class Handler<T>(val invocation: (T) -> Unit, val receivesCancelled: Boolean)
|
||||
|
||||
@@ -17,7 +24,11 @@ open class NEUEventBus<T : NEUEvent> {
|
||||
fun publish(event: T): T {
|
||||
for (function in toHandle) {
|
||||
if (function.receivesCancelled || event !is NEUEvent.Cancellable || !event.cancelled) {
|
||||
try {
|
||||
function.invocation(event)
|
||||
} catch (e: Exception) {
|
||||
NotEnoughUpdates.logger.error("Caught exception during processing event $event", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return event
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package moe.nea.notenoughupdates.events
|
||||
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.notenoughupdates.util.unformattedString
|
||||
|
||||
/**
|
||||
* This event gets published whenever the client receives a chat message from the server.
|
||||
*/
|
||||
data class ServerChatLineReceivedEvent(val text: Text) : NEUEvent.Cancellable() {
|
||||
companion object : NEUEventBus<ServerChatLineReceivedEvent>()
|
||||
|
||||
val unformattedString = text.unformattedString
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package moe.nea.notenoughupdates.events
|
||||
|
||||
import moe.nea.notenoughupdates.util.Locraw
|
||||
|
||||
/**
|
||||
* This event gets published whenever `/locraw` is queried and HyPixel returns a location different to the old one.
|
||||
*
|
||||
* **N.B.:** This event may get fired multiple times while on the server (for example, first to null, then to the
|
||||
* correct location).
|
||||
*/
|
||||
data class SkyblockServerUpdateEvent(val oldLocraw: Locraw?, val newLocraw: Locraw?) : NEUEvent() {
|
||||
companion object : NEUEventBus<SkyblockServerUpdateEvent>()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package moe.nea.notenoughupdates.events
|
||||
|
||||
import net.minecraft.client.render.Camera
|
||||
import net.minecraft.client.render.GameRenderer
|
||||
import net.minecraft.client.render.LightmapTextureManager
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.math.Matrix4f
|
||||
|
||||
/**
|
||||
* This event is called after all world rendering is done, but before any GUI rendering (including hand) has been done.
|
||||
*/
|
||||
data class WorldRenderLastEvent(
|
||||
val matrices: MatrixStack,
|
||||
val tickDelta: Float,
|
||||
val renderBlockOutline: Boolean,
|
||||
val camera: Camera,
|
||||
val gameRenderer: GameRenderer,
|
||||
val lightmapTextureManager: LightmapTextureManager,
|
||||
val positionMatrix: Matrix4f,
|
||||
) : NEUEvent() {
|
||||
companion object : NEUEventBus<WorldRenderLastEvent>()
|
||||
}
|
||||
@@ -1,27 +1,42 @@
|
||||
package moe.nea.notenoughupdates.features
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.serializer
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
import moe.nea.notenoughupdates.features.world.FairySouls
|
||||
import moe.nea.notenoughupdates.util.ConfigHolder
|
||||
import moe.nea.notenoughupdates.util.config.ConfigHolder
|
||||
|
||||
object FeatureManager : ConfigHolder<FeatureManager.Config>(serializer(), "features", ::Config) {
|
||||
@Serializable
|
||||
data class Config(
|
||||
val enabledFeatures: MutableMap<String, Boolean> = mutableMapOf()
|
||||
)
|
||||
|
||||
private val features = mutableMapOf<String, NEUFeature>()
|
||||
|
||||
private var hasAutoloaded = false
|
||||
|
||||
init {
|
||||
autoload()
|
||||
}
|
||||
|
||||
fun autoload() {
|
||||
synchronized(this) {
|
||||
if (hasAutoloaded) return
|
||||
loadFeature(FairySouls)
|
||||
hasAutoloaded = true
|
||||
}
|
||||
}
|
||||
|
||||
fun loadFeature(feature: NEUFeature) {
|
||||
synchronized(features) {
|
||||
if (feature.identifier in features) {
|
||||
NotEnoughUpdates.logger.error("Double registering feature ${feature.identifier}. Ignoring second instance $feature")
|
||||
return
|
||||
}
|
||||
features[feature.identifier] = feature
|
||||
feature.onLoad()
|
||||
}
|
||||
}
|
||||
|
||||
fun isEnabled(identifier: String): Boolean? =
|
||||
|
||||
@@ -1,12 +1,103 @@
|
||||
package moe.nea.notenoughupdates.features.world
|
||||
|
||||
import io.github.moulberry.repo.data.Coordinate
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.serializer
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import moe.nea.notenoughupdates.events.ServerChatLineReceivedEvent
|
||||
import moe.nea.notenoughupdates.events.SkyblockServerUpdateEvent
|
||||
import moe.nea.notenoughupdates.events.WorldRenderLastEvent
|
||||
import moe.nea.notenoughupdates.features.NEUFeature
|
||||
import moe.nea.notenoughupdates.repo.RepoManager
|
||||
import moe.nea.notenoughupdates.util.MC
|
||||
import moe.nea.notenoughupdates.util.SBData
|
||||
import moe.nea.notenoughupdates.util.config.ProfileSpecificConfigHolder
|
||||
import moe.nea.notenoughupdates.util.render.RenderBlockContext.Companion.renderBlocks
|
||||
import moe.nea.notenoughupdates.util.unformattedString
|
||||
|
||||
val Coordinate.blockPos: BlockPos
|
||||
get() = BlockPos(x, y, z)
|
||||
|
||||
object FairySouls : NEUFeature,
|
||||
ProfileSpecificConfigHolder<FairySouls.Config>(serializer(), "fairy-souls.json", ::Config) {
|
||||
@Serializable
|
||||
data class Config(
|
||||
val foundSouls: MutableMap<String, MutableSet<Int>> = mutableMapOf()
|
||||
)
|
||||
|
||||
object FairySouls : NEUFeature {
|
||||
override val name: String get() = "Fairy Souls"
|
||||
override val identifier: String get() = "fairy-souls"
|
||||
|
||||
override fun onLoad() {
|
||||
val playerReach = 5
|
||||
val playerReachSquared = playerReach * playerReach
|
||||
|
||||
var currentLocationName: String? = null
|
||||
var currentLocationSouls: List<Coordinate> = emptyList()
|
||||
var currentMissingSouls: List<Coordinate> = emptyList()
|
||||
|
||||
fun updateMissingSouls() {
|
||||
currentMissingSouls = emptyList()
|
||||
val c = config ?: return
|
||||
val fi = c.foundSouls[currentLocationName] ?: setOf()
|
||||
val cms = currentLocationSouls.toMutableList()
|
||||
fi.asSequence().sortedDescending().filter { it in cms.indices }.forEach { cms.removeAt(it) }
|
||||
currentMissingSouls = cms
|
||||
}
|
||||
|
||||
fun updateWorldSouls() {
|
||||
currentLocationSouls = emptyList()
|
||||
val loc = currentLocationName ?: return
|
||||
currentLocationSouls = RepoManager.neuRepo.constants.fairySouls.soulLocations[loc] ?: return
|
||||
}
|
||||
|
||||
fun findNearestClickableSoul(): Coordinate? {
|
||||
val player = MC.player ?: return null
|
||||
val pos = player.pos
|
||||
val location = SBData.skyblockLocation ?: return null
|
||||
val soulLocations: List<Coordinate> =
|
||||
RepoManager.neuRepo.constants.fairySouls.soulLocations[location] ?: return null
|
||||
return soulLocations
|
||||
.map { it to it.blockPos.getSquaredDistance(pos) }
|
||||
.filter { it.second < playerReachSquared }
|
||||
.minByOrNull { it.second }
|
||||
?.first
|
||||
}
|
||||
|
||||
private fun markNearestSoul() {
|
||||
val nearestSoul = findNearestClickableSoul() ?: return
|
||||
val c = config ?: return
|
||||
val loc = currentLocationName ?: return
|
||||
val idx = currentLocationSouls.indexOf(nearestSoul)
|
||||
c.foundSouls.computeIfAbsent(loc) { mutableSetOf() }.add(idx)
|
||||
markDirty()
|
||||
updateMissingSouls()
|
||||
}
|
||||
|
||||
|
||||
override fun onLoad() {
|
||||
SkyblockServerUpdateEvent.subscribe {
|
||||
currentLocationName = it.newLocraw?.skyblockLocation
|
||||
updateWorldSouls()
|
||||
updateMissingSouls()
|
||||
}
|
||||
ServerChatLineReceivedEvent.subscribe {
|
||||
when (it.text.unformattedString) {
|
||||
"You have already found that Fairy Soul!" -> {
|
||||
markNearestSoul()
|
||||
}
|
||||
|
||||
"SOUL! You found a Fairy Soul!" -> {
|
||||
markNearestSoul()
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldRenderLastEvent.subscribe {
|
||||
renderBlocks(it.camera) {
|
||||
color(1F, 1F, 0F, 0.8F)
|
||||
currentMissingSouls.forEach {
|
||||
block(it.blockPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment
|
||||
import io.github.cottonmc.cotton.gui.widget.data.Insets
|
||||
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
import moe.nea.notenoughupdates.util.ConfigHolder
|
||||
import moe.nea.notenoughupdates.util.config.ConfigHolder
|
||||
import net.minecraft.text.Text
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package moe.nea.notenoughupdates.mixins
|
||||
|
||||
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 net.minecraft.client.network.message.MessageHandler
|
||||
import net.minecraft.network.message.MessageType
|
||||
import net.minecraft.network.message.SignedMessage
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.notenoughupdates.events.ServerChatLineReceivedEvent
|
||||
|
||||
@Mixin(MessageHandler::class)
|
||||
class MixinMessageHandler {
|
||||
@Inject(method = ["onChatMessage"], at = [At("HEAD")], cancellable = true)
|
||||
fun onOnChatMessage(message: SignedMessage, params: MessageType.Parameters, ci: CallbackInfo) {
|
||||
val decoratedText = params.applyChatDecoration(message.unsignedContent.orElse(message.content))
|
||||
val event = ServerChatLineReceivedEvent(decoratedText)
|
||||
if (ServerChatLineReceivedEvent.publish(event).cancelled) {
|
||||
ci.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = ["onGameMessage"], at = [At("HEAD")], cancellable = true)
|
||||
fun onOnGameMessage(message: Text, overlay: Boolean, ci: CallbackInfo) {
|
||||
if (!overlay) {
|
||||
val event = ServerChatLineReceivedEvent(message)
|
||||
if (ServerChatLineReceivedEvent.publish(event).cancelled) {
|
||||
ci.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package moe.nea.notenoughupdates.mixins
|
||||
|
||||
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 net.minecraft.client.render.Camera
|
||||
import net.minecraft.client.render.GameRenderer
|
||||
import net.minecraft.client.render.LightmapTextureManager
|
||||
import net.minecraft.client.render.WorldRenderer
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.math.Matrix4f
|
||||
import moe.nea.notenoughupdates.events.WorldRenderLastEvent
|
||||
|
||||
@Mixin(WorldRenderer::class)
|
||||
class MixinWorldRenderer {
|
||||
|
||||
@Inject(
|
||||
method = ["render"],
|
||||
at = [At("INVOKE", target = "renderChunkDebugInfo", shift = At.Shift.AFTER)],
|
||||
)
|
||||
fun onWorldRenderLast(
|
||||
matrices: MatrixStack,
|
||||
tickDelta: Float,
|
||||
arg2: Long,
|
||||
renderBlockOutline: Boolean,
|
||||
camera: Camera,
|
||||
gameRenderer: GameRenderer,
|
||||
lightmapTextureManager: LightmapTextureManager,
|
||||
positionMatrix: Matrix4f,
|
||||
ci: CallbackInfo
|
||||
) {
|
||||
val event = WorldRenderLastEvent(
|
||||
matrices, tickDelta, renderBlockOutline,
|
||||
camera, gameRenderer, lightmapTextureManager,
|
||||
positionMatrix
|
||||
)
|
||||
WorldRenderLastEvent.publish(event)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import kotlinx.serialization.serializer
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates.logger
|
||||
import moe.nea.notenoughupdates.hud.ProgressBar
|
||||
import moe.nea.notenoughupdates.util.ConfigHolder
|
||||
import moe.nea.notenoughupdates.util.config.ConfigHolder
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
package moe.nea.notenoughupdates.util
|
||||
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.readText
|
||||
import kotlin.io.path.writeText
|
||||
import kotlin.reflect.KClass
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.server.command.CommandOutput
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
import moe.nea.notenoughupdates.events.ScreenOpenEvent
|
||||
|
||||
abstract class ConfigHolder<T>(
|
||||
val serializer: KSerializer<T>,
|
||||
val name: String,
|
||||
val default: () -> T
|
||||
) {
|
||||
|
||||
var config: T
|
||||
private set
|
||||
|
||||
init {
|
||||
config = readValueOrDefault()
|
||||
putConfig(this::class, this)
|
||||
}
|
||||
|
||||
val file: Path get() = NotEnoughUpdates.CONFIG_DIR.resolve("$name.json")
|
||||
|
||||
protected fun readValueOrDefault(): T {
|
||||
if (file.exists())
|
||||
try {
|
||||
return NotEnoughUpdates.json.decodeFromString(
|
||||
serializer,
|
||||
file.readText()
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
badLoads.add(name)
|
||||
NotEnoughUpdates.logger.error(
|
||||
"IO exception during loading of config file $name. This will reset this config.",
|
||||
e
|
||||
)
|
||||
} catch (e: SerializationException) {
|
||||
badLoads.add(name)
|
||||
NotEnoughUpdates.logger.error(
|
||||
"Serialization exception during loading of config file $name. This will reset this config.",
|
||||
e
|
||||
)
|
||||
}
|
||||
return default()
|
||||
}
|
||||
|
||||
private fun writeValue(t: T) {
|
||||
file.writeText(NotEnoughUpdates.json.encodeToString(serializer, t))
|
||||
}
|
||||
|
||||
fun save() {
|
||||
writeValue(config)
|
||||
}
|
||||
|
||||
fun load() {
|
||||
config = readValueOrDefault()
|
||||
}
|
||||
|
||||
fun markDirty() {
|
||||
Companion.markDirty(this::class)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var badLoads: MutableList<String> = CopyOnWriteArrayList()
|
||||
private val allConfigs: MutableMap<KClass<out ConfigHolder<*>>, ConfigHolder<*>> = mutableMapOf()
|
||||
private val dirty: MutableSet<KClass<out ConfigHolder<*>>> = mutableSetOf()
|
||||
|
||||
private fun <T : ConfigHolder<K>, K> putConfig(kClass: KClass<T>, inst: ConfigHolder<K>) {
|
||||
allConfigs[kClass] = inst
|
||||
}
|
||||
|
||||
fun <T : ConfigHolder<K>, K> markDirty(kClass: KClass<T>) {
|
||||
if (kClass !in allConfigs) {
|
||||
NotEnoughUpdates.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'ConfigHolder'")
|
||||
return
|
||||
}
|
||||
dirty.add(kClass)
|
||||
}
|
||||
|
||||
private fun performSaves() {
|
||||
val toSave = dirty.toList().also {
|
||||
dirty.clear()
|
||||
}
|
||||
for (it in toSave) {
|
||||
val obj = allConfigs[it]
|
||||
if (obj == null) {
|
||||
NotEnoughUpdates.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'")
|
||||
continue
|
||||
}
|
||||
obj.save()
|
||||
}
|
||||
}
|
||||
|
||||
private fun warnForResetConfigs(player: CommandOutput) {
|
||||
if (badLoads.isNotEmpty()) {
|
||||
player.sendMessage(
|
||||
Text.literal(
|
||||
"The following configs have been reset: ${badLoads.joinToString(", ")}. " +
|
||||
"This can be intentional, but probably isn't."
|
||||
)
|
||||
)
|
||||
badLoads.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun registerEvents() {
|
||||
ScreenOpenEvent.subscribe { event ->
|
||||
performSaves()
|
||||
val p = MinecraftClient.getInstance().player
|
||||
if (p != null) {
|
||||
warnForResetConfigs(p)
|
||||
}
|
||||
}
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
|
||||
performSaves()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
8
src/main/kotlin/moe/nea/notenoughupdates/util/Locraw.kt
Normal file
8
src/main/kotlin/moe/nea/notenoughupdates/util/Locraw.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package moe.nea.notenoughupdates.util
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Locraw(val server: String, val gametype: String? = null, val mode: String? = null, val map: String? = null) {
|
||||
val skyblockLocation = if (gametype == "SKYBLOCK") mode else null
|
||||
}
|
||||
7
src/main/kotlin/moe/nea/notenoughupdates/util/MC.kt
Normal file
7
src/main/kotlin/moe/nea/notenoughupdates/util/MC.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package moe.nea.notenoughupdates.util
|
||||
|
||||
import net.minecraft.client.MinecraftClient
|
||||
|
||||
object MC {
|
||||
inline val player get() = MinecraftClient.getInstance().player
|
||||
}
|
||||
63
src/main/kotlin/moe/nea/notenoughupdates/util/SBData.kt
Normal file
63
src/main/kotlin/moe/nea/notenoughupdates/util/SBData.kt
Normal file
@@ -0,0 +1,63 @@
|
||||
package moe.nea.notenoughupdates.util
|
||||
|
||||
import dev.architectury.event.events.client.ClientPlayerEvent
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.TimeSource
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
import moe.nea.notenoughupdates.events.ServerChatLineReceivedEvent
|
||||
import moe.nea.notenoughupdates.events.SkyblockServerUpdateEvent
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
object SBData {
|
||||
val profileRegex = "(?:Your profile was changed to: |You are playing on profile: )(.+)".toRegex()
|
||||
var profileCuteName: String? = null
|
||||
|
||||
private var lastLocrawSent: TimeSource.Monotonic.ValueTimeMark? = null
|
||||
private val locrawRoundtripTime: Duration = 5.seconds
|
||||
var locraw: Locraw? = null
|
||||
val skyblockLocation get() = locraw?.skyblockLocation
|
||||
|
||||
|
||||
fun init() {
|
||||
ServerChatLineReceivedEvent.subscribe { event ->
|
||||
val profileMatch = profileRegex.matchEntire(event.unformattedString)
|
||||
if (profileMatch != null) {
|
||||
profileCuteName = profileMatch.groupValues[1]
|
||||
}
|
||||
if (event.unformattedString.startsWith("{")) {
|
||||
val lLS = lastLocrawSent
|
||||
if (tryReceiveLocraw(event.unformattedString) && lLS != null && lLS.elapsedNow() < locrawRoundtripTime) {
|
||||
lastLocrawSent = null
|
||||
event.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClientPlayerEvent.CLIENT_PLAYER_JOIN.register(ClientPlayerEvent.ClientPlayerJoin {
|
||||
locraw = null
|
||||
sendLocraw()
|
||||
})
|
||||
}
|
||||
|
||||
private fun tryReceiveLocraw(unformattedString: String): Boolean = try {
|
||||
val lastLocraw = locraw
|
||||
locraw = NotEnoughUpdates.json.decodeFromString<Locraw>(unformattedString)
|
||||
SkyblockServerUpdateEvent.publish(SkyblockServerUpdateEvent(lastLocraw, locraw))
|
||||
true
|
||||
} catch (e: SerializationException) {
|
||||
false
|
||||
} catch (e: IllegalArgumentException) {
|
||||
false
|
||||
}
|
||||
|
||||
fun sendLocraw() {
|
||||
lastLocrawSent = TimeSource.Monotonic.markNow()
|
||||
MC.player?.sendCommand("locraw")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package moe.nea.notenoughupdates.util.config
|
||||
|
||||
import java.nio.file.Path
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.readText
|
||||
import kotlin.io.path.writeText
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
|
||||
abstract class ConfigHolder<T>(
|
||||
val serializer: KSerializer<T>,
|
||||
val name: String,
|
||||
val default: () -> T
|
||||
) : IConfigHolder<T> {
|
||||
|
||||
|
||||
final override var config: T
|
||||
private set
|
||||
|
||||
init {
|
||||
config = readValueOrDefault()
|
||||
IConfigHolder.putConfig(this::class, this)
|
||||
}
|
||||
|
||||
private val file: Path get() = NotEnoughUpdates.CONFIG_DIR.resolve("$name.json")
|
||||
|
||||
protected fun readValueOrDefault(): T {
|
||||
if (file.exists())
|
||||
try {
|
||||
return NotEnoughUpdates.json.decodeFromString(
|
||||
serializer,
|
||||
file.readText()
|
||||
)
|
||||
} catch (e: Exception) {/* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/
|
||||
IConfigHolder.badLoads.add(name)
|
||||
NotEnoughUpdates.logger.error(
|
||||
"Exception during loading of config file $name. This will reset this config.",
|
||||
e
|
||||
)
|
||||
}
|
||||
return default()
|
||||
}
|
||||
|
||||
private fun writeValue(t: T) {
|
||||
file.writeText(NotEnoughUpdates.json.encodeToString(serializer, t))
|
||||
}
|
||||
|
||||
override fun save() {
|
||||
writeValue(config)
|
||||
}
|
||||
|
||||
override fun load() {
|
||||
config = readValueOrDefault()
|
||||
}
|
||||
|
||||
override fun markDirty() {
|
||||
IConfigHolder.markDirty(this::class)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package moe.nea.notenoughupdates.util.config
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents
|
||||
import kotlin.reflect.KClass
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.server.command.CommandOutput
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
import moe.nea.notenoughupdates.events.ScreenOpenEvent
|
||||
|
||||
interface IConfigHolder<T> {
|
||||
companion object {
|
||||
internal var badLoads: MutableList<String> = CopyOnWriteArrayList()
|
||||
private val allConfigs: MutableMap<KClass<out IConfigHolder<*>>, IConfigHolder<*>> = mutableMapOf()
|
||||
private val dirty: MutableSet<KClass<out IConfigHolder<*>>> = mutableSetOf()
|
||||
|
||||
internal fun <T : IConfigHolder<K>, K> putConfig(kClass: KClass<T>, inst: IConfigHolder<K>) {
|
||||
allConfigs[kClass] = inst
|
||||
}
|
||||
|
||||
fun <T : IConfigHolder<K>, K> markDirty(kClass: KClass<T>) {
|
||||
if (kClass !in allConfigs) {
|
||||
NotEnoughUpdates.logger.error("Tried to markDirty '${kClass.qualifiedName}', which isn't registered as 'IConfigHolder'")
|
||||
return
|
||||
}
|
||||
dirty.add(kClass)
|
||||
}
|
||||
|
||||
private fun performSaves() {
|
||||
val toSave = dirty.toList().also {
|
||||
dirty.clear()
|
||||
}
|
||||
for (it in toSave) {
|
||||
val obj = allConfigs[it]
|
||||
if (obj == null) {
|
||||
NotEnoughUpdates.logger.error("Tried to save '${it}', which isn't registered as 'ConfigHolder'")
|
||||
continue
|
||||
}
|
||||
obj.save()
|
||||
}
|
||||
}
|
||||
|
||||
private fun warnForResetConfigs(player: CommandOutput) {
|
||||
if (badLoads.isNotEmpty()) {
|
||||
player.sendMessage(
|
||||
Text.literal(
|
||||
"The following configs have been reset: ${badLoads.joinToString(", ")}. " +
|
||||
"This can be intentional, but probably isn't."
|
||||
)
|
||||
)
|
||||
badLoads.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun registerEvents() {
|
||||
ScreenOpenEvent.subscribe { event ->
|
||||
performSaves()
|
||||
val p = MinecraftClient.getInstance().player
|
||||
if (p != null) {
|
||||
warnForResetConfigs(p)
|
||||
}
|
||||
}
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register(ClientLifecycleEvents.ClientStopping {
|
||||
performSaves()
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val config: T
|
||||
fun save()
|
||||
fun markDirty()
|
||||
fun load()
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package moe.nea.notenoughupdates.util.config
|
||||
|
||||
import java.nio.file.Path
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.deleteExisting
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.extension
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.nameWithoutExtension
|
||||
import kotlin.io.path.readText
|
||||
import kotlin.io.path.writeText
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
import moe.nea.notenoughupdates.util.SBData
|
||||
|
||||
abstract class ProfileSpecificConfigHolder<S>(
|
||||
private val configSerializer: KSerializer<S>,
|
||||
val configName: String,
|
||||
private val configDefault: () -> S
|
||||
) : IConfigHolder<S?> {
|
||||
|
||||
var allConfigs: MutableMap<String, S>
|
||||
|
||||
override val config: S?
|
||||
get() = SBData.profileCuteName?.let {
|
||||
allConfigs.computeIfAbsent(it) { configDefault() }
|
||||
}
|
||||
|
||||
init {
|
||||
allConfigs = readValues()
|
||||
readValues()
|
||||
}
|
||||
|
||||
private val configDirectory: Path get() = NotEnoughUpdates.CONFIG_DIR.resolve("profiles")
|
||||
|
||||
private fun readValues(): MutableMap<String, S> {
|
||||
if (!configDirectory.exists()) {
|
||||
configDirectory.createDirectories()
|
||||
}
|
||||
val profileFiles = configDirectory.listDirectoryEntries()
|
||||
return profileFiles
|
||||
.filter { it.extension == "json" }
|
||||
.mapNotNull {
|
||||
try {
|
||||
it.nameWithoutExtension to NotEnoughUpdates.json.decodeFromString(configSerializer, it.readText())
|
||||
} catch (e: Exception) { /* Expecting IOException and SerializationException, but Kotlin doesn't allow multi catches*/
|
||||
IConfigHolder.badLoads.add(configName)
|
||||
NotEnoughUpdates.logger.error(
|
||||
"Exception during loading of profile specific config file $it ($configName). This will reset that profiles config.",
|
||||
e
|
||||
)
|
||||
null
|
||||
}
|
||||
}.toMap().toMutableMap()
|
||||
}
|
||||
|
||||
override fun save() {
|
||||
if (!configDirectory.exists()) {
|
||||
configDirectory.createDirectories()
|
||||
}
|
||||
val c = allConfigs
|
||||
configDirectory.listDirectoryEntries().forEach {
|
||||
if (it.nameWithoutExtension !in c) {
|
||||
it.deleteExisting()
|
||||
}
|
||||
}
|
||||
c.forEach { (name, value) ->
|
||||
val f = configDirectory.resolve("$name.json")
|
||||
f.writeText(NotEnoughUpdates.json.encodeToString(configSerializer, value))
|
||||
}
|
||||
}
|
||||
|
||||
override fun markDirty() {
|
||||
IConfigHolder.markDirty(this::class)
|
||||
}
|
||||
|
||||
override fun load() {
|
||||
allConfigs = readValues()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package moe.nea.notenoughupdates.util.render
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import net.minecraft.client.gl.VertexBuffer
|
||||
import net.minecraft.client.render.BufferBuilder
|
||||
import net.minecraft.client.render.Camera
|
||||
import net.minecraft.client.render.GameRenderer
|
||||
import net.minecraft.client.render.Tessellator
|
||||
import net.minecraft.client.render.VertexFormat
|
||||
import net.minecraft.client.render.VertexFormats
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
class RenderBlockContext(val tesselator: Tessellator, val camPos: Vec3d) {
|
||||
val buffer = tesselator.buffer
|
||||
fun color(red: Float, green: Float, blue: Float, alpha: Float) {
|
||||
RenderSystem.setShaderColor(red, green, blue, alpha)
|
||||
}
|
||||
|
||||
fun block(blockPos: BlockPos) {
|
||||
val matrixStack = RenderSystem.getModelViewStack()
|
||||
matrixStack.push()
|
||||
matrixStack.translate(blockPos.x - camPos.x, blockPos.y - camPos.y, blockPos.z - camPos.z)
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader)
|
||||
buildCube(buffer)
|
||||
tesselator.draw()
|
||||
matrixStack.pop()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun buildCube(buf: BufferBuilder) {
|
||||
buf.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR)
|
||||
buf.fixedColor(255, 255, 255, 255)
|
||||
buf.vertex(0.0, 0.0, 0.0).next()
|
||||
buf.vertex(0.0, 0.0, 1.0).next()
|
||||
buf.vertex(0.0, 1.0, 1.0).next()
|
||||
buf.vertex(1.0, 1.0, 0.0).next()
|
||||
buf.vertex(0.0, 0.0, 0.0).next()
|
||||
buf.vertex(0.0, 1.0, 0.0).next()
|
||||
buf.vertex(1.0, 0.0, 1.0).next()
|
||||
buf.vertex(0.0, 0.0, 0.0).next()
|
||||
buf.vertex(1.0, 0.0, 0.0).next()
|
||||
buf.vertex(1.0, 1.0, 0.0).next()
|
||||
buf.vertex(1.0, 0.0, 0.0).next()
|
||||
buf.vertex(0.0, 0.0, 0.0).next()
|
||||
buf.vertex(0.0, 0.0, 0.0).next()
|
||||
buf.vertex(0.0, 1.0, 1.0).next()
|
||||
buf.vertex(0.0, 1.0, 0.0).next()
|
||||
buf.vertex(1.0, 0.0, 1.0).next()
|
||||
buf.vertex(0.0, 0.0, 1.0).next()
|
||||
buf.vertex(0.0, 0.0, 0.0).next()
|
||||
buf.vertex(0.0, 1.0, 1.0).next()
|
||||
buf.vertex(0.0, 0.0, 1.0).next()
|
||||
buf.vertex(1.0, 0.0, 1.0).next()
|
||||
buf.vertex(1.0, 1.0, 1.0).next()
|
||||
buf.vertex(1.0, 0.0, 0.0).next()
|
||||
buf.vertex(1.0, 1.0, 0.0).next()
|
||||
buf.vertex(1.0, 0.0, 0.0).next()
|
||||
buf.vertex(1.0, 1.0, 1.0).next()
|
||||
buf.vertex(1.0, 0.0, 1.0).next()
|
||||
buf.vertex(1.0, 1.0, 1.0).next()
|
||||
buf.vertex(1.0, 1.0, 0.0).next()
|
||||
buf.vertex(0.0, 1.0, 0.0).next()
|
||||
buf.vertex(1.0, 1.0, 1.0).next()
|
||||
buf.vertex(0.0, 1.0, 0.0).next()
|
||||
buf.vertex(0.0, 1.0, 1.0).next()
|
||||
buf.vertex(1.0, 1.0, 1.0).next()
|
||||
buf.vertex(0.0, 1.0, 1.0).next()
|
||||
buf.vertex(1.0, 0.0, 1.0).next()
|
||||
buf.unfixColor()
|
||||
}
|
||||
|
||||
fun renderBlocks(camera: Camera, block: RenderBlockContext. () -> Unit) {
|
||||
RenderSystem.disableDepthTest()
|
||||
RenderSystem.disableTexture()
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
|
||||
val ctx = RenderBlockContext(Tessellator.getInstance(), camera.pos)
|
||||
block(ctx)
|
||||
|
||||
VertexBuffer.unbind()
|
||||
RenderSystem.enableDepthTest()
|
||||
RenderSystem.enableTexture()
|
||||
RenderSystem.disableBlend()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
70
src/main/kotlin/moe/nea/notenoughupdates/util/textutil.kt
Normal file
70
src/main/kotlin/moe/nea/notenoughupdates/util/textutil.kt
Normal file
@@ -0,0 +1,70 @@
|
||||
package moe.nea.notenoughupdates.util
|
||||
|
||||
import net.minecraft.text.LiteralTextContent
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.text.TextContent
|
||||
import moe.nea.notenoughupdates.NotEnoughUpdates
|
||||
|
||||
|
||||
class TextMatcher(text: Text) {
|
||||
data class State(
|
||||
var iterator: MutableList<Text>,
|
||||
var currentText: Text?,
|
||||
var offset: Int,
|
||||
var textContent: String,
|
||||
)
|
||||
|
||||
var state = State(
|
||||
mutableListOf(text),
|
||||
null,
|
||||
0,
|
||||
""
|
||||
)
|
||||
|
||||
fun pollChunk(): Boolean {
|
||||
val firstOrNull = state.iterator.removeFirstOrNull() ?: return false
|
||||
state.offset = 0
|
||||
state.currentText = firstOrNull
|
||||
state.textContent = when (val content = firstOrNull.content) {
|
||||
is LiteralTextContent -> content.string
|
||||
TextContent.EMPTY -> ""
|
||||
else -> {
|
||||
NotEnoughUpdates.logger.warn("TextContent of type ${content.javaClass} not understood.")
|
||||
return false
|
||||
}
|
||||
}
|
||||
state.iterator.addAll(0, firstOrNull.siblings)
|
||||
return true
|
||||
}
|
||||
|
||||
fun pollChunks(): Boolean {
|
||||
while (state.offset !in state.textContent.indices) {
|
||||
if (!pollChunk()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun pollChar(): Char? {
|
||||
if (!pollChunks()) return null
|
||||
return state.textContent[state.offset++]
|
||||
}
|
||||
|
||||
|
||||
fun expectString(string: String): Boolean {
|
||||
var found = ""
|
||||
while (found.length < string.length) {
|
||||
if (!pollChunks()) return false
|
||||
val takeable = state.textContent.drop(state.offset).take(string.length - found.length)
|
||||
state.offset += takeable.length
|
||||
found += takeable
|
||||
}
|
||||
return found == string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val Text.unformattedString
|
||||
get() = string.replace("§.".toRegex(), "")
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
{
|
||||
"notenoughupdates": {
|
||||
"repo": {
|
||||
"reload": {
|
||||
"network": "Trying to redownload the repository",
|
||||
"disk": "Reloading repository from disk. This may lag a bit."
|
||||
},
|
||||
"cache": "Recaching items",
|
||||
"brokenitem": "Failed to render item: %s"
|
||||
},
|
||||
"gui": {
|
||||
"repo": {
|
||||
"title": "NotEnoughUpdates Repo Settings",
|
||||
"autoupdate": "Auto Update",
|
||||
"username": "Repo Username",
|
||||
"hint.username": "NotEnoughUpdates",
|
||||
"reponame": "Repo Name",
|
||||
"hint.reponame": "NotEnoughUpdates-REPO",
|
||||
"branch": "Repo Branch",
|
||||
"hint.branch": "dangerous",
|
||||
"reset": "Reset",
|
||||
"reset.label": "Reset to Defaults"
|
||||
}
|
||||
}
|
||||
}
|
||||
"notenoughupdates.repo.reload.network": "Trying to redownload the repository",
|
||||
"notenoughupdates.repo.reload.disk": "Reloading repository from disk. This may lag a bit.",
|
||||
"notenoughupdates.repo.cache": "Recaching items",
|
||||
"notenoughupdates.repo.brokenitem": "Failed to render item: %s",
|
||||
"notenoughupdates.gui.repo.title": "NotEnoughUpdates Repo Settings",
|
||||
"notenoughupdates.gui.repo.autoupdate": "Auto Update",
|
||||
"notenoughupdates.gui.repo.username": "Repo Username",
|
||||
"notenoughupdates.gui.repo.hint.username": "NotEnoughUpdates",
|
||||
"notenoughupdates.gui.repo.reponame": "Repo Name",
|
||||
"notenoughupdates.gui.repo.hint.reponame": "NotEnoughUpdates-REPO",
|
||||
"notenoughupdates.gui.repo.branch": "Repo Branch",
|
||||
"notenoughupdates.gui.repo.hint.branch": "dangerous",
|
||||
"notenoughupdates.gui.repo.reset": "Reset",
|
||||
"notenoughupdates.gui.repo.reset.label": "Reset to Defaults",
|
||||
"notenoughupdates.sbinfo.nolocraw": "No locraw data available",
|
||||
"notenoughupdates.sbinfo.profile": "Current profile cutename: %s",
|
||||
"notenoughupdates.sbinfo.server": "Locraw Server: %s",
|
||||
"notenoughupdates.sbinfo.gametype": "Locraw Gametype: %s",
|
||||
"notenoughupdates.sbinfo.mode": "Locraw Mode: %s",
|
||||
"notenoughupdates.sbinfo.map": "Locraw Map: %s"
|
||||
}
|
||||
|
||||
2
src/main/resources/hotswap-agent.properties
Normal file
2
src/main/resources/hotswap-agent.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
disabledPlugins=Log4j2,Proxy
|
||||
LOGGER=info
|
||||
@@ -3,7 +3,9 @@
|
||||
"package": "moe.nea.notenoughupdates.mixins",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"client": [
|
||||
"MixinMinecraft"
|
||||
"MixinMessageHandler",
|
||||
"MixinMinecraft",
|
||||
"MixinWorldRenderer"
|
||||
],
|
||||
"mixins": [
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user