Compare commits

..

No commits in common. "master" and "v1.4.0" have entirely different histories.

49 changed files with 646 additions and 2827 deletions

1
.gitignore vendored
View File

@ -4,4 +4,3 @@ run/
build/
.gradle/
build.number

View File

@ -1,10 +0,0 @@
## [1.4.0] - 2024-07-23
### Chore
- Remove comments
### Feat
- *(chestesp)* Add initial implementation, halfway done

View File

@ -1,23 +1,3 @@
# SkyBlockTweaks
My QOL mod for Hypixel Skyblock
## Includes:
- Grotto Finder
- Gemstone Finder
- Powder ChestESP
- Route Builder
## Config
You can configure the gemstone search radius, and also toggle the powder chest esp
## Commands:
- /sbt gemstonesearchradius <number>
- /sbt powderchest [disable/enable]
## TODO (Asin these WILL be implemented):
- Add route builder history GUI/Command or something
- Make Route Builder export to Skytils/CrystalHollowWaypoints/Coleweight
- Optimize Block Outline Rendering
- Glacite Mineshaft GemstoneESP
- PlayerESP (Grotto - Glacite Mineshaft)
My QOL mod for Hypixel Skyblock

View File

@ -1,5 +1,4 @@
import org.apache.commons.lang3.SystemUtils
import java.util.Properties
plugins {
idea
@ -10,28 +9,25 @@ plugins {
kotlin("jvm") version "2.0.0"
}
//Constants:
val baseGroup: String by project
val mcVersion: String by project
val versionBase: String by project
val version: String by project
val mixinGroup = "$baseGroup.mixin"
val modid: String by project
val buildNumberFile = file("build.number")
val buildNumber: String = if (buildNumberFile.exists()) {
buildNumberFile.readText().trim()
} else {
"1"
}
group = baseGroup
version = "alpha_$versionBase-b$buildNumber"
// Toolchains:
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
}
// Minecraft configuration:
loom {
log4jConfigs.from(file("log4j2.xml"))
launchConfigs {
"client" {
// If you don't want mixins, remove these lines
property("mixin.debug", "true")
arg("--tweakClass", "org.spongepowered.asm.launch.MixinTweaker")
}
@ -39,6 +35,7 @@ loom {
runConfigs {
"client" {
if (SystemUtils.IS_OS_MAC_OSX) {
// This argument causes a crash on macOS
vmArgs.remove("-XstartOnFirstThread")
}
}
@ -46,8 +43,10 @@ loom {
}
forge {
pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter())
// If you don't want mixins, remove this lines
mixinConfig("mixins.$modid.json")
}
// If you don't want mixins, remove these lines
mixin {
defaultRefmapName.set("mixins.$modid.refmap.json")
}
@ -63,9 +62,12 @@ sourceSets.main {
kotlin.destinationDirectory.set(java.destinationDirectory)
}
// Dependencies:
repositories {
mavenCentral()
maven("https://repo.spongepowered.org/maven/")
// If you don't want to log in with your real minecraft account, remove this line
maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1")
}
@ -80,23 +82,30 @@ dependencies {
shadowImpl(kotlin("stdlib-jdk8"))
// If you don't want mixins, remove these lines
shadowImpl("org.spongepowered:mixin:0.7.11-SNAPSHOT") {
isTransitive = false
}
annotationProcessor("org.spongepowered:mixin:0.8.5-SNAPSHOT")
// If you don't want to log in with your real minecraft account, remove this line
runtimeOnly("me.djtheredstoner:DevAuth-forge-legacy:1.2.1")
}
// Tasks:
tasks.withType(JavaCompile::class) {
options.encoding = "UTF-8"
}
tasks.withType(org.gradle.jvm.tasks.Jar::class) {
archiveBaseName.set(modid)
archiveVersion.set("$version")
manifest.attributes.run {
this["FMLCorePluginContainsFMLMod"] = "true"
this["ForceLoadAsMod"] = "true"
// If you don't want mixins, remove these lines
this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker"
this["MixinConfigs"] = "mixins.$modid.json"
}
@ -115,6 +124,7 @@ tasks.processResources {
rename("(.+_at.cfg)", "META-INF/$1")
}
val remapJar by tasks.named<net.fabricmc.loom.task.RemapJarTask>("remapJar") {
archiveClassifier.set("")
from(tasks.shadowJar)
@ -135,19 +145,10 @@ tasks.shadowJar {
println("Copying dependencies into mod: ${it.files}")
}
}
// If you want to include other dependencies and shadow them, you can relocate them in here
fun relocate(name: String) = relocate(name, "$baseGroup.deps.$name")
}
tasks.register("incrementBuildNumber") {
doLast {
val current = buildNumber.toIntOrNull() ?: 1
val next = current + 1
buildNumberFile.writeText(next.toString())
println("🔢 Build number incremented to $next")
}
}
tasks.assemble.get().dependsOn(tasks.remapJar)
tasks.assemble {
dependsOn("remapJar")
dependsOn("incrementBuildNumber")
}

View File

@ -1,36 +0,0 @@
# cliff.toml
[changelog]
title = "Changelog"
description = "All notable changes to this project will be documented in this file."
repository_url = "http://localhost:3001/illyum/sbt-stash"
template = """
# {{version}} - {{date}}
{% for group, commits in commits | group_by(attribute="group") %}
### {{group | upper_first}}
{% for commit in commits %}
- {{ commit.message | upper_first }} ({% if commit.breaking %}! {% endif %}{{ commit.hash }})
{% endfor %}
{% endfor %}
"""
[git]
commit_parsers = [
{ message = "^\\(Chore\\)", group = "Chore" },
{ message = "^\\(BugFix\\)", group = "Bug Fixes" },
{ message = "^\\(Feat\\)", group = "Features" },
{ message = "^\\(Docs\\)", group = "Documentation" },
{ message = "^\\(Refactor\\)", group = "Refactor" },
{ message = "^\\(Test\\)", group = "Tests" },
{ message = "^\\(Style\\)", group = "Styling" },
{ message = "^\\(Perf\\)", group = "Performance" },
]
[git.tag]
pattern = "^v[0-9]+"
[git.commit]
conventional = false
[git.filters]
exclude_merge_commits = true

View File

@ -1,131 +0,0 @@
# Client Command Framework
I'm using a lightweight Kotlin DSL, annotation-based command system for making client side commands.
## Defining Commands
All commands are defined as Kotlin functions annotated with `@SubCommand` in `ClientCommands.kt`.
### Example:
```kotlin
@SubCommand(
name = "test",
description = "Runs a test command"
)
fun test(ctx: CommandContext) {
ctx.send("Test command executed!")
}
```
### Subcommand Options:
- `name`: command name (required)
- `usage`: shows usage in help menu
- `description`: description shown in help
- `aliases`: optional aliases
### CommandContext helpers:
- `ctx.arg(index: Int)`: get argument (nullable)
- `ctx.require(index: Int, errorMsg: String)`: get required argument (throws error if missing)
- `ctx.send(msg: String)`: send message to client player
## Help System
- `/sbt` shows all available subcommands
- `/sbt help <command>` shows usage & description for a subcommand
## Tab Completion
- Tab completion works for first argument (subcommands)
### Example:
```kotlin
@SubCommand(
name = "test",
description = "Runs a test command"
)
fun test(ctx: CommandContext) {
ctx.send("Test command executed!")
}
```
### Subcommand Options:
- `name`: command name (required)
- `usage`: shows usage in help menu
- `description`: description shown in help
- `aliases`: optional aliases
### CommandContext helpers:
- `ctx.arg(index: Int)`: get argument (nullable)
- `ctx.require(index: Int, errorMsg: String)`: get required argument (throws error if missing)
- `ctx.send(msg: String)`: send message to client player
## Help System
- `/sbt` shows all available subcommands
- `/sbt help <command>` shows usage & description for a subcommand
## Tab Completion
- Tab completion works for first argument (subcommands)
## Example Commands
```kotlin
@SubCommand(
name = "autogrotto",
usage = "<status|enable|disable>",
description = "Manages the AutoGrotto feature"
)
fun autogrotto(ctx: CommandContext) {
when (ctx.require(0, "Provide status, enable, or disable")) {
"status" -> ctx.send("Autogrotto is enabled")
"enable" -> ctx.send("Autogrotto enabled")
"disable" -> ctx.send("Autogrotto disabled")
else -> ctx.send("Invalid usage. Try /sbt help autogrotto")
}
}
```
## How to Add a New Command
1. Go to `ClientCommands.kt`
2. Define a function
3. Annotate with `@SubCommand`
4. Use `ctx` to get args and send messages
That's it!
## Using CommandContext Helpers
```kotlin
val playerName = ctx.player?.name // Nullable: client-side player
val firstArg = ctx.arg(0) // Safe nullable accessor
val secondArgRequired = ctx.require(1, "Missing second argument") // Throws if missing
ctx.send("You said: $firstArg and $secondArgRequired") // Send chat to player
```
## Calling Functions From Another Class
Create a utility or manager class like:
```kotlin
object MyFeatureManager {
fun toggleFeature(enabled: Boolean) {
// logic here
}
}
```
Then call it from a command:
```kotlin
@SubCommand(name = "feature", usage = "<on|off>", description = "Toggles a feature")
fun feature(ctx: CommandContext) {
val toggle = ctx.require(0, "Provide a toggle option")
when (toggle.lowercase()) {
"on", "enable" -> // same action
"off", "disable" -> // another action
else -> {
ctx.send("Invalid argument '$toggle'. Usage:")
ctx.send("/sbt autogrotto <enable|disable|status>")
}
}
}
```

View File

@ -1,33 +0,0 @@
# Contributing to This Project
Thank you for your interest in contributing to this project! Please read the following guidelines to understand how you can contribute.
## Private Repository
This is a **private repository**. While you're welcome to file issues and suggest ideas, please note that this project is primarily a personal endeavor. Contributions from the community are appreciated, but they might not always be incorporated.
## Filing Issues
If you encounter any issues or have suggestions for improvements, feel free to [open an issue](https://github.com/your-repo/issues) (or email me). Please be as detailed as possible when describing the problem or idea. I appreciate your input!
## Contributing Fixes
If you have a fix that you'd like to contribute:
- Please do **not** submit a pull request directly.
- Instead, email the developer at [developer@itzilly.com](mailto:developer@itzilly.com) with details about your fix.
- If the fix aligns with the project's goals and standards, you'll receive guidance on how to proceed.
## Suggesting Ideas
I welcome ideas and suggestions! However, please keep in mind:
- This project is more of a personal project, so while all ideas are welcome, not every suggestion will be implemented.
- Feel free to suggest ideas by [opening an issue](https://github.com/404) and detailing your thoughts.
## Code of Conduct
Please remember to be respectful and constructive when engaging with this project. At the end of the day, this is just my project.
Thank you for your understanding and for contributing to this project!
# Note for persons with a Gitea account
If you have access to an account with elevated permissions on this repo, you're welcome to commit code/make pull requests.

View File

@ -1,55 +0,0 @@
# Developer Notice
Welcome to my project! This is primarily a personal project, and while I'm happy to have others take an interest, it's important to follow the guidelines below to ensure consistency and maintainability. (This is mostly for my reference)
## Conventional Commits
I use [Conventional Commits](https://www.conventionalcommits.org/) for all commit messages. This means that every commit should follow this format:
```
<type>(<scope>): <description>
```
- **Type:** The type of change you're committing. Common types include `feat` (new feature), `fix` (bug fix), `docs` (documentation only changes), `style` (code style, formatting, etc.), `refactor` (refactoring code), `test` (adding or updating tests), and `chore` (other changes that don't modify src or test files).
- **Scope:** An optional field that describes the part of the codebase the change affects (e.g., `api`, `config`, `ui`).
- **Description:** A brief description of the change.
Example commit message:
```
feat(api): add new endpoint for user data
```
```
chore(release): bump version to 1.4.3
```
```
style(ui): clean up redundant CSS classes in header component
```
```
fix(auth): resolve login redirect loop issue
```
```
merge(pr-45): integrate feature-x from pull request #45
```
## Branching Strategy
Branches are primarily for adding new features. However, while the project is in pre-release, it's okay to work on minor features directly on the `main` branch. Just make sure you:
- Commit all changes for the feature at once.
- Avoid having partial changes spread across multiple commits. Each commit should represent a complete and functional piece of work.
## Versioning
The versioning scheme I use is simple:
- **Patch version:** Bumped when small, incremental changes or bug fixes are made. For example, `x.x.y` to `x.x.y + 1`.
- **Minor version:** Typically, if a feature is added or updated, the version may stay the same until the project exits pre-release. Version `2.x.x` will be used if the project ever gets out of pre-release.
- **Major version:** Reserved for significant changes, like command updates, configuration overhauls, or substantial new features.
Remember, this is my project, so while I'm open to contributions and suggestions, I maintain the final say on what gets merged or included. Thanks for your understanding and contributions!

View File

@ -3,4 +3,4 @@ org.gradle.jvmargs=-Xmx2g
baseGroup = com.github.itzilly.sbt
mcVersion = 1.8.9
modid = sbt
versionBase = alpha-2.0.0
version = 1.0.0

116
options.txt Normal file
View File

@ -0,0 +1,116 @@
invertYMouse:false
mouseSensitivity:0.30985916
fov:0.25
gamma:0.91549295
saturation:0.0
renderDistance:20
guiScale:2
particles:0
bobView:false
anaglyph3d:false
maxFps:260
fboEnable:true
difficulty:3
fancyGraphics:true
ao:2
renderClouds:false
resourcePacks:["! §b Yeah.zip","dillyumfs_8bridge_doverlay_8vd1.zip","No Explosion Particles.zip"]
incompatibleResourcePacks:[]
lastServer:0
lang:en_US
chatVisibility:0
chatColors:true
chatLinks:true
chatLinksPrompt:true
chatOpacity:1.0
snooperEnabled:true
fullscreen:true
enableVsync:false
useVbo:true
hideServerAddress:false
advancedItemTooltips:true
pauseOnLostFocus:true
touchscreen:false
overrideWidth:0
overrideHeight:0
heldItemTooltips:true
chatHeightFocused:1.0
chatHeightUnfocused:0.44366196
chatScale:1.0
chatWidth:1.0
showInventoryAchievementHint:false
mipmapLevels:0
streamBytesPerPixel:0.5
streamMicVolume:1.0
streamSystemVolume:1.0
streamKbps:0.5412844
streamFps:0.31690142
streamCompression:1
streamSendMetadata:true
streamPreferredServer:
streamChatEnabled:0
streamChatUserFilter:0
streamMicToggleBehavior:0
forceUnicodeFont:false
allowBlockAlternatives:true
reducedDebugInfo:false
useNativeTransport:true
entityShadows:false
realmsNotifications:true
key_key.attack:-100
key_key.use:-99
key_key.forward:17
key_key.left:30
key_key.back:31
key_key.right:32
key_key.jump:57
key_key.sneak:42
key_key.sprint:184
key_key.drop:16
key_key.inventory:18
key_key.chat:46
key_key.playerlist:15
key_key.pickItem:-98
key_key.command:53
key_key.screenshot:60
key_key.togglePerspective:34
key_key.smoothCamera:48
key_key.streamStartStop:64
key_key.streamPauseUnpause:65
key_key.streamCommercial:0
key_key.streamToggleMic:0
key_key.fullscreen:87
key_key.spectatorOutlines:0
key_key.hotbar.1:2
key_key.hotbar.2:20
key_key.hotbar.3:47
key_key.hotbar.4:5
key_key.hotbar.5:6
key_key.hotbar.6:44
key_key.hotbar.7:-96
key_key.hotbar.8:-97
key_key.hotbar.9:4
key_of.key.zoom:41
key_Create Waypoint:49
key_Toggle Display of Waypoints:0
key_Freelook:33
key_Snaplook:56
key_Mod Menu:54
key_Waypoint Menu:0
key_Emote Wheel:52
soundCategory_master:0.51324505
soundCategory_music:0.0
soundCategory_record:1.0
soundCategory_weather:1.0
soundCategory_block:1.0
soundCategory_hostile:1.0
soundCategory_neutral:1.0
soundCategory_player:1.0
soundCategory_ambient:1.0
modelPart_cape:true
modelPart_jacket:true
modelPart_left_sleeve:true
modelPart_right_sleeve:true
modelPart_left_pants_leg:true
modelPart_right_pants_leg:true
modelPart_hat:true

View File

@ -7,7 +7,7 @@ pluginManagement {
maven("https://maven.fabricmc.net")
maven("https://maven.minecraftforge.net/")
maven("https://repo.spongepowered.org/maven/")
maven("https://repo.essential.gg/repository/maven-releases/")
maven("https://repo.sk1er.club/repository/maven-releases/")
}
resolutionStrategy {
eachPlugin {

View File

@ -0,0 +1,24 @@
package com.github.itzilly.sbt
import net.minecraft.client.renderer.GlStateManager
import java.util.*
class HudText(var textLines: Array<String>, var x: Int, var y: Int, var shadow: Boolean) : RenderHudAble {
var scale = 1f
val id = UUID.randomUUID()
override fun render(partialTicks: Float) {
GlStateManager.pushMatrix()
GlStateManager.translate(x.toFloat(), y.toFloat(), 0f)
GlStateManager.scale(scale, scale, scale)
var yOff = 0
for (line in textLines) {
if (shadow) {
SkyBlockTweaks.INSTANCE.fontRenderer.drawStringWithShadow(line, 0f, yOff.toFloat(), 0)
} else {
SkyBlockTweaks.INSTANCE.fontRenderer.drawString(line, 0, yOff, 0)
}
yOff += 10
}
GlStateManager.popMatrix()
}
}

View File

@ -0,0 +1,112 @@
package com.github.itzilly.sbt
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.util.AxisAlignedBB
import java.awt.Color
class RenderUtils {
var TESSELLATOR: Tessellator = Tessellator.getInstance()
var WORLD_RENDERER: WorldRenderer = Tessellator.getInstance().worldRenderer
fun drawBlock(box: AxisAlignedBB, outlineStartColor: Int, outlineEndColor: Int) {
drawBlockTop(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockBottom(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockNorth(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockEast(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockSouth(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockWest(box, Color(outlineStartColor), Color(outlineEndColor));
}
private fun drawBlockTop(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockBottom(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockNorth(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockEast(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockSouth(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockWest(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
}

View File

@ -1,16 +0,0 @@
package com.github.itzilly.sbt
import com.github.itzilly.sbt.SkyBlockTweaks.Companion.config
object SBTConfig {
fun loadConfig() {
config.load()
syncConfig()
}
private fun syncConfig() {
if (config.hasChanged()) {
config.save()
}
}
}

View File

@ -1,29 +0,0 @@
package com.github.itzilly.sbt
import net.minecraft.client.settings.KeyBinding
import net.minecraftforge.fml.client.registry.ClientRegistry
import org.lwjgl.input.Keyboard
object Keybinds {
// Grotto Finder
var searchGrotto: KeyBinding = KeyBinding("key.searchGrotto", Keyboard.KEY_Y, "key.categories.sbt")
var clearGrotto: KeyBinding = KeyBinding("key.clearGrotto", Keyboard.KEY_X, "key.categories.sbt")
// Route Builder
var addRouteNode: KeyBinding = KeyBinding("key.addRouteNode", Keyboard.KEY_ADD, "key.categories.sbt")
var removeLastNode: KeyBinding = KeyBinding("key.removeLastNode", Keyboard.KEY_MINUS, "key.categories.sbt")
var finishRoute: KeyBinding = KeyBinding("key.finishRoute", Keyboard.KEY_F4, "key.categories.sbt")
var openGui: KeyBinding = KeyBinding("key.openGui", Keyboard.KEY_LEFT, "key.categories.sbt")
fun register() {
ClientRegistry.registerKeyBinding(searchGrotto)
ClientRegistry.registerKeyBinding(clearGrotto)
ClientRegistry.registerKeyBinding(addRouteNode)
ClientRegistry.registerKeyBinding(removeLastNode)
ClientRegistry.registerKeyBinding(finishRoute)
ClientRegistry.registerKeyBinding(openGui)
}
}

View File

@ -1,22 +1,36 @@
package com.github.itzilly.sbt
import com.github.itzilly.sbt.SBTConfig.loadConfig
import com.github.itzilly.sbt.command.ClientCommands
import com.github.itzilly.sbt.command.ModCommandRegistry
import com.github.itzilly.sbt.command.registerBaseCommand
import com.github.itzilly.sbt.events.ForgeEventListener
import com.github.itzilly.sbt.events.ModEventBus
import com.github.itzilly.sbt.features.GrottoFinder
import com.github.itzilly.sbt.features.MineshaftHelper
import com.github.itzilly.sbt.features.RouteBuilder
import com.github.itzilly.sbt.util.GuiOpener
import com.google.gson.Gson
import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.*
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.client.renderer.entity.RenderManager
import net.minecraft.client.settings.KeyBinding
import net.minecraft.command.CommandException
import net.minecraft.command.ICommandSender
import net.minecraft.entity.Entity
import net.minecraft.init.Blocks
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.BlockPos
import net.minecraft.util.ChatComponentText
import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.client.event.RenderWorldLastEvent
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.fml.client.registry.ClientRegistry
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.FMLInitializationEvent
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.common.config.Configuration
import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent
import java.io.File
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.InputEvent
import org.lwjgl.input.Keyboard
import org.lwjgl.opengl.GL11
import java.awt.Color
import java.awt.Toolkit
import java.awt.datatransfer.Clipboard
import java.awt.datatransfer.StringSelection
@Mod(modid = "sbt", useMetadata = true)
class SkyBlockTweaks {
@ -26,41 +40,325 @@ class SkyBlockTweaks {
companion object {
lateinit var INSTANCE: SkyBlockTweaks
lateinit var config: Configuration
var routeList: ArrayList<RouteMarker> = ArrayList()
}
@Mod.EventHandler
fun preInit(event: FMLPreInitializationEvent) {
val directory = event.modConfigurationDirectory
config = Configuration(File(directory.path, "SkyBlockTweaks.cfg"))
loadConfig()
}
lateinit var tessellator: Tessellator
lateinit var worldRenderer: WorldRenderer
lateinit var renderManager: RenderManager
lateinit var fontRenderer: FontRenderer
private var renderWorldList: ArrayList<RenderHudAble> = ArrayList()
@Mod.EventHandler
fun init(event: FMLInitializationEvent) {
Keybinds.register()
registerEventListeners()
try {
val resource: net.minecraft.client.resources.IResource = Minecraft.getMinecraft().resourceManager
.getResource(net.minecraft.util.ResourceLocation("test:test.txt"))
org.apache.commons.io.IOUtils.copy(resource.inputStream, java.lang.System.out)
} catch (e: java.io.IOException) {
throw java.lang.RuntimeException(e)
}
// Client Commands
if (FMLCommonHandler.instance().effectiveSide.isClient) {
ModCommandRegistry.register(ClientCommands)
registerBaseCommand()
MinecraftForge.EVENT_BUS.register(GuiOpener)
STBKeyBinds.init()
tessellator = Tessellator.getInstance()
worldRenderer = tessellator.worldRenderer
renderManager = Minecraft.getMinecraft().renderManager
fontRenderer = Minecraft.getMinecraft().fontRendererObj
MinecraftForge.EVENT_BUS.register(this)
MinecraftForge.EVENT_BUS.register(KeyInputHandler())
MinecraftForge.EVENT_BUS.register(RouteMarkerRender())
}
// @SubscribeEvent
// fun worldLoadEvent(event: WorldEvent.Load) {
// val msg = "Hello illy!"
// renderWorldList.add(
// HudText(
// arrayOf(msg),
// (Display.getWidth() / 2),
// Display.getHeight() / 2 / 2,
// false
// )
// )
// }
@SubscribeEvent
fun renderOverlayEvent(event: RenderGameOverlayEvent.Text) {
if (renderWorldList.size == 0) {
return
}
for (render: RenderHudAble in renderWorldList) {
render.render(event.partialTicks)
}
}
}
interface RenderHudAble {
fun render(partialTicks: Float)
}
interface RenderWorldAble {
fun render(partialTicks: Float)
}
object STBKeyBinds {
lateinit var addWaypoint: KeyBinding
lateinit var finishWaypoints: KeyBinding
lateinit var clearWaypoints: KeyBinding
lateinit var openRoutesGui: KeyBinding
lateinit var xrayChests: KeyBinding
fun init() {
addWaypoint = KeyBinding("key.addWaypoint", Keyboard.KEY_ADD, "key.categories.sbt")
ClientRegistry.registerKeyBinding(addWaypoint)
finishWaypoints = KeyBinding("key.finishWaypoints", Keyboard.KEY_P, "key.categories.sbt")
ClientRegistry.registerKeyBinding(finishWaypoints)
clearWaypoints = KeyBinding("key.clearWaypoints", Keyboard.KEY_MINUS, "key.categories.sbt")
ClientRegistry.registerKeyBinding(clearWaypoints)
openRoutesGui = KeyBinding("key.openRoutesGui", Keyboard.KEY_O, "key.categories.sbt")
ClientRegistry.registerKeyBinding(openRoutesGui)
xrayChests = KeyBinding("key.xrayToggle", Keyboard.KEY_I, "key.categories.sbt")
ClientRegistry.registerKeyBinding(xrayChests)
}
}
class KeyInputHandler {
private val mc = Minecraft.getMinecraft()
@SubscribeEvent
fun onKeyInput(event: InputEvent.KeyInputEvent?) {
if (STBKeyBinds.addWaypoint.isPressed) {
val x = mc.thePlayer.posX.toInt()
val y = mc.thePlayer.posY.toInt()
val z = mc.thePlayer.posZ.toInt() - 1 // Offset from player (no clue why I need this)
if (!isPointInRouteList(SkyBlockTweaks.routeList, x, y, z)) {
val name = SkyBlockTweaks.routeList.size + 1
val point = RouteMarker(x, y, z, 0u, 1u, 0u, RouteOptions(name.toString()))
SkyBlockTweaks.routeList.add(point)
mc.thePlayer.addChatMessage(ChatComponentText("Adding Point ($x, $y, $z) to route list"))
} else {
mc.thePlayer.addChatMessage(ChatComponentText("Point ($x, $y, $z) is already in the route list"))
}
} else if (STBKeyBinds.finishWaypoints.isPressed) {
mc.thePlayer.addChatMessage(ChatComponentText("Finished route! Copied route to clipboard"))
val jsonString = Gson().toJson(SkyBlockTweaks.routeList)
setClipboard(jsonString)
SkyBlockTweaks.routeList.clear()
} else if (STBKeyBinds.clearWaypoints.isPressed) {
SkyBlockTweaks.routeList.clear()
mc.thePlayer.addChatMessage(ChatComponentText("Reset current route"))
} else if (STBKeyBinds.openRoutesGui.isPressed) {
mc.displayGuiScreen(RouteGui())
} else if (STBKeyBinds.xrayChests.isPressed) {
highlightChests()
}
}
private fun registerEventListeners() {
registerCustomEventListeners()
MinecraftForge.EVENT_BUS.register(GuiOpener)
MinecraftForge.EVENT_BUS.register(RouteBuilder)
MinecraftForge.EVENT_BUS.register(GrottoFinder)
MinecraftForge.EVENT_BUS.register(MineshaftHelper)
private fun highlightChests() {
val searchRadius = 8
val world = Minecraft.getMinecraft().thePlayer.worldObj
val posX = Minecraft.getMinecraft().thePlayer.posX
val posY = Minecraft.getMinecraft().thePlayer.posY
val posZ = Minecraft.getMinecraft().thePlayer.posZ
val boundXMax = posX + searchRadius
val boundXMin = posX - searchRadius
val boundYMax = posY + searchRadius
val boundYMin = posY - searchRadius
val boundZMax = posZ + searchRadius
val boundZMin = posZ - searchRadius
val maxMarker =
RouteMarker(boundXMax.toInt(), boundYMax.toInt(), boundZMax.toInt(), 1u, 0u, 0u, RouteOptions("Max Bounds"))
val minMarker =
RouteMarker(boundXMin.toInt(), boundYMin.toInt(), boundZMin.toInt(), 0u, 1u, 0u, RouteOptions("Min Bounds"))
Minecraft.getMinecraft().thePlayer.addChatMessage(ChatComponentText("Searching..."))
for (x in boundXMin.toInt()..boundXMax.toInt()) {
for (y in boundYMin.toInt()..boundYMax.toInt()) {
for (z in boundZMin.toInt()..boundZMax.toInt()) {
val block = world.getBlockState(BlockPos(x, y, z)).block
if (block == Blocks.chest || block == Blocks.trapped_chest || block == Blocks.ender_chest) {
val point = RouteMarker(x, y, z, 0u, 0u, 1u, RouteOptions("Located point"))
SkyBlockTweaks.routeList.add(point)
}
}
}
}
Minecraft.getMinecraft().thePlayer.addChatMessage(ChatComponentText("Done!"))
// SkyBlockTweaks.routeList.add(maxMarker)
// SkyBlockTweaks.routeList.add(minMarker)
}
}
data class RouteMarker(
val x: Int,
val y: Int,
val z: Int,
val r: UByte,
val g: UByte,
val b: UByte,
val options: RouteOptions
)
fun isPointInRouteList(routeList: List<RouteMarker>, x: Int, y: Int, z: Int): Boolean {
return routeList.any { it.x == x && it.y == y && it.z == z }
}
data class RouteOptions(
val name: String
)
fun setClipboard(s: String) {
val selection = StringSelection(s)
val clipboard: Clipboard = Toolkit.getDefaultToolkit().systemClipboard
clipboard.setContents(selection, selection)
}
class RouteMarkerRender {
@SubscribeEvent
fun renderBlockOverlay(event: RenderWorldLastEvent) {
val player = Minecraft.getMinecraft().thePlayer
for (marker: RouteMarker in SkyBlockTweaks.routeList) {
val pos = BlockPos(marker.x, marker.y, marker.z)
renderPoint(player, pos, event.partialTicks)
}
}
}
fun renderPoint(entity: Entity, blockPos: BlockPos, partialTicks: Float) {
val padding: Double = 0.0020000000949949026
val entityX: Double = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
val entityY: Double = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
val entityZ: Double = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks
val outlineStartColor = 0xFFFFFF
val outlineEndColor = 0xFFFFFF
val world = Minecraft.getMinecraft().theWorld
val blockState = world.getBlockState(blockPos)
val block: Block = blockState.block
// Create a default bounding box for blocks that don't have one
val boundingBox: AxisAlignedBB = block.getCollisionBoundingBox(world, blockPos, blockState)
?: AxisAlignedBB(
blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(),
blockPos.x + 1.0, blockPos.y + 1.0, blockPos.z + 1.0
).expand(padding, padding, padding)
GL11.glPushMatrix()
GlStateManager.disableTexture2D()
GlStateManager.depthMask(false)
GlStateManager.disableDepth()
GL11.glEnable(GL11.GL_LINE_SMOOTH)
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
GL11.glLineWidth(2.0f)
GL11.glShadeModel(GL11.GL_SMOOTH)
RenderUtils().drawBlock(boundingBox.offset(-entityX, -entityY, -entityZ), outlineStartColor, outlineEndColor)
GL11.glLineWidth(2.0f)
GL11.glDisable(GL11.GL_LINE_SMOOTH)
GlStateManager.enableDepth()
GlStateManager.depthMask(true)
GlStateManager.enableAlpha()
GlStateManager.enableTexture2D()
GL11.glPopMatrix()
}
class RouteMarkerButton(buttonId: Int, x: Int, y: Int, widthIn: Int, heightIn: Int, buttonText: String?) :
GuiButton(buttonId, x, y, widthIn, heightIn, buttonText) {
constructor(buttonId: Int, x: Int, y: Int, buttonText: String?) : this(buttonId, x, y, 200, 20, buttonText)
override fun drawButton(mc: Minecraft, mouseX: Int, mouseY: Int) {
if (visible) {
val fontrenderer = mc.fontRendererObj
//mc.getTextureManager().bindTexture(buttonTextures);
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f)
hovered =
mouseX >= xPosition && mouseY >= yPosition && mouseX < xPosition + width && mouseY < yPosition + height
//int i = this.getHoverState(this.hovered);
drawRect(
xPosition, yPosition, xPosition + width, yPosition + height,
if (hovered) Color(255, 255, 255, 80).rgb else Color(0, 0, 0, 80).rgb
)
//this.drawTexturedModalRect(this.xPosition, this.yPosition, 0, 46 + i * 20, this.width / 2, this.height);
//this.drawTexturedModalRect(this.xPosition + this.width / 2, this.yPosition, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
mouseDragged(mc, mouseX, mouseY)
var j = 14737632
if (packedFGColour != 0) {
j = packedFGColour
} else if (!enabled) {
j = 10526880
} else if (hovered) {
j = 16777120
}
drawCenteredString(
fontrenderer,
displayString, xPosition + width / 2, yPosition + (height - 8) / 2, j
)
}
}
}
class RouteGui : GuiScreen() {
private val id: Int = 0
override fun initGui() {
super.initGui()
buttonList.clear()
populateRouteList()
buttonList.add(RouteMarkerButton(9000, width / 2 + 20, height - 40, "Exit"))
}
private fun registerCustomEventListeners() {
MinecraftForge.EVENT_BUS.register(ForgeEventListener)
override fun actionPerformed(button: GuiButton?) {
if (button == null) {
return
}
if (button.id < 1000) {
buttonList.remove(button)
} else if (button.id == 9000) {
Minecraft.getMinecraft().thePlayer.closeScreen()
}
}
ModEventBus.register(MineshaftHelper)
override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) {
this.drawDefaultBackground()
super.drawScreen(mouseX, mouseY, partialTicks)
}
private fun populateRouteList() {
for ((buttonId, m: RouteMarker) in SkyBlockTweaks.routeList.withIndex()) {
val markerField = GuiTextField(1000 + buttonId, fontRendererObj, width / 2 - 200, 0, 100, 20)
markerField.text = "${m.options.name} X:${m.x} Y:${m.y} Z:${m.z}"
val removeButton = RouteMarkerButton(2000 + buttonId, width / 2 + 175, 0, 50, 20, "Remove")
buttonList.add(removeButton)
}
}
}

View File

@ -1,10 +0,0 @@
package com.github.itzilly.sbt.command
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class SubCommand(
val name: String,
val usage: String = "",
val description: String = "",
val aliases: Array<String> = []
)

View File

@ -1,31 +0,0 @@
package com.github.itzilly.sbt.command
import net.minecraft.command.CommandBase
import net.minecraft.command.ICommandSender
import net.minecraft.util.BlockPos
import net.minecraftforge.client.ClientCommandHandler
fun registerBaseCommand() {
ClientCommandHandler.instance.registerCommand(object : CommandBase() {
override fun getCommandName() = "sbt"
override fun getCommandUsage(sender: ICommandSender) = "/sbt <subcommand>"
override fun processCommand(sender: ICommandSender, args: Array<out String>) {
ModCommandRegistry.dispatch(CommandContext(sender, args))
}
override fun addTabCompletionOptions(
sender: ICommandSender,
args: Array<out String>,
pos: BlockPos?
): List<String>? {
return if (args.size == 1) {
ModCommandRegistry.subcommands.keys.toList().distinct().filter { it.startsWith(args[0]) }
} else null
}
override fun canCommandSenderUseCommand(sender: ICommandSender): Boolean {
return true
}
})
}

View File

@ -1,57 +0,0 @@
package com.github.itzilly.sbt.command
import com.github.itzilly.sbt.features.GrottoFinder
import com.github.itzilly.sbt.gui.MineshaftGui
import com.github.itzilly.sbt.util.Chatterbox
import com.github.itzilly.sbt.util.GuiOpener
import com.github.itzilly.sbt.util.SimpleChatMsg
import com.github.itzilly.sbt.util.getAreaNameFromScoreboard
import com.github.itzilly.sbt.util.getMiniIdFromTab
object ClientCommands {
// @SubCommand(name="search", usage = "<gold|jasper>", description = "Switch between searches")
// fun search(ctx: CommandContext) {
// val action = ctx.arg(0)?.lowercase()
//
// when (action) {
// "gold" -> {
// GrottoFinder.isGrottoEnabled = false
// GoldFinder.isGoldFinderEnabled = true
// Chatterbox.say("Disabling Grotto finder and Enabling Gold finder")
// }
//
// "jasper" -> {
// GrottoFinder.isGrottoEnabled = true
// GoldFinder.isGoldFinderEnabled = false
// Chatterbox.say("Disabling Gold finder and Enabling Grotto finder")
// }
//
// else -> {
// Chatterbox.say("Status:")
//
// val grottoStatus = if (GrottoFinder.isGrottoEnabled)
// SimpleChatMsg(" - Grotto Finder: ENABLED").green()
// else
// SimpleChatMsg(" - Grotto Finder: DISABLED").red()
//
// val goldStatus = if (GoldFinder.isGoldFinderEnabled)
// SimpleChatMsg(" - Gold Finder: ENABLED").green()
// else
// SimpleChatMsg(" - Gold Finder: DISABLED").red()
//
// Chatterbox.say(grottoStatus)
// Chatterbox.say(goldStatus)
// }
// }
// }
@SubCommand(name = "msgui", usage = "", description = "Open Mineshaft GUI")
fun openMineshaftGUI() {
val area = getAreaNameFromScoreboard()?.lowercase()
if (area == null || "mineshaft" !in area) {
Chatterbox.say(SimpleChatMsg("You are not in a mineshaft!").red())
}
GuiOpener.ScheduleGui(MineshaftGui())
}
}

View File

@ -1,54 +0,0 @@
package com.github.itzilly.sbt.command
import net.minecraft.client.Minecraft
import net.minecraft.command.ICommandSender
import net.minecraft.util.ChatComponentText
/**
* Wrapper for command execution context.
*
* Provides access to the command sender, arguments, and helper methods.
*
* @property sender The ICommandSender executing the command.
* @property args The raw array of command arguments.
*/
class CommandContext(
val sender: ICommandSender,
var args: Array<out String>
) {
/**
* The client-side player instance.
* Can be null in rare cases (e.g., not in-game).
*/
val player get() = Minecraft.getMinecraft().thePlayer
/**
* Sends a chat message to the player.
*
* @param msg The message to send.
*/
fun send(msg: String) {
player?.addChatMessage(ChatComponentText(msg))
}
/**
* Retrieves an argument at the given index, or null if not present.
*
* @param index The argument index.
* @return The argument or null.
*/
fun arg(index: Int): String? = args.getOrNull(index)
/**
* Retrieves an argument and throws if it's missing.
*
* @param index The argument index.
* @param error Error message to show if argument is missing.
* @return The argument string.
* @throws IllegalArgumentException if missing.
*/
fun require(index: Int, error: String): String {
return args.getOrNull(index) ?: throw IllegalArgumentException(error)
}
}

View File

@ -1,66 +0,0 @@
package com.github.itzilly.sbt.command
object ModCommandRegistry {
val subcommands = mutableMapOf<String, CommandEntry>()
fun register(target: Any) {
for (method in target::class.java.declaredMethods) {
val annotation = method.getAnnotation(SubCommand::class.java) ?: continue
val entry = CommandEntry(annotation, method, target)
subcommands[annotation.name.lowercase()] = entry
annotation.aliases.forEach {
subcommands[it.lowercase()] = entry
}
}
}
fun dispatch(context: CommandContext) {
val sub = context.arg(0)?.lowercase()
val subArgs = context.args.drop(1).toTypedArray()
if (sub == null || sub == "help") {
showHelp(context, subArgs.firstOrNull())
return
}
val cmd = subcommands[sub]
if (cmd != null) {
context.args = subArgs
cmd.invoke(context)
} else {
context.send("Unknown subcommand '$sub'. Use /sbt help.")
}
}
private fun showHelp(ctx: CommandContext, target: String?) {
if (target != null) {
val cmd = subcommands[target.lowercase()]
if (cmd != null) {
ctx.send("Usage: /sbt ${cmd.annotation.name} ${cmd.annotation.usage}")
ctx.send(cmd.annotation.description)
return
}
ctx.send("Unknown command '$target'")
return
}
ctx.send("Available /sbt commands:")
subcommands.values.toSet().forEach {
ctx.send("- ${it.annotation.name} ${it.annotation.usage} : ${it.annotation.description}")
}
}
class CommandEntry(
val annotation: SubCommand,
val method: java.lang.reflect.Method,
val target: Any
) {
fun invoke(ctx: CommandContext) {
try {
method.invoke(target, ctx)
} catch (e: Exception) {
ctx.send("§cError: ${e.cause?.message ?: e.message}")
}
}
}
}

View File

@ -1,17 +0,0 @@
package com.github.itzilly.sbt.data
data class RouteNode(
val x: Int,
val y: Int,
val z: Int,
val r: UByte,
val g: UByte,
val b: UByte,
val options: NodeOptions
)
data class NodeOptions(
val name: String
)

View File

@ -1,4 +0,0 @@
package com.github.itzilly.sbt.data
data class Vec3d(val x:Double, val y:Double, val z:Double)
data class Vecf3(val x:Float, val y:Float, val z:Float)

View File

@ -1,11 +0,0 @@
package com.github.itzilly.sbt.events
import net.minecraftforge.client.event.RenderWorldLastEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
object ForgeEventListener {
@SubscribeEvent
fun onRenderWorldLast(event: RenderWorldLastEvent) {
ModEventBus.post(RenderUIOverlayEvent(event))
}
}

View File

@ -1,5 +0,0 @@
package com.github.itzilly.sbt.events
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Listen

View File

@ -1,6 +0,0 @@
package com.github.itzilly.sbt.events
import net.minecraftforge.client.event.RenderWorldLastEvent
open class ModEvent
class RenderUIOverlayEvent(val original: RenderWorldLastEvent) : ModEvent() { val partialTicks: Float get() = original.partialTicks }

View File

@ -1,32 +0,0 @@
package com.github.itzilly.sbt.events
object ModEventBus {
private val listeners = mutableMapOf<Class<out ModEvent>, MutableList<(ModEvent) -> Unit>>()
fun register(obj: Any) {
for (method in obj::class.java.declaredMethods) {
if (method.isAnnotationPresent(Listen::class.java)) {
val params = method.parameterTypes
if (params.size != 1 || !ModEvent::class.java.isAssignableFrom(params[0])) continue
val eventClass = params[0] as Class<out ModEvent>
method.isAccessible = true
listeners.computeIfAbsent(eventClass) { mutableListOf() }.add { event ->
try {
method.invoke(obj, event)
} catch (e: Exception) {
println("Error in listener ${method.name} of ${obj::class.simpleName}: ${e.cause}")
e.cause?.printStackTrace()
}
}
}
}
}
fun <T : ModEvent> post(event: T) {
listeners[event::class.java]?.forEach { handler ->
handler(event)
}
}
}

View File

@ -1,8 +0,0 @@
package com.github.itzilly.sbt.events.custom
import net.minecraft.util.BlockPos
import net.minecraft.block.Block
import net.minecraft.client.entity.EntityPlayerSP
import net.minecraftforge.fml.common.eventhandler.Event
class ClientBlockBreakEvent(val pos: BlockPos, val block: Block, val player: EntityPlayerSP) : Event()

View File

@ -1,164 +0,0 @@
package com.github.itzilly.sbt.features
import com.github.itzilly.sbt.SkyBlockTweaks
import com.github.itzilly.sbt.render.BlockOutlineRenderer
import net.minecraft.client.Minecraft
import net.minecraft.init.Blocks
import net.minecraft.util.BlockPos
import net.minecraftforge.client.event.RenderWorldLastEvent
import net.minecraftforge.common.config.Configuration
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
enum class GemstoneColors(val color: Int) {
RUBY(0xFF5555), // Red
JADE(0x00AA00), // Lime
AMBER(0xFFAA00), // Orange
SAPPHIRE(0x55FFFF), // Light Blue
AMETHYST(0xAA00AA), // Purple
TOPAZ(0xFFFF55), // Yellow
JASPER(0xFF55FF), // Magenta
OPAL(0xFFFFFF), // White (clear glass)
CITRINE(0x8B5A2B), // Brown (approximate, earthy tone)
AQUAMARINE(0x1D57C0), // Deep Lapis Blue
PERIDOT(0x3F9B0B), // Cactus Green
ONYX(0x000000) // Black
}
object GemstoneFinder {
private var gemstoneClusters: ArrayList<GemstoneCluster> = ArrayList()
private var gemstoneList: ArrayList<GemstoneBlock> = ArrayList()
var radius = SkyBlockTweaks.config.getCategory(Configuration.CATEGORY_GENERAL)?.get("gemstonesearchradius")?.int?: 16
fun clear() {
gemstoneClusters.clear()
}
fun find() {
val playerPos = Minecraft.getMinecraft().thePlayer.position
val minBounds = BlockPos(
playerPos.x - radius,
maxOf(playerPos.y - radius, 31),
playerPos.z - radius
)
val maxBounds = BlockPos(
playerPos.x + radius,
minOf(playerPos.y + radius, 188),
playerPos.z + radius
)
val world = Minecraft.getMinecraft().thePlayer.worldObj
val gemstonesMap = mutableMapOf<GemstoneColors, MutableList<BlockPos>>()
for (chunkX in minBounds.x / 16..maxBounds.x / 16) {
for (chunkZ in minBounds.z / 16..maxBounds.z / 16) {
val chunk = world.getChunkFromChunkCoords(chunkX, chunkZ)
for (x in 0..15) {
for (y in minBounds.y..maxBounds.y) {
for (z in 0..15) {
val worldX = chunk.xPosition * 16 + x
val worldZ = chunk.zPosition * 16 + z
if (worldX in minBounds.x..maxBounds.x && worldZ in minBounds.z..maxBounds.z) {
val blockPos = BlockPos(worldX, y, worldZ)
val blockState = chunk.getBlockState(blockPos)
val block = blockState.block
if (block == Blocks.air) continue
val meta = block.getMetaFromState(blockState)
val gemstoneColor = when {
block === Blocks.stained_glass || block === Blocks.stained_glass_pane -> {
when (meta) {
1 -> GemstoneColors.AMBER // Orange
2 -> GemstoneColors.JASPER // Magenta
3 -> GemstoneColors.SAPPHIRE // Light Blue
4 -> GemstoneColors.TOPAZ // Yellow
5 -> GemstoneColors.JADE // Lime
14 -> GemstoneColors.RUBY // Red
10 -> GemstoneColors.AMETHYST // Purple
else -> null
}
}
else -> null
}
if (gemstoneColor != null) {
gemstonesMap.getOrPut(gemstoneColor) { mutableListOf() }.add(blockPos)
}
}
}
}
}
}
}
for ((color, positions) in gemstonesMap) {
val clusters = clusterGemstones(positions)
for (cluster in clusters) {
gemstoneClusters.add(GemstoneCluster(cluster, color))
}
}
}
private fun clusterGemstones(positions: List<BlockPos>): List<List<BlockPos>> {
val clusters = mutableListOf<List<BlockPos>>()
val visited = mutableSetOf<BlockPos>()
fun dfs(start: BlockPos, cluster: MutableList<BlockPos>) {
val stack = ArrayDeque<BlockPos>()
stack.add(start)
while (stack.isNotEmpty()) {
val pos = stack.removeLast()
if (pos in visited) continue
visited.add(pos)
cluster.add(pos)
// Check adjacent blocks in all six directions
for (offset in listOf(BlockPos(1, 0, 0), BlockPos(-1, 0, 0), BlockPos(0, 1, 0), BlockPos(0, -1, 0), BlockPos(0, 0, 1), BlockPos(0, 0, -1))) {
val neighbor = pos.add(offset)
if (neighbor in positions && neighbor !in visited) {
stack.add(neighbor)
}
}
}
}
for (pos in positions) {
if (pos !in visited) {
val cluster = mutableListOf<BlockPos>()
dfs(pos, cluster)
clusters.add(cluster)
}
}
return clusters
}
@SubscribeEvent
fun renderBlockOverlay(event: RenderWorldLastEvent) {
val player = Minecraft.getMinecraft().thePlayer
for (cluster in gemstoneClusters) {
BlockOutlineRenderer.drawClusterOutline(player, cluster.positions, event.partialTicks, cluster.color.color)
}
}
private data class GemstoneCluster(
val positions: List<BlockPos>,
val color: GemstoneColors
)
private data class GemstoneBlock(
val x: Int,
val y: Int,
val z: Int,
val color: GemstoneColors,
val maxX: Int = x,
val maxY: Int = y,
val maxZ: Int = z
)
}

View File

@ -1,345 +0,0 @@
package com.github.itzilly.sbt.features
import com.github.itzilly.sbt.Keybinds
import com.github.itzilly.sbt.events.custom.ClientBlockBreakEvent
import com.github.itzilly.sbt.render.BlockOutlineRenderer
import com.github.itzilly.sbt.util.Chatterbox
import com.github.itzilly.sbt.util.SimpleChatMsg
import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.init.Blocks
import net.minecraft.util.BlockPos
import net.minecraft.util.ChatComponentText
import net.minecraft.util.ChatStyle
import net.minecraft.util.EnumChatFormatting
import net.minecraft.world.World
import net.minecraft.world.chunk.Chunk
import net.minecraftforge.client.event.RenderWorldLastEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.InputEvent
object GrottoFinder {
var isGrottoEnabled: Boolean = true
private var isRunningAutoDetect: Boolean = true
private var autoDetectEnabled: Boolean = false
private val scannedChunks = mutableMapOf<Pair<Int, Int>, Long>()
private val pendingJasperBlocks = mutableListOf<BlockPos>()
private var hasLocatedGrotto = false
private const val SCAN_COOLDOWN_MS = 5 * 60 * 1100 // 5 minutes (+ a little to account for lag)
// World Bounds 824, 189, 824 201, 30, 201
private val minBounds = BlockPos(201, 30, 201) // Max area of the Crystal Hollows
private val maxBounds = BlockPos(824, 189, 824) // Max area of the Crystal Hollows
private val targetBlock: Block = Blocks.stained_glass
private val targetMeta: Int = 2 // Magenta stained glass
private var lastWorldLoadTime = 0L
private var lastMiniServerId: String? = null
private var renderBlockList: ArrayList<BlockPos> = ArrayList()
private var jasperCrystalsList: ArrayList<BlockPos> = ArrayList()
fun enableAutoDetect() {
autoDetectEnabled = true
}
fun disableAutoDetect() {
autoDetectEnabled = false
}
fun isAutoDetectEnabled(): Boolean {
return autoDetectEnabled
}
fun clear() {
renderBlockList.clear()
}
private fun magentaNodeExists(x: Int, y: Int, z: Int): Boolean {
return renderBlockList.any { it.x == x && it.y == y && it.z == z }
}
@SubscribeEvent
fun onKeyInput(event: InputEvent.KeyInputEvent) {
if (!isGrottoEnabled) { return }
if (Keybinds.searchGrotto.isPressed) {
Chatterbox.say("Checking chunks for grotto...")
checkWorldForMagentaStainedGlassAsync(Minecraft.getMinecraft().theWorld)
renderBlockList.addAll(jasperCrystalsList)
}
if (Keybinds.clearGrotto.isPressed) {
renderBlockList.clear()
}
}
@Deprecated("Use async instead")
private fun checkWorldForMagentaStainedGlassSync(world: World) {
for (chunkX in minBounds.x / 16..maxBounds.x / 16) {
for (chunkZ in minBounds.z / 16..maxBounds.z / 16) {
val chunk = world.getChunkFromChunkCoords(chunkX, chunkZ)
// Iterate through the chunk's blocks within the world bounds
for (x in 0..15) {
for (y in minBounds.y..maxBounds.y) {
for (z in 0..15) {
val worldX = chunk.xPosition * 16 + x
val worldZ = chunk.zPosition * 16 + z
// Ensure the block is within the specified bounds
if (worldX in minBounds.x..maxBounds.x && worldZ in minBounds.z..maxBounds.z) {
val blockPos = BlockPos(worldX, y, worldZ)
val blockState = chunk.getBlockState(blockPos)
val block = blockState.block
val meta = block.getMetaFromState(blockState)
if (block === targetBlock && meta == targetMeta) {
if (!magentaNodeExists(blockPos.x, blockPos.y, blockPos.z)) {
renderBlockList.add(BlockPos(blockPos.x, blockPos.y, blockPos.z))
}
}
}
}
}
}
}
}
if (renderBlockList.isNotEmpty()) {
val pos = renderBlockList[0]
val msg = SimpleChatMsg(
"Found Jasper near (%d, %d, %d)".format(
pos.x,
pos.y,
pos.z
)
).light_purple()
Chatterbox.say(msg)
}
}
fun checkWorldForMagentaStainedGlassAsync(world: World) {
Thread {
val foundBlocks = ArrayList<BlockPos>()
for (chunkX in minBounds.x / 16..maxBounds.x / 16) {
for (chunkZ in minBounds.z / 16..maxBounds.z / 16) {
val chunk = world.getChunkFromChunkCoords(chunkX, chunkZ)
for (x in 0..15) {
for (y in minBounds.y..maxBounds.y) {
for (z in 0..15) {
val worldX = chunk.xPosition * 16 + x
val worldZ = chunk.zPosition * 16 + z
if (worldX in minBounds.x..maxBounds.x && worldZ in minBounds.z..maxBounds.z) {
val blockPos = BlockPos(worldX, y, worldZ)
val blockState = chunk.getBlockState(blockPos)
val block = blockState.block
val meta = block.getMetaFromState(blockState)
if (block === targetBlock && meta == targetMeta) {
foundBlocks.add(blockPos)
}
}
}
}
}
}
}
Minecraft.getMinecraft().addScheduledTask {
clear()
renderBlockList.addAll(foundBlocks)
if (renderBlockList.isNotEmpty()) {
val pos = renderBlockList[0]
val msg = SimpleChatMsg(
"Found Jasper near (%d, %d, %d)".format(
pos.x,
pos.y,
pos.z
)
).light_purple()
Chatterbox.say(msg)
} else {
Chatterbox.say("No Jasper found.")
}
}
}.start()
}
@SubscribeEvent
fun renderBlockOverlay(event: RenderWorldLastEvent) {
val player = Minecraft.getMinecraft().thePlayer
if (!isGrottoEnabled) { return }
for (glass: BlockPos in renderBlockList) {
val pos = BlockPos(glass.x, glass.y, glass.z)
BlockOutlineRenderer.drawBlockOutline(player, pos, event.partialTicks)
BlockOutlineRenderer.drawBlockLine(pos, event.partialTicks)
}
}
private fun isInCrystalHollowsFromTab(): Boolean {
val infoList = Minecraft.getMinecraft().thePlayer?.sendQueue?.playerInfoMap ?: return false
val lines = infoList
.mapNotNull { it.displayName?.unformattedText }
.map { it.trim() }
.filter { it.isNotBlank() }
for (i in 0 until lines.size - 1) {
if (lines[i].equals("Info", ignoreCase = true) &&
lines[i + 1].contains("Area: Crystal Hollows", ignoreCase = true)
) {
return true
}
}
return false
}
// @SubscribeEvent
// fun onEntityJoinWorldEvent(event: EntityJoinWorldEvent) {
// val mc = Minecraft.getMinecraft()
// val player = mc.thePlayer
// val TWO_SECONDS = 2000
//
// if (event.entity === player && event.world.isRemote) {
// val now = System.currentTimeMillis()
// if (now - lastWorldLoadTime < TWO_SECONDS) return
// lastWorldLoadTime = now
//
// DelayedFunction({
// isRunningAutoDetect = isInCrystalHollowsFromTab()
// if (isRunningAutoDetect) {
// if (pendingJasperBlocks.isNotEmpty()) {
// jasperCrystalsList.addAll(pendingJasperBlocks)
// pendingJasperBlocks.clear()
// showRevealMessage()
// }
// }
// }, delayTicks = 100)
// }
// }
// @SubscribeEvent
// fun onClientTick(event: TickEvent.ClientTickEvent) {
// if (!autoDetectEnabled || event.phase != TickEvent.Phase.END) return
//
// val currentMiniId = getMiniServerIdFromScoreboard() ?: return
// if (currentMiniId != lastMiniServerId) {
// if (lastMiniServerId != null) {
// // TODO: fix
//// isRunningAutoDetect = false
// renderBlockList.clear()
// jasperCrystalsList.clear()
// pendingJasperBlocks.clear()
// hasLocatedGrotto = false
// }
// lastMiniServerId = currentMiniId
// }
// }
// @SubscribeEvent
// fun onChunkLoad(event: ChunkEvent.Load) {
// if (!autoDetectEnabled) return
//
// val chunk = event.chunk
// val key = Pair(chunk.xPosition, chunk.zPosition)
// val now = System.currentTimeMillis()
//
// if (now - (scannedChunks[key] ?: 0) < SCAN_COOLDOWN_MS) return
// scannedChunks[key] = now
//
// scanChunkForJasper(chunk)
// }
private fun scanChunkForJasper(chunk: Chunk) {
Thread {
val found = mutableListOf<BlockPos>()
val baseX = chunk.xPosition * 16
val baseZ = chunk.zPosition * 16
for (x in 0..15) {
for (y in minBounds.y..maxBounds.y) {
for (z in 0..15) {
val pos = BlockPos(baseX + x, y, baseZ + z)
val blockState = chunk.getBlockState(pos)
val block = blockState.block
val meta = block.getMetaFromState(blockState)
if (block == targetBlock && meta == targetMeta) {
found.add(pos)
}
}
}
}
if (found.count() != 1) {
if (isRunningAutoDetect) {
jasperCrystalsList.addAll(found)
if (!hasLocatedGrotto) {
showRevealMessage()
hasLocatedGrotto = true
}
} else {
pendingJasperBlocks.addAll(found)
}
}
Chatterbox.say("Scanned Chunk, found: ${found.count()}")
}.start()
}
private fun showRevealMessage() {
Chatterbox.say(SimpleChatMsg("- - - - - - - - - - - - - - - - - - -").light_purple())
val clickMsg = ChatComponentText("§dDetected Fairy Grotto! §7[Click to reveal]").apply {
chatStyle = ChatStyle().apply {
color = EnumChatFormatting.LIGHT_PURPLE
underlined = true
chatClickEvent = net.minecraft.event.ClickEvent(
net.minecraft.event.ClickEvent.Action.RUN_COMMAND,
"/sbt reveal_grotto"
)
chatHoverEvent = net.minecraft.event.HoverEvent(
net.minecraft.event.HoverEvent.Action.SHOW_TEXT,
ChatComponentText("§7Click to show block outlines.")
)
}
}
Chatterbox.say(clickMsg)
Chatterbox.say(SimpleChatMsg("- - - - - - - - - - - - - - - - - - -").light_purple())
}
fun revealDetectedJasperBlocks() {
jasperCrystalsList.addAll(pendingJasperBlocks)
if (jasperCrystalsList.isEmpty()) {
Chatterbox.say(SimpleChatMsg("[Grotto] No Jasper found!").light_purple())
return
}
renderBlockList.clear()
renderBlockList.addAll(jasperCrystalsList)
Chatterbox.say(SimpleChatMsg("[Grotto] Revealed detected Fairy Grotto blocks").light_purple())
val pos = renderBlockList[0]
val msg = SimpleChatMsg(
"Found Jasper near (%d, %d, %d)".format(
pos.x,
pos.y,
pos.z
)
).light_purple()
Chatterbox.say(msg)
}
@SubscribeEvent
fun onBlockBreakEvent(event: ClientBlockBreakEvent) {
renderBlockList.remove(event.pos)
jasperCrystalsList.remove(event.pos)
pendingJasperBlocks.remove(event.pos)
}
}

View File

@ -1,500 +0,0 @@
package com.github.itzilly.sbt.features
import com.github.itzilly.sbt.Keybinds
import com.github.itzilly.sbt.events.Listen
import com.github.itzilly.sbt.events.RenderUIOverlayEvent
import com.github.itzilly.sbt.gui.MineshaftGui
import com.github.itzilly.sbt.render.BlockOutlineRenderer
import com.github.itzilly.sbt.util.Chatterbox
import com.github.itzilly.sbt.util.LoopedFunction
import com.github.itzilly.sbt.util.SimpleChatMsg
import com.github.itzilly.sbt.util.getAreaNameFromScoreboard
import com.github.itzilly.sbt.util.getMiniIdFromTab
import net.minecraft.client.Minecraft
import net.minecraft.entity.item.EntityArmorStand
import net.minecraft.init.Blocks
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.BlockPos
import net.minecraft.util.IChatComponent
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.InputEvent
object MineshaftHelper {
private var pos1: BlockPos? = null
private var pos2: BlockPos? = null
private val gemstonePositions: MutableList<Pair<BlockPos, Gemstone>> = mutableListOf()
private val gemstoneClusters = mutableListOf<GemstoneCluster>()
private var corpses = mutableListOf<Corpse>()
private var lastMineshaftId: String? = getMiniIdFromTab()
private var corpseLoop: LoopedFunction? = null
private var drawDebug: Boolean = false
private var drawCorpses: Boolean = false
private var drawGemstones: Boolean = false
fun reset() {
drawDebug = false
drawCorpses = false
drawGemstones = false
pos1 = null
pos2 = null
gemstonePositions.clear()
gemstoneClusters.clear()
corpseLoop?.cancel()
corpses.clear()
}
fun setDebugEnabled(debugEnabled: Boolean) {
drawDebug = debugEnabled
}
fun getDebugEnabled(): Boolean {
return drawDebug
}
fun setCorpsesEnabled(corpsesEnabled: Boolean) {
drawCorpses = corpsesEnabled
}
fun getCorpsesEnabled(): Boolean {
return drawCorpses
}
fun setGemstonesEnabled(gemstonesEnabled: Boolean) {
drawGemstones = gemstonesEnabled
}
fun getGemstonesEnabled(): Boolean {
return drawGemstones
}
private val debugColors = listOf(
"Red" to 0xFF0000,
"Green" to 0x00FF00,
"Blue" to 0x0000FF,
"Cyan" to 0x00FFFF,
"Magenta" to 0xFF00FF,
"Yellow" to 0xFFFF00,
"Orange" to 0xFFA500,
"Purple" to 0x800080,
"Lime" to 0x32CD32,
"Aqua" to 0x7FFFD4
)
private enum class Gemstone(val color: Int) {
RUBY(0xFF5555), // Red
JADE(0x00AA00), // Lime
AMBER(0xFFAA00), // Orange
SAPPHIRE(0x55FFFF), // Light Blue
AMETHYST(0xAA00AA), // Purple
TOPAZ(0xFFFF55), // Yellow
JASPER(0xFF55FF), // Magenta
OPAL(0xFFFFFF), // White
CITRINE(0x8B5A2B), // Brown
AQUAMARINE(0x1D57C0), // Blue
PERIDOT(0x3F9B0B), // Green
ONYX(0x000000) // Black
}
private data class GemstoneCluster(
val positions: List<BlockPos>,
val type: Gemstone,
val boundingBox: AxisAlignedBB
)
private data class GemstoneBlock(
val x: Int,
val y: Int,
val z: Int,
val type: Gemstone,
val maxX: Int = x,
val maxY: Int = y,
val maxZ: Int = z
)
private enum class CorpseType(val displayName: String, val color: Int) {
LAPIS("Lapis", 0x0000AA),
TUNGSTEN("Tungsten", 0xAAAAAA),
UMBER("Umber", 0xAA0000),
VANGUARD("Vanguard", 0x5555FF)
}
private data class Corpse(
val x: Int,
val y: Int,
val z: Int,
val type: CorpseType,
)
@Deprecated("One time check is bad!")
fun locateBounds() {
val world = Minecraft.getMinecraft().theWorld
val start = Minecraft.getMinecraft().thePlayer.position
val searchRadius = 10
var startBedrock: BlockPos? = null
loop@ for (dx in -searchRadius..searchRadius) {
for (dy in -searchRadius..searchRadius) {
for (dz in -searchRadius..searchRadius) {
val checkPos = start.add(dx, dy, dz)
if (world.getBlockState(checkPos).block == Blocks.bedrock) {
startBedrock = checkPos
break@loop
}
}
}
}
if (startBedrock == null) {
Chatterbox.say(SimpleChatMsg("Could not locate bedrock bounds!").red())
return
}
val visited = mutableSetOf<BlockPos>()
val queue = ArrayDeque<BlockPos>()
queue.add(startBedrock)
while (queue.isNotEmpty()) {
val pos = queue.removeFirst()
if (pos in visited) continue
visited.add(pos)
for (offset in listOf(
pos.add(1, 0, 0), pos.add(-1, 0, 0),
pos.add(0, 1, 0), pos.add(0, -1, 0),
pos.add(0, 0, 1), pos.add(0, 0, -1)
)) {
if (!visited.contains(offset) &&
world.getBlockState(offset).block == Blocks.bedrock) {
queue.add(offset)
}
}
}
val minX = visited.minOf { it.x }
val maxX = visited.maxOf { it.x }
val minY = visited.minOf { it.y }
val maxY = visited.maxOf { it.y }
val minZ = visited.minOf { it.z }
val maxZ = visited.maxOf { it.z }
pos1 = BlockPos(minX, minY, minZ)
pos2 = BlockPos(maxX, maxY, maxZ)
}
fun locateGemstones() {
val world = Minecraft.getMinecraft().theWorld
val p1 = pos1 ?: return
val p2 = pos2 ?: return
val xRange = p1.x..p2.x
val yRange = p1.y..p2.y
val zRange = p1.z..p2.z
for (x in xRange) {
for (y in yRange) {
for (z in zRange) {
val blockPos = BlockPos(x, y, z)
val blockState = world.getBlockState(blockPos)
val block = blockState.block
if (block == Blocks.air) continue
val meta = block.getMetaFromState(blockState)
val gemstoneColor = when {
block === Blocks.stained_glass || block === Blocks.stained_glass_pane -> {
when (meta) {
0 -> Gemstone.OPAL // White
1 -> Gemstone.AMBER // Orange
2 -> Gemstone.JASPER // Magenta
3 -> Gemstone.SAPPHIRE // Light Blue
4 -> Gemstone.TOPAZ // Yellow
5 -> Gemstone.JADE // Lime
6 -> Gemstone.PERIDOT // Green
7 -> Gemstone.ONYX // Black
10 -> Gemstone.AMETHYST // Purple
11 -> Gemstone.AQUAMARINE // Blue
12 -> Gemstone.CITRINE // Brown
14 -> Gemstone.RUBY // Red
else -> null
}
}
else -> null
}
if (gemstoneColor != null) {
gemstonePositions.add(blockPos to gemstoneColor)
}
}
}
}
}
fun populateGemstoneLocations() {
val visited = mutableSetOf<BlockPos>()
for ((startPos, type) in gemstonePositions) {
if (startPos in visited) continue
val queue = ArrayDeque<BlockPos>()
val clusterPositions = mutableListOf<BlockPos>()
queue.add(startPos)
while (queue.isNotEmpty()) {
val current = queue.removeFirst()
if (current in visited) continue
visited.add(current)
clusterPositions.add(current)
for (dx in -1..1) {
for (dy in -1..1) {
for (dz in -1..1) {
if (dx == 0 && dy == 0 && dz == 0) continue
val neighbor = current.add(dx, dy, dz)
if (neighbor in visited) continue
val match = gemstonePositions.find { it.first == neighbor && it.second == type }
if (match != null) {
queue.add(neighbor)
}
}
}
}
}
if (clusterPositions.isNotEmpty()) {
val minX = clusterPositions.minOf { it.x }
val minY = clusterPositions.minOf { it.y }
val minZ = clusterPositions.minOf { it.z }
val maxX = clusterPositions.maxOf { it.x }
val maxY = clusterPositions.maxOf { it.y }
val maxZ = clusterPositions.maxOf { it.z }
val boundingBox = AxisAlignedBB(minX.toDouble(), minY.toDouble(), minZ.toDouble(),
maxX + 1.0, maxY + 1.0, maxZ + 1.0)
gemstoneClusters.add(GemstoneCluster(clusterPositions, type, boundingBox))
}
}
}
@Deprecated("One time check is bad!")
fun locateCorpses(manualRun: Boolean) {
if (pos1 == null || pos2 == null) {
if (manualRun) {
Chatterbox.say(SimpleChatMsg("Bounds not set! Skipping locate corpses!").red())
}
return
}
val world = Minecraft.getMinecraft().theWorld
corpses.clear()
val minX = minOf(pos1!!.x, pos2!!.x)
val minY = minOf(pos1!!.y, pos2!!.y)
val minZ = minOf(pos1!!.z, pos2!!.z)
val maxX = maxOf(pos1!!.x, pos2!!.x)
val maxY = maxOf(pos1!!.y, pos2!!.y)
val maxZ = maxOf(pos1!!.z, pos2!!.z)
val armorStandsInBounds = world.loadedEntityList
.filterIsInstance<EntityArmorStand>()
.filter { stand ->
val x = stand.posX.toInt()
val y = stand.posY.toInt()
val z = stand.posZ.toInt()
x in minX..maxX && y in minY..maxY && z in minZ..maxZ
}
for (stand in armorStandsInBounds) {
for (i in 0..3) {
val item = try {
stand.getCurrentArmor(i)
} catch (e: Exception) {
null
}
}
val chestplate = try {
stand.getCurrentArmor(2)
} catch (e: Exception) {
// No chestplate so skip it
null
}
if (chestplate == null)
continue
val nbt = chestplate.tagCompound
val id = nbt?.getCompoundTag("ExtraAttributes")?.getString("id")?.uppercase()
val corpseType = when (id) {
"LAPIS_ARMOR_CHESTPLATE" -> CorpseType.LAPIS
"MINERAL_CHESTPLATE" -> CorpseType.TUNGSTEN
"ARMOR_OF_YOG_CHESTPLATE" -> CorpseType.UMBER
"VANGUARD_CHESTPLATE" -> CorpseType.VANGUARD
else -> {
Chatterbox.say("Unknown corpse ID: $id")
continue
}
}
corpses.add(Corpse(stand.posX.toInt() - 1, stand.posY.toInt() + 1, stand.posZ.toInt() - 1, corpseType))
}
}
fun startTrackingCorpses() {
corpseLoop?.cancel()
corpseLoop = LoopedFunction(40) {
try {
val tabCorpseMap = parseCorpseCounts()
val targetCount = tabCorpseMap.size
if (corpses.size >= targetCount) {
corpseLoop?.cancel()
} else {
locateCorpses(false)
}
} catch (e: Exception) {
e.printStackTrace()
corpseLoop?.cancel()
}
}
}
fun parseCorpseCounts(): Map<String, Boolean> {
val mc = Minecraft.getMinecraft()
val netHandler = mc.netHandler ?: return emptyMap()
val lines = netHandler.playerInfoMap
.mapNotNull { it.displayName?.unformattedText?.replace(Regex("§."), "")?.trim() }
.filter { it.isNotEmpty() }
val result = mutableMapOf<String, Boolean>()
val startIndex = lines.indexOfFirst { it.equals("Frozen Corpses:", ignoreCase = true) }
if (startIndex == -1) return result
for (i in startIndex + 1 until lines.size) {
val line = lines[i]
if (!line.contains(":")) break
val parts = line.split(":")
if (parts.size == 2) {
val corpseType = parts[0].trim().lowercase()
val status = parts[1].trim().uppercase()
result[corpseType] = status == "LOOTED"
}
}
return result
}
private fun searchMineshaft() {
if (lastMineshaftId == null) {
runSearch()
return
}
if (lastMineshaftId != getMiniIdFromTab()) {
reset()
runSearch()
return
}
}
fun runSearch() {
reset()
try {
lastMineshaftId = getMiniIdFromTab()
println("Setting mineshaft id to '$lastMineshaftId'")
locateBounds()
if (pos1 == null || pos2 == null) {
println("Aborting search — bounds not found.")
return
}
// locateCorpses()
startTrackingCorpses()
Chatterbox.say("Located ${corpses.size} corpses:")
corpses.forEach {
val msg = SimpleChatMsg("(${it.x}, ${it.y}, ${it.z})")
Chatterbox.say(colorizeMessage(msg, it.type))
}
locateGemstones()
populateGemstoneLocations()
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun colorizeMessage(msg: SimpleChatMsg, type: CorpseType): IChatComponent {
return when (type) {
CorpseType.LAPIS -> msg.blue()
CorpseType.TUNGSTEN -> msg.gray()
CorpseType.UMBER -> msg.red()
CorpseType.VANGUARD -> msg.blue()
}
}
@SubscribeEvent
fun onKeyInput(event: InputEvent.KeyInputEvent) {
if (Keybinds.openGui.isPressed) {
if (getAreaNameFromScoreboard()?.lowercase() != "mineshaft") {
Chatterbox.say(SimpleChatMsg("You are not in a mineshaft!").red())
Minecraft.getMinecraft().displayGuiScreen(MineshaftGui())
return
}
searchMineshaft()
Minecraft.getMinecraft().displayGuiScreen(MineshaftGui())
}
}
@Listen
fun onUIRender(event: RenderUIOverlayEvent) {
val mc = Minecraft.getMinecraft()
val player = mc.thePlayer
if (drawGemstones) {
val snapshot = gemstoneClusters.toList()
for (cluster in snapshot) {
BlockOutlineRenderer.drawBoundingBox(player, cluster.boundingBox, event.partialTicks, cluster.type.color)
}
}
if (drawCorpses) {
val snapshot = corpses.toList()
for (corpse in snapshot) {
val corpsePos = BlockPos(corpse.x, corpse.y, corpse.z)
BlockOutlineRenderer.drawBlockOutline(player, corpsePos, event.partialTicks, corpse.type.color)
}
}
if (!drawDebug) return
val p1 = pos1 ?: return
val p2 = pos2 ?: return
BlockOutlineRenderer.drawBlockOutline(player, p1, event.partialTicks, 0xFFFFFF)
BlockOutlineRenderer.drawBlockOutline(player, p2, event.partialTicks, 0x000000)
}
@SubscribeEvent
fun onWorldLoad(event: WorldEvent.Load) {
corpseLoop?.cancel()
reset()
}
}

View File

@ -1,120 +0,0 @@
package com.github.itzilly.sbt.features
import com.github.itzilly.sbt.Keybinds
import com.github.itzilly.sbt.data.NodeOptions
import com.github.itzilly.sbt.data.RouteNode
import com.github.itzilly.sbt.render.BlockOutlineRenderer
import com.github.itzilly.sbt.util.Chatterbox
import com.github.itzilly.sbt.util.SimpleChatMsg
import com.google.gson.Gson
import net.minecraft.client.Minecraft
import net.minecraft.util.BlockPos
import net.minecraftforge.client.event.RenderWorldLastEvent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.InputEvent
import java.awt.Toolkit
import java.awt.datatransfer.Clipboard
import java.awt.datatransfer.StringSelection
import kotlin.math.round
object RouteBuilder {
private const val OFFSET: Float = 0.5f;
private const val MAX_HISTORY = 5
private var nodes: ArrayList<RouteNode> = ArrayList()
private val history = ArrayDeque<List<RouteNode>>()
private fun nodeExists(x: Int, y: Int, z: Int): Boolean {
return nodes.any { it.x == x && it.y == y && it.z == z }
}
private fun addNode(x: Int, y: Int, z: Int) {
nodes.add(RouteNode(x, y, z, 0u, 1u, 0u, NodeOptions("${nodes.size + 1}")))
}
private fun addNode(x: Int, y: Int, z: Int, r: UByte, g: UByte, b: UByte) {
nodes.add(RouteNode(x, y, z, r, g, b, NodeOptions("${nodes.size + 1}")))
}
@SubscribeEvent
fun onKeyInput(event: InputEvent.KeyInputEvent) {
if (Keybinds.addRouteNode.isPressed) {
addRouteNode()
}
if (Keybinds.removeLastNode.isPressed) {
removeLastNode()
}
if (Keybinds.finishRoute.isPressed) {
finishRoute()
}
}
@SubscribeEvent
fun renderBlockOverlay(event: RenderWorldLastEvent) {
val player = Minecraft.getMinecraft().thePlayer
for (marker: RouteNode in nodes) {
val pos = BlockPos(marker.x, marker.y, marker.z)
BlockOutlineRenderer.drawBlockOutline(player, pos, event.partialTicks)
BlockOutlineRenderer.drawBlockLine(pos, event.partialTicks)
}
}
private fun addRouteNode() {
val mc = Minecraft.getMinecraft()
val x = round(mc.thePlayer.posX - OFFSET).toInt()
val y = round(mc.thePlayer.posY).toInt() - 1 // for the block below the player
val z = round(mc.thePlayer.posZ - OFFSET).toInt()
if (nodeExists(x, y, z)) {
Chatterbox.say(SimpleChatMsg("Node already exists!").red())
} else {
addNode(x, y, z)
}
}
private fun removeLastNode() {
val wasRemoved = nodes.removeLastOrNull()
if (wasRemoved == null) {
val msg = SimpleChatMsg("There isn't a node to delete!")
Chatterbox.say(msg.red())
} else {
val msg = SimpleChatMsg("Removed previous node")
Chatterbox.say(msg.green())
}
}
private fun finishRoute() {
if (nodes.size == 0) {
val msg = SimpleChatMsg("There aren't any nodes to copy!")
Chatterbox.say(msg.red())
return
}
// TODO: Make a config option to export to coleweight or the other mod (different format)
// Maybe skytils too??
saveRouteToHistory()
// TODO: Make a way to view the history in case you goof up
val jsonString = Gson().toJson(nodes)
val msg = SimpleChatMsg("String copied to clipboard!")
setClipboard(jsonString)
Chatterbox.say(msg.green())
nodes.clear()
}
private fun setClipboard(s: String) {
val selection = StringSelection(s)
val clipboard: Clipboard = Toolkit.getDefaultToolkit().systemClipboard
clipboard.setContents(selection, selection)
}
private fun saveRouteToHistory() {
history.addLast(nodes.map { it.copy() })
if (history.size > MAX_HISTORY) {
history.removeFirst()
}
}
}

View File

@ -1,85 +0,0 @@
package com.github.itzilly.sbt.gui
import com.github.itzilly.sbt.features.MineshaftHelper
import net.minecraft.client.gui.GuiButton
import net.minecraft.client.gui.GuiScreen
class MineshaftGui : GuiScreen() {
private var debugEnabled = MineshaftHelper.getDebugEnabled()
private var corpsesEnabled = MineshaftHelper.getCorpsesEnabled()
private var gemstonesEnabled = MineshaftHelper.getGemstonesEnabled()
override fun initGui() {
buttonList.clear()
val centerX = width / 2
val centerY = height / 2
buttonList.add(GuiButton(0, centerX - 100, centerY - 60, 200, 20, ""))
buttonList.add(GuiButton(1, centerX - 100, centerY - 30, 200, 20, ""))
buttonList.add(GuiButton(2, centerX - 100, centerY, 200, 20, ""))
buttonList.add(GuiButton(3, centerX - 100, centerY + 30, 200, 20, "Rescan"))
buttonList.add(GuiButton(4, centerX - 100, centerY + 60, 200, 20, "Check Bounds"))
buttonList.add(GuiButton(5, centerX - 100, centerY + 90, 200, 20, "Check Corpses"))
buttonList.add(GuiButton(6, centerX - 100, centerY + 120, 200, 20, "Check Gemstones"))
updateButtonLabels()
}
override fun actionPerformed(button: GuiButton) {
when (button.id) {
0 -> {
debugEnabled = !debugEnabled
MineshaftHelper.setDebugEnabled(debugEnabled)
}
1 -> {
corpsesEnabled = !corpsesEnabled
MineshaftHelper.setCorpsesEnabled(corpsesEnabled)
}
2 -> {
gemstonesEnabled = !gemstonesEnabled
MineshaftHelper.setGemstonesEnabled(gemstonesEnabled)
}
3 -> MineshaftHelper.runSearch()
4 -> MineshaftHelper.locateBounds()
5 -> MineshaftHelper.locateCorpses(true)
6 -> {
MineshaftHelper.locateGemstones()
MineshaftHelper.populateGemstoneLocations()
}
}
updateButtonLabels()
}
private fun updateButtonLabels() {
debugEnabled = MineshaftHelper.getDebugEnabled()
corpsesEnabled = MineshaftHelper.getCorpsesEnabled()
gemstonesEnabled = MineshaftHelper.getGemstonesEnabled()
buttonList.filterIsInstance<GuiButton>().forEach { button ->
when (button.id) {
0 -> button.displayString = getColoredLabel("Toggle Debug", debugEnabled)
1 -> button.displayString = getColoredLabel("Toggle Corpses", corpsesEnabled)
2 -> button.displayString = getColoredLabel("Toggle Gemstones", gemstonesEnabled)
}
}
}
private fun getColoredLabel(base: String, state: Boolean): String {
val color = if (state) "\u00A7a" else "\u00A7c"
return "$color$base"
}
override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) {
drawDefaultBackground()
super.drawScreen(mouseX, mouseY, partialTicks)
drawCenteredString(fontRendererObj, "Mineshaft Tools", width / 2, height / 2 - 90, 0xFFFFFF)
}
override fun doesGuiPauseGame(): Boolean = false
}

View File

@ -1,12 +0,0 @@
package com.github.itzilly.sbt.gui
import net.minecraft.client.gui.GuiScreen
class SBTConfigGui : GuiScreen() {
override fun initGui() {}
override fun doesGuiPauseGame(): Boolean = false
override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) {
drawDefaultBackground()
super.drawScreen(mouseX, mouseY, partialTicks)
}
}

View File

@ -0,0 +1,16 @@
package com.github.itzilly.sbt.mixin;
import net.minecraft.client.gui.GuiMainMenu;
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(GuiMainMenu.class)
public class MixinGuiMainMenu {
@Inject(method = "initGui", at = @At("HEAD"))
public void onInitGui(CallbackInfo ci) {
// System.out.println("Hello from Main Menu!");
}
}

View File

@ -1,27 +0,0 @@
package com.github.itzilly.sbt.mixin
import com.github.itzilly.sbt.events.custom.ClientBlockBreakEvent
import net.minecraft.client.Minecraft
import net.minecraft.client.multiplayer.PlayerControllerMP
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraftforge.common.MinecraftForge
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.CallbackInfoReturnable
@Mixin(PlayerControllerMP::class)
class MixinPlayerControllerMP {
@Inject(method = ["onPlayerDestroyBlock"], at = [At("HEAD")])
fun onPlayerDestroyBlock(
pos: BlockPos,
side: EnumFacing,
cir: CallbackInfoReturnable<Boolean>
) {
val block = Minecraft.getMinecraft().theWorld.getBlockState(pos).block
val player = Minecraft.getMinecraft().thePlayer
MinecraftForge.EVENT_BUS.post(ClientBlockBreakEvent(pos, block, player))
}
}

View File

@ -1,213 +0,0 @@
package com.github.itzilly.sbt.render
import com.github.itzilly.sbt.data.Vec3d
import com.github.itzilly.sbt.render.RenderPrimitives.drawBlock
import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.entity.Entity
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import org.lwjgl.opengl.GL11
import java.awt.Color
object BlockOutlineRenderer {
fun drawBlockOutline(entity: Entity, blockPos: BlockPos, partialTicks: Float, outlineColor: Int) {
val padding = 0.0020000000949949026 // Magic number DO NOT TOUCH
val entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
val entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
val entityZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks
val world = Minecraft.getMinecraft().theWorld
val blockState = world.getBlockState(blockPos)
val block = blockState.block
val boundingBox = block.getCollisionBoundingBox(world, blockPos, blockState)
?: AxisAlignedBB(
blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(),
blockPos.x + 1.0, blockPos.y + 1.0, blockPos.z + 1.0
).expand(padding, padding, padding)
val r = (outlineColor shr 16 and 0xFF) / 255.0f
val g = (outlineColor shr 8 and 0xFF) / 255.0f
val b = (outlineColor and 0xFF) / 255.0f
val a = (outlineColor shr 24 and 0xFF) / 255.0f
GL11.glPushMatrix()
GlStateManager.disableTexture2D()
GlStateManager.depthMask(false)
GlStateManager.disableDepth()
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
GL11.glEnable(GL11.GL_LINE_SMOOTH)
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
GL11.glLineWidth(2.0f)
GL11.glColor4f(r, g, b, a)
RenderPrimitives.drawBlock(boundingBox.offset(-entityX, -entityY, -entityZ), outlineColor, outlineColor)
GL11.glDisable(GL11.GL_LINE_SMOOTH)
GL11.glDisable(GL11.GL_BLEND)
GlStateManager.enableDepth()
GlStateManager.depthMask(true)
GlStateManager.enableAlpha()
GlStateManager.enableTexture2D()
GL11.glPopMatrix()
}
fun drawBlockOutline(entity: Entity, blockPos: BlockPos, partialTicks: Float) {
val padding: Double = 0.0020000000949949026
val entityX: Double = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
val entityY: Double = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
val entityZ: Double = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks
val outlineStartColor = 0xFFFFFF
val outlineEndColor = 0xFFFFFF
val world = Minecraft.getMinecraft().theWorld
val blockState = world.getBlockState(blockPos)
val block: Block = blockState.block
val boundingBox: AxisAlignedBB = block.getCollisionBoundingBox(world, blockPos, blockState)
?: AxisAlignedBB(
blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(),
blockPos.x + 1.0, blockPos.y + 1.0, blockPos.z + 1.0
).expand(padding, padding, padding)
GL11.glPushMatrix()
GlStateManager.disableTexture2D()
GlStateManager.depthMask(false)
GlStateManager.disableDepth()
GL11.glEnable(GL11.GL_LINE_SMOOTH)
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
GL11.glLineWidth(2.0f)
GL11.glShadeModel(GL11.GL_SMOOTH)
RenderPrimitives.drawBlock(boundingBox.offset(-entityX, -entityY, -entityZ), outlineStartColor, outlineEndColor)
GL11.glLineWidth(2.0f)
GL11.glDisable(GL11.GL_LINE_SMOOTH)
GlStateManager.enableDepth()
GlStateManager.depthMask(true)
GlStateManager.enableAlpha()
GlStateManager.enableTexture2D()
GL11.glPopMatrix()
}
fun drawBlockLine(pos: BlockPos, partialTicks: Float) {
val render = Minecraft.getMinecraft().renderViewEntity
val rm = Minecraft.getMinecraft().renderManager
// TODO: Fix this not working with view bobbing enabled
val pos1 = Vec3d(rm.viewerPosX, rm.viewerPosY + render.eyeHeight, rm.viewerPosZ)
val pos2 = Vec3d(
pos.x.toDouble() + 0.5, // Center of the block
pos.y.toDouble() + 0.5, // Center of the block
pos.z.toDouble() + 0.5 // Center of the block
)
val lineColor = Color(0xe310d5)
RenderPrimitives.drawLine(pos1, pos2, lineColor, 2, false, partialTicks)
}
fun drawClusterOutline(entity: Entity, positions: List<BlockPos>, partialTicks: Float, outlineColor: Int) {
val padding = 0.0020000000949949026 // Magic number DO NOT TOUCH
val entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
val entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
val entityZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks
val world = Minecraft.getMinecraft().theWorld
GL11.glPushMatrix()
GlStateManager.disableTexture2D()
GlStateManager.depthMask(false)
GlStateManager.disableDepth()
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
GL11.glEnable(GL11.GL_LINE_SMOOTH)
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
GL11.glLineWidth(2.0f)
val r = (outlineColor shr 16 and 0xFF) / 255.0f
val g = (outlineColor shr 8 and 0xFF) / 255.0f
val b = (outlineColor and 0xFF) / 255.0f
val a = (outlineColor shr 24 and 0xFF) / 255.0f
GL11.glColor4f(r, g, b, a)
for (pos in positions) {
val blockState = world.getBlockState(pos)
val boundingBox = blockState.block.getCollisionBoundingBox(world, pos, blockState)
?: AxisAlignedBB(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), pos.x + 1.0, pos.y + 1.0, pos.z + 1.0).expand(padding, padding, padding)
val offsetBoundingBox = boundingBox.offset(-entityX, -entityY, -entityZ)
// Only draw exposed faces
if (!positions.contains(pos.add(1, 0, 0))) {
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.EAST, outlineColor)
}
if (!positions.contains(pos.add(-1, 0, 0))) {
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.WEST, outlineColor)
}
if (!positions.contains(pos.add(0, 1, 0))) {
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.UP, outlineColor)
}
if (!positions.contains(pos.add(0, -1, 0))) {
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.DOWN, outlineColor)
}
if (!positions.contains(pos.add(0, 0, 1))) {
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.SOUTH, outlineColor)
}
if (!positions.contains(pos.add(0, 0, -1))) {
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.NORTH, outlineColor)
}
}
GL11.glDisable(GL11.GL_LINE_SMOOTH)
GL11.glDisable(GL11.GL_BLEND)
GlStateManager.enableDepth()
GlStateManager.depthMask(true)
GlStateManager.enableAlpha()
GlStateManager.enableTexture2D()
GL11.glPopMatrix()
}
fun drawBoundingBox(player: Entity, box: AxisAlignedBB, partialTicks: Float, color: Int) {
val entityX = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks
val entityY = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks
val entityZ = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks
val offsetBox = box.offset(-entityX, -entityY, -entityZ)
val r = (color shr 16 and 0xFF) / 255.0f
val g = (color shr 8 and 0xFF) / 255.0f
val b = (color and 0xFF) / 255.0f
val a = (color shr 24 and 0xFF) / 255.0f
GL11.glPushMatrix()
GlStateManager.disableTexture2D()
GlStateManager.depthMask(false)
GlStateManager.disableDepth()
GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
GL11.glEnable(GL11.GL_LINE_SMOOTH)
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
GL11.glLineWidth(2.0f)
GL11.glColor4f(r, g, b, a)
drawBlock(offsetBox, color, color)
GL11.glDisable(GL11.GL_LINE_SMOOTH)
GL11.glDisable(GL11.GL_BLEND)
GlStateManager.enableDepth()
GlStateManager.depthMask(true)
GlStateManager.enableAlpha()
GlStateManager.enableTexture2D()
GL11.glPopMatrix()
}
}

View File

@ -1,318 +0,0 @@
package com.github.itzilly.sbt.render
import com.github.itzilly.sbt.data.Vec3d
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.util.AxisAlignedBB
import net.minecraft.util.EnumFacing
import org.lwjgl.opengl.GL11
import java.awt.Color
object RenderPrimitives {
var TESSELLATOR: Tessellator = Tessellator.getInstance()
var WORLD_RENDERER: WorldRenderer = Tessellator.getInstance().worldRenderer
fun drawBlock(box: AxisAlignedBB, outlineStartColor: Int, outlineEndColor: Int) {
drawBlockTop(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockBottom(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockNorth(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockEast(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockSouth(box, Color(outlineStartColor), Color(outlineEndColor));
drawBlockWest(box, Color(outlineStartColor), Color(outlineEndColor));
}
private fun drawBlockTop(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockBottom(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockNorth(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockEast(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockSouth(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
private fun drawBlockWest(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color) {
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
fun drawLine(p1: Vec3d, p2: Vec3d, color: Color, lineWidth: Int, depth: Boolean, partialTicks: Float) {
GlStateManager.disableCull()
val render = Minecraft.getMinecraft().renderViewEntity
val worldRenderer = TESSELLATOR.worldRenderer
val realX = render.lastTickPosX + (render.posX - render.lastTickPosX) * partialTicks
val realY = render.lastTickPosY + (render.posY - render.lastTickPosY) * partialTicks
val realZ = render.lastTickPosZ + (render.posZ - render.lastTickPosZ) * partialTicks
GlStateManager.pushMatrix()
GlStateManager.translate(-realX, -realY, -realZ)
GlStateManager.disableTexture2D()
GlStateManager.enableBlend()
GlStateManager.disableAlpha()
GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0)
GL11.glLineWidth(lineWidth.toFloat())
if (!depth) {
GL11.glDisable(GL11.GL_DEPTH_TEST)
GlStateManager.depthMask(false)
}
GlStateManager.color(color.red / 255f, color.green / 255f, color.blue / 255f, color.alpha / 255f)
worldRenderer.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION)
worldRenderer.pos(p1.x, p1.y, p1.z).endVertex()
worldRenderer.pos(p2.x, p2.y, p2.z).endVertex()
Tessellator.getInstance().draw()
GlStateManager.translate(realX, realY, realZ)
if (!depth) {
GL11.glEnable(GL11.GL_DEPTH_TEST)
GlStateManager.depthMask(true)
}
GlStateManager.disableBlend()
GlStateManager.enableAlpha()
GlStateManager.enableTexture2D()
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f)
GlStateManager.popMatrix()
GlStateManager.disableLighting()
GlStateManager.enableCull()
}
fun drawAnimatedBlockTop(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color, time: Float) {
val offsetY = Math.sin(time.toDouble()).toFloat() * (box.maxY - box.minY) / 2.0f
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY + offsetY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY + offsetY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY + offsetY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY + offsetY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
fun drawAnimatedBlockBottom(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color, time: Float) {
val offsetY = Math.sin(time.toDouble()).toFloat() * (box.maxY - box.minY) / 2.0f
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.minY + offsetY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY + offsetY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY + offsetY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY + offsetY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
fun drawAnimatedBlockNorth(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color, time: Float) {
val offsetY = Math.sin(time.toDouble()).toFloat() * (box.maxY - box.minY) / 2.0f
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.maxY + offsetY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY + offsetY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY + offsetY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY + offsetY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
fun drawAnimatedBlockEast(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color, time: Float) {
val offsetY = Math.sin(time.toDouble()).toFloat() * (box.maxY - box.minY) / 2.0f
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.maxX, box.maxY + offsetY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY + offsetY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY + offsetY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY + offsetY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
fun drawAnimatedBlockSouth(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color, time: Float) {
val offsetY = Math.sin(time.toDouble()).toFloat() * (box.maxY - box.minY) / 2.0f
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY + offsetY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY + offsetY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY + offsetY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY + offsetY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
fun drawAnimatedBlockWest(box: AxisAlignedBB, outlineStartColor: Color, outlineEndColor: Color, time: Float) {
val offsetY = Math.sin(time.toDouble()).toFloat() * (box.maxY - box.minY) / 2.0f
WORLD_RENDERER.begin(2, DefaultVertexFormats.POSITION_COLOR)
WORLD_RENDERER.pos(box.minX, box.maxY + offsetY, box.minZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY + offsetY, box.maxZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY + offsetY, box.maxZ)
.color(outlineStartColor.red, outlineStartColor.green, outlineStartColor.blue, outlineStartColor.alpha)
.endVertex()
WORLD_RENDERER.pos(box.minX, box.minY + offsetY, box.minZ)
.color(outlineEndColor.red, outlineEndColor.green, outlineEndColor.blue, outlineEndColor.alpha).endVertex()
TESSELLATOR.draw()
}
fun drawBlockFace(box: AxisAlignedBB, face: EnumFacing, color: Int) {
WORLD_RENDERER.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION_COLOR)
val r = (color shr 16 and 0xFF) / 255.0f
val g = (color shr 8 and 0xFF) / 255.0f
val b = (color and 0xFF) / 255.0f
val a = (color shr 24 and 0xFF) / 255.0f
GL11.glColor4f(r, g, b, a)
when (face) {
EnumFacing.UP -> {
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ).endVertex()
}
EnumFacing.DOWN -> {
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ).endVertex()
}
EnumFacing.NORTH -> {
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ).endVertex()
}
EnumFacing.SOUTH -> {
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ).endVertex()
}
EnumFacing.WEST -> {
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.maxY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.minX, box.minY, box.minZ).endVertex()
}
EnumFacing.EAST -> {
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.maxZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.maxY, box.minZ).endVertex()
WORLD_RENDERER.pos(box.maxX, box.minY, box.minZ).endVertex()
}
else -> {}
}
TESSELLATOR.draw()
}
}

View File

@ -1,41 +0,0 @@
package com.github.itzilly.sbt.util
import net.minecraft.client.Minecraft
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.util.ChatComponentText
import net.minecraft.util.ChatStyle
import net.minecraft.util.EnumChatFormatting
import net.minecraft.util.IChatComponent
object Chatterbox {
private const val prefixString = "[SBT] "
private val prefixColorStyle = ChatStyle().setColor(EnumChatFormatting.AQUA)
private val prefixComponent = ChatComponentText(prefixString).setChatStyle(prefixColorStyle)
private val player = Minecraft.getMinecraft().thePlayer
private fun copy(component: IChatComponent): IChatComponent {
val newComponent = ChatComponentText(component.unformattedTextForChat)
newComponent.chatStyle = component.chatStyle.createShallowCopy()
component.siblings.forEach { sibling ->
newComponent.appendSibling(copy(sibling))
}
return newComponent
}
fun say(msg: String) {
val messageComponent = ChatComponentText(msg).setChatStyle(ChatStyle().setColor(EnumChatFormatting.RESET))
player.addChatMessage(prefixComponent.createCopy().appendSibling(messageComponent))
}
fun say(component: ChatComponentText) {
player.addChatMessage(copy(prefixComponent).appendSibling(copy(component)))
}
fun say(component: IChatComponent) {
player.addChatMessage(copy(prefixComponent).appendSibling(copy(component)))
}
fun say(player: EntityPlayer, component: IChatComponent) {
player.addChatMessage(copy(prefixComponent).appendSibling(copy(component)))
}
}

View File

@ -1,25 +0,0 @@
package com.github.itzilly.sbt.util
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
class DelayedFunction(private val function: () -> Unit, private val delayTicks: Int) {
private var ticksLeft: Int = delayTicks
init {
MinecraftForge.EVENT_BUS.register(this)
}
@SubscribeEvent
fun onClientTick(event: TickEvent.ClientTickEvent) {
if (ticksLeft > 0) {
ticksLeft--
if (ticksLeft == 0) {
function()
MinecraftForge.EVENT_BUS.unregister(this)
}
}
}
}

View File

@ -1,26 +0,0 @@
package com.github.itzilly.sbt.util
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiScreen
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
object GuiOpener {
private var set: Boolean = false
private var screen: GuiScreen? = null
fun ScheduleGui(screen: GuiScreen) {
set = true
this.screen = screen
}
@SubscribeEvent
fun onClientTick(event: TickEvent.ClientTickEvent) {
if (set) {
Minecraft.getMinecraft().addScheduledTask {
Minecraft.getMinecraft().displayGuiScreen(screen)
}
set = false
screen = null
}
}
}

View File

@ -1,37 +0,0 @@
package com.github.itzilly.sbt.util
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
import java.util.concurrent.atomic.AtomicBoolean
class LoopedFunction(
private val intervalTicks: Int,
private val function: () -> Unit
) {
private var tickCounter = 0
private val active = AtomicBoolean(true)
init {
require(intervalTicks > 0) { "Interval must be greater than 0" }
MinecraftForge.EVENT_BUS.register(this)
}
@SubscribeEvent
fun onClientTick(event: TickEvent.ClientTickEvent) {
if (!active.get() || event.phase != TickEvent.Phase.END) return
tickCounter++
if (tickCounter >= intervalTicks) {
function()
tickCounter = 0
}
}
fun cancel() {
if (active.getAndSet(false)) {
MinecraftForge.EVENT_BUS.unregister(this)
}
}
}

View File

@ -1,22 +0,0 @@
package com.github.itzilly.sbt.util
import net.minecraft.util.IChatComponent
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent
object MessageScheduler {
private val components: MutableList<IChatComponent> = mutableListOf()
@SubscribeEvent
fun onPlayerLoggedIn(event: PlayerLoggedInEvent) {
val player = event.player
for (component in components) {
Chatterbox.say(player, component)
}
components.clear() // Clear the list after sending the messages
}
fun sayWhenReady(component: IChatComponent) {
components.add(component)
}
}

View File

@ -1,146 +0,0 @@
package com.github.itzilly.sbt.util
import net.minecraft.util.ChatComponentText
import net.minecraft.util.ChatStyle
import net.minecraft.util.EnumChatFormatting.BLACK
import net.minecraft.util.EnumChatFormatting.DARK_BLUE
import net.minecraft.util.EnumChatFormatting.DARK_GREEN
import net.minecraft.util.EnumChatFormatting.DARK_AQUA
import net.minecraft.util.EnumChatFormatting.DARK_RED
import net.minecraft.util.EnumChatFormatting.DARK_PURPLE
import net.minecraft.util.EnumChatFormatting.GOLD
import net.minecraft.util.EnumChatFormatting.GRAY
import net.minecraft.util.EnumChatFormatting.DARK_GRAY
import net.minecraft.util.EnumChatFormatting.BLUE
import net.minecraft.util.EnumChatFormatting.GREEN
import net.minecraft.util.EnumChatFormatting.AQUA
import net.minecraft.util.EnumChatFormatting.RED
import net.minecraft.util.EnumChatFormatting.LIGHT_PURPLE
import net.minecraft.util.EnumChatFormatting.YELLOW
import net.minecraft.util.EnumChatFormatting.WHITE
import net.minecraft.util.EnumChatFormatting.OBFUSCATED
import net.minecraft.util.EnumChatFormatting.BOLD
import net.minecraft.util.EnumChatFormatting.STRIKETHROUGH
import net.minecraft.util.EnumChatFormatting.UNDERLINE
import net.minecraft.util.EnumChatFormatting.ITALIC
import net.minecraft.util.EnumChatFormatting.RESET
import net.minecraft.util.IChatComponent
class SimpleChatMsg(msg: String) {
private var component: IChatComponent
init {
component = ChatComponentText(msg)
}
fun default(): IChatComponent {
component.chatStyle = ChatStyle().setColor(RESET)
return component
}
fun black(): IChatComponent {
component.chatStyle = ChatStyle().setColor(BLACK)
return component
}
fun dark_blue(): IChatComponent {
component.chatStyle = ChatStyle().setColor(DARK_BLUE)
return component
}
fun dark_green(): IChatComponent {
component.chatStyle = ChatStyle().setColor(DARK_GREEN)
return component
}
fun dark_aqua(): IChatComponent {
component.chatStyle = ChatStyle().setColor(DARK_AQUA)
return component
}
fun dark_red(): IChatComponent {
component.chatStyle = ChatStyle().setColor(DARK_RED)
return component
}
fun dark_purple(): IChatComponent {
component.chatStyle = ChatStyle().setColor(DARK_PURPLE)
return component
}
fun gold(): IChatComponent {
component.chatStyle = ChatStyle().setColor(GOLD)
return component
}
fun gray(): IChatComponent {
component.chatStyle = ChatStyle().setColor(GRAY)
return component
}
fun dark_gray(): IChatComponent {
component.chatStyle = ChatStyle().setColor(DARK_GRAY)
return component
}
fun blue(): IChatComponent {
component.chatStyle = ChatStyle().setColor(BLUE)
return component
}
fun green(): IChatComponent {
component.chatStyle = ChatStyle().setColor(GREEN)
return component
}
fun aqua(): IChatComponent {
component.chatStyle = ChatStyle().setColor(AQUA)
return component
}
fun red(): IChatComponent {
component.chatStyle = ChatStyle().setColor(RED)
return component
}
fun light_purple(): IChatComponent {
component.chatStyle = ChatStyle().setColor(LIGHT_PURPLE)
return component
}
fun yellow(): IChatComponent {
component.chatStyle = ChatStyle().setColor(YELLOW)
return component
}
fun white(): IChatComponent {
component.chatStyle = ChatStyle().setColor(WHITE)
return component
}
fun obfuscated(): IChatComponent {
component.chatStyle = ChatStyle().setColor(OBFUSCATED)
return component
}
fun bold(): IChatComponent {
component.chatStyle = ChatStyle().setColor(BOLD)
return component
}
fun strikethrough(): IChatComponent {
component.chatStyle = ChatStyle().setColor(STRIKETHROUGH)
return component
}
fun underline(): IChatComponent {
component.chatStyle = ChatStyle().setColor(UNDERLINE)
return component
}
fun italic(): IChatComponent {
component.chatStyle = ChatStyle().setColor(ITALIC)
return component
}
}

View File

@ -1,32 +0,0 @@
package com.github.itzilly.sbt.util
import net.minecraft.client.Minecraft
fun getAreaNameFromScoreboard(): String? {
val mc = Minecraft.getMinecraft()
val netHandler = mc.netHandler ?: return null
for (info in netHandler.playerInfoMap) {
val line = info.displayName?.unformattedText?.replace(Regex("§."), "")?.trim() ?: continue
if (line.startsWith("Area: ")) {
val area = line.removePrefix("Area: ").trim()
return area
}
}
return null
}
fun getMiniIdFromTab(): String? {
val mc = Minecraft.getMinecraft()
val netHandler = mc.netHandler ?: return null
for (info in netHandler.playerInfoMap) {
val line = info.displayName?.unformattedText?.replace(Regex("§."), "")?.trim() ?: continue
if (line.startsWith("Server: ")) {
val id = line.removePrefix("Server: ").trim()
return id
}
}
return null
}

View File

@ -1,4 +0,0 @@
package com.github.itzilly.sbt.util
data class Vec3d(val x:Double, val y:Double, val z:Double)
data class Vec3f(val x:Float, val y:Float, val z:Float)

View File

@ -1,7 +1,6 @@
key.searchGrotto=Search Grotto
key.clearGrotto=Clear Grotto
key.addRouteNode=Add Route Node
key.removeLastNode=Remove Last Node
key.finishRoute=Finish Route
key.categories.sbt=SkyBlock Tweaks
key.categories.sbt=SkyBlock Tweaks
key.addWaypoint=Add Route Point
key.finishWaypoints=Finish Route
key.clearWaypoints=Clear Route Points
key.openRoutesGui=Open Route GUI
key.xrayToggle=Toggle ChestESP

View File

@ -0,0 +1,3 @@
test
from resource pack

View File

@ -1,17 +1,16 @@
[
{
"modid": "${modid}",
"name": "SkyBlockTweaks",
"description": "Small tweaks and hud displays for Hypixel Skyblock",
"name": "Xample Mod",
"description": "A mod that is used as an example.",
"version": "${version}",
"mcversion": "${mcversion}",
"url": "http://itzilly.com/illyum/SkyBlockTweaks",
"url": "https://github.com/romangraef/Forge1.8.9Template/",
"updateUrl": "",
"authorList": [
"itzilly",
"illyum"
"You"
],
"credits": "Special thanks to Kakazo for contributing feature ideas, testing, and for just using this mod throughout development!",
"credits": "",
"logoFile": "",
"screenshots": [],
"dependencies": []