Compare commits
2 Commits
master
...
rewrite-pr
Author | SHA1 | Date | |
---|---|---|---|
2946914101 | |||
09ed358681 |
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,10 +0,0 @@
|
|||||||
## [1.4.0] - 2024-07-23
|
|
||||||
|
|
||||||
### Chore
|
|
||||||
|
|
||||||
- Remove comments
|
|
||||||
|
|
||||||
### Feat
|
|
||||||
|
|
||||||
- *(chestesp)* Add initial implementation, halfway done
|
|
||||||
|
|
16
README.md
16
README.md
@ -2,15 +2,7 @@
|
|||||||
|
|
||||||
My QOL mod for Hypixel Skyblock
|
My QOL mod for Hypixel Skyblock
|
||||||
|
|
||||||
## Includes:
|
## TODO (Asin these WILL be implemented):
|
||||||
- Grotto Finder
|
- Add route builder history GUI/Command or something
|
||||||
- Gemstone Finder
|
- Make Route Builder export to Skytils/CrystalHollowWaypoints/Coleweight
|
||||||
- Powder ChestESP
|
- Optimize Block Outline Rendering
|
||||||
- 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]
|
|
@ -18,7 +18,7 @@ val modid: String by project
|
|||||||
val mixinGroup = "$baseGroup.mixin"
|
val mixinGroup = "$baseGroup.mixin"
|
||||||
|
|
||||||
group = baseGroup
|
group = baseGroup
|
||||||
version = "$versionBase-b$buildNumber"
|
version = "alpha_$versionBase-b$buildNumber"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
|
||||||
@ -140,31 +140,6 @@ tasks.assemble {
|
|||||||
dependsOn("incrementBuildNumber")
|
dependsOn("incrementBuildNumber")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Copy>("illyExtractMappings") {
|
|
||||||
from("O:/.gradle")
|
|
||||||
into("${layout.buildDirectory}/mcp_mappings")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("illyApplyMappings") {
|
|
||||||
dependsOn("illyExtractMappings")
|
|
||||||
doLast {
|
|
||||||
val mappingsDir = file("O:/Kotlin Programming/sbt/build/mcp_mappings")
|
|
||||||
if (mappingsDir.exists()) {
|
|
||||||
project.ext.set("mappingsPath", mappingsDir.absolutePath)
|
|
||||||
} else {
|
|
||||||
throw GradleException("Mappings directory not found!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType<JavaCompile> {
|
|
||||||
dependsOn("illyApplyMappings")
|
|
||||||
doLast {
|
|
||||||
options.compilerArgs.add("-Amap=O:/Kotlin Programming/sbt/build/mcp_mappings")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 🔁 Auto-increment build number each assemble
|
|
||||||
tasks.register("incrementBuildNumber") {
|
tasks.register("incrementBuildNumber") {
|
||||||
doLast {
|
doLast {
|
||||||
val propsFile = file("gradle.properties")
|
val propsFile = file("gradle.properties")
|
||||||
|
36
cliff.toml
36
cliff.toml
@ -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
|
|
131
docs/CLIENT_COMMAND_BUILDER.md
Normal file
131
docs/CLIENT_COMMAND_BUILDER.md
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# 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>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -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.
|
|
@ -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!
|
|
@ -1,8 +1,8 @@
|
|||||||
#Sat Apr 19 14:54:37 MDT 2025
|
#Tue Apr 22 09:20:13 MDT 2025
|
||||||
versionBase=1.5.0
|
versionBase=2.0.0
|
||||||
loom.platform=forge
|
loom.platform=forge
|
||||||
baseGroup=com.github.itzilly.sbt
|
baseGroup=com.github.itzilly.sbt
|
||||||
mcVersion=1.8.9
|
mcVersion=1.8.9
|
||||||
org.gradle.jvmargs=-Xmx2g
|
org.gradle.jvmargs=-Xmx2g
|
||||||
buildNumber=107
|
buildNumber=214
|
||||||
modid=sbt
|
modid=sbt
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
@ -1,48 +0,0 @@
|
|||||||
package com.github.itzilly.sbt
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.features.ChestEsp
|
|
||||||
import com.github.itzilly.sbt.features.GemstoneFinder
|
|
||||||
import com.github.itzilly.sbt.features.GrottoFinder
|
|
||||||
import com.github.itzilly.sbt.util.Chatterbox
|
|
||||||
import com.github.itzilly.sbt.util.SimpleChatMsg
|
|
||||||
import net.minecraft.client.Minecraft
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import net.minecraftforge.fml.common.gameevent.InputEvent
|
|
||||||
|
|
||||||
class InputHandler {
|
|
||||||
@SubscribeEvent
|
|
||||||
fun onKeyInput(event: InputEvent.KeyInputEvent?) {
|
|
||||||
if (STBKeyBinds.searchForChests.isPressed) {
|
|
||||||
ChestEsp.highlightChests()
|
|
||||||
}
|
|
||||||
if (STBKeyBinds.clearChests.isPressed) {
|
|
||||||
ChestEsp.chestList.clear()
|
|
||||||
Chatterbox.say(SimpleChatMsg("Chests cleared").green())
|
|
||||||
}
|
|
||||||
if (STBKeyBinds.toggleGrottoFinder.isPressed) {
|
|
||||||
Chatterbox.say("Running check...")
|
|
||||||
GrottoFinder.checkWorldForMagentaStainedGlass(Minecraft.getMinecraft().thePlayer.worldObj)
|
|
||||||
Chatterbox.say("Check done")
|
|
||||||
// if (GrottoFinder.isEnabled) {
|
|
||||||
// GrottoFinder.isEnabled = false
|
|
||||||
// Chatterbox.say(SimpleChatMsg("Grotto finder disabled!").red())
|
|
||||||
// MinecraftForge.EVENT_BUS.register(GrottoFinder)
|
|
||||||
// } else {
|
|
||||||
// GrottoFinder.isEnabled = true
|
|
||||||
// Chatterbox.say(SimpleChatMsg("Grotto finder enabled!").green())
|
|
||||||
// // MinecraftForge.EVENT_BUS.unregister(GrottoFinder)
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
if (STBKeyBinds.clearGrotto.isPressed) {
|
|
||||||
GrottoFinder.clear()
|
|
||||||
Chatterbox.say("Cleared grotto finder")
|
|
||||||
}
|
|
||||||
if (STBKeyBinds.findGemstones.isPressed) {
|
|
||||||
GemstoneFinder.find()
|
|
||||||
}
|
|
||||||
if (STBKeyBinds.clearGemstones.isPressed) {
|
|
||||||
GemstoneFinder.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
26
src/main/kotlin/com/github/itzilly/sbt/Keybinds.kt
Normal file
26
src/main/kotlin/com/github/itzilly/sbt/Keybinds.kt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
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")
|
||||||
|
|
||||||
|
fun register() {
|
||||||
|
ClientRegistry.registerKeyBinding(searchGrotto)
|
||||||
|
ClientRegistry.registerKeyBinding(clearGrotto)
|
||||||
|
|
||||||
|
ClientRegistry.registerKeyBinding(addRouteNode)
|
||||||
|
ClientRegistry.registerKeyBinding(removeLastNode)
|
||||||
|
ClientRegistry.registerKeyBinding(finishRoute)
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
package com.github.itzilly.sbt
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.features.ChestEsp
|
|
||||||
import com.github.itzilly.sbt.features.GemstoneFinder
|
|
||||||
import net.minecraft.command.CommandBase
|
|
||||||
import net.minecraft.command.CommandException
|
|
||||||
import net.minecraft.command.ICommandSender
|
|
||||||
import net.minecraft.util.ChatComponentText
|
|
||||||
import net.minecraftforge.common.config.Configuration.*
|
|
||||||
|
|
||||||
|
|
||||||
class SBTCommand : CommandBase() {
|
|
||||||
|
|
||||||
override fun getCommandName(): String {
|
|
||||||
return "sbt"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCommandUsage(sender: ICommandSender): String {
|
|
||||||
return "/sbt <powderchests/gemstonesearchradius> [enable/disable/radius]"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getRequiredPermissionLevel(): Int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(CommandException::class)
|
|
||||||
override fun processCommand(sender: ICommandSender, args: Array<String>) {
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
sender.addChatMessage(ChatComponentText("Invalid command. Usage: /sbt <powderchests/gemstonesearchradius> [enable/disable/radius]"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
when (args[0].lowercase()) {
|
|
||||||
"powderchests" -> {
|
|
||||||
if (args.size < 2) {
|
|
||||||
sender.addChatMessage(ChatComponentText("Usage: /sbt powderchests <enable/disable>"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
when (args[1].lowercase()) {
|
|
||||||
"enable" -> {
|
|
||||||
ChestEsp.enabled = true
|
|
||||||
SkyBlockTweaks.config.getCategory(CATEGORY_GENERAL)?.get("powderchestenable")?.set(true)
|
|
||||||
SkyBlockTweaks.config.save()
|
|
||||||
sender.addChatMessage(ChatComponentText("Powder ChestESP enabled."))
|
|
||||||
}
|
|
||||||
"disable" -> {
|
|
||||||
ChestEsp.enabled = false
|
|
||||||
SkyBlockTweaks.config.getCategory(CATEGORY_GENERAL)?.get("powderchestenable")?.set(false)
|
|
||||||
SkyBlockTweaks.config.save()
|
|
||||||
sender.addChatMessage(ChatComponentText("Powder ChestESP disabled."))
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
sender.addChatMessage(ChatComponentText("Invalid option. Usage: /sbt powderchests <enable/disable>"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"gemstonesearchradius" -> {
|
|
||||||
if (args.size < 2) {
|
|
||||||
sender.addChatMessage(ChatComponentText("Usage: /sbt gemstonesearchradius <radius>"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
val radius = args[1].toInt()
|
|
||||||
|
|
||||||
if (radius < 0) {
|
|
||||||
sender.addChatMessage(ChatComponentText("Radius must be a positive integer."))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
SkyBlockTweaks.config.getCategory(CATEGORY_GENERAL)?.get("gemstonesearchradius")?.set(radius)
|
|
||||||
SkyBlockTweaks.config.save()
|
|
||||||
GemstoneFinder.radius = radius
|
|
||||||
sender.addChatMessage(ChatComponentText("Gemstone search radius set to $radius."))
|
|
||||||
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
sender.addChatMessage(ChatComponentText("Invalid radius. Please provide a positive integer."))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
sender.addChatMessage(ChatComponentText("Invalid command. Usage: /sbt <powderchests/gemstonesearchradius> [enable/disable/radius]"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +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 STBKeyBinds {
|
|
||||||
lateinit var searchForChests: KeyBinding
|
|
||||||
lateinit var clearChests: KeyBinding
|
|
||||||
lateinit var toggleGrottoFinder: KeyBinding
|
|
||||||
lateinit var clearGrotto: KeyBinding
|
|
||||||
lateinit var findGemstones: KeyBinding
|
|
||||||
lateinit var clearGemstones: KeyBinding
|
|
||||||
|
|
||||||
lateinit var toggleLeftWalk: KeyBinding
|
|
||||||
lateinit var toggleRightWalk: KeyBinding
|
|
||||||
lateinit var toggleForwardWalk: KeyBinding
|
|
||||||
lateinit var toggleBackwardWalk: KeyBinding
|
|
||||||
|
|
||||||
lateinit var toggleLeftMouse: KeyBinding
|
|
||||||
|
|
||||||
fun init() {
|
|
||||||
searchForChests = KeyBinding("key.xraySearch", Keyboard.KEY_F10, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(searchForChests)
|
|
||||||
|
|
||||||
clearChests = KeyBinding("key.xrayClear", Keyboard.KEY_MINUS, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(clearChests)
|
|
||||||
|
|
||||||
toggleGrottoFinder = KeyBinding("key.toggleGrottoFinder", Keyboard.KEY_N, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(toggleGrottoFinder)
|
|
||||||
|
|
||||||
clearGrotto = KeyBinding("key.clearGrotto", Keyboard.KEY_F1, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(clearGrotto)
|
|
||||||
|
|
||||||
findGemstones = KeyBinding("key.findGemstones", Keyboard.KEY_J, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(findGemstones)
|
|
||||||
|
|
||||||
clearGemstones = KeyBinding("key.clearGemstones", Keyboard.KEY_K, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(clearGemstones)
|
|
||||||
|
|
||||||
// -----------------------
|
|
||||||
// Macro Toggle
|
|
||||||
// -----------------------
|
|
||||||
toggleLeftWalk = KeyBinding("key.toggleLeftWalk", Keyboard.KEY_LEFT, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(toggleLeftWalk)
|
|
||||||
|
|
||||||
toggleRightWalk = KeyBinding("key.toggleRightWalk", Keyboard.KEY_RIGHT, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(toggleRightWalk)
|
|
||||||
|
|
||||||
toggleForwardWalk = KeyBinding("key.toggleForwardWalk", Keyboard.KEY_UP, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(toggleForwardWalk)
|
|
||||||
|
|
||||||
toggleBackwardWalk = KeyBinding("key.toggleBackwardWalk", Keyboard.KEY_DOWN, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(toggleBackwardWalk)
|
|
||||||
|
|
||||||
toggleLeftMouse = KeyBinding("key.toggleLeftMouse", Keyboard.KEY_PRIOR, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(toggleLeftMouse)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +1,11 @@
|
|||||||
package com.github.itzilly.sbt
|
package com.github.itzilly.sbt
|
||||||
|
|
||||||
import com.github.itzilly.sbt.features.ChestEsp
|
|
||||||
import com.github.itzilly.sbt.features.FarmHelper
|
import com.github.itzilly.sbt.command.ClientCommands
|
||||||
import com.github.itzilly.sbt.features.GemstoneFinder
|
import com.github.itzilly.sbt.command.ModCommandRegistry
|
||||||
|
import com.github.itzilly.sbt.command.registerBaseCommand
|
||||||
import com.github.itzilly.sbt.features.GrottoFinder
|
import com.github.itzilly.sbt.features.GrottoFinder
|
||||||
import com.github.itzilly.sbt.features.router.RouteBuilder
|
import com.github.itzilly.sbt.features.RouteBuilder
|
||||||
import com.github.itzilly.sbt.util.MessageScheduler
|
|
||||||
import net.minecraftforge.client.ClientCommandHandler
|
|
||||||
import net.minecraftforge.common.MinecraftForge
|
import net.minecraftforge.common.MinecraftForge
|
||||||
import net.minecraftforge.common.config.Configuration
|
import net.minecraftforge.common.config.Configuration
|
||||||
import net.minecraftforge.fml.common.Mod
|
import net.minecraftforge.fml.common.Mod
|
||||||
@ -34,41 +33,16 @@ class SkyBlockTweaks {
|
|||||||
|
|
||||||
@Mod.EventHandler
|
@Mod.EventHandler
|
||||||
fun init(event: FMLInitializationEvent) {
|
fun init(event: FMLInitializationEvent) {
|
||||||
STBKeyBinds.init()
|
Keybinds.register()
|
||||||
|
registerEventListeners()
|
||||||
|
|
||||||
MinecraftForge.EVENT_BUS.register(RouteBuilder)
|
ModCommandRegistry.register(ClientCommands)
|
||||||
MinecraftForge.EVENT_BUS.register(InputHandler())
|
registerBaseCommand()
|
||||||
MinecraftForge.EVENT_BUS.register(MessageScheduler)
|
|
||||||
MinecraftForge.EVENT_BUS.register(GrottoFinder)
|
|
||||||
MinecraftForge.EVENT_BUS.register(ChestEsp)
|
|
||||||
MinecraftForge.EVENT_BUS.register(GemstoneFinder)
|
|
||||||
MinecraftForge.EVENT_BUS.register(FarmHelper)
|
|
||||||
|
|
||||||
ClientCommandHandler.instance.registerCommand(SBTCommand())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadConfig() {
|
private fun loadConfig() {
|
||||||
config.load()
|
config.load()
|
||||||
|
|
||||||
val powderChestEnable = config.getBoolean(
|
|
||||||
"powderchestenable",
|
|
||||||
Configuration.CATEGORY_GENERAL,
|
|
||||||
true,
|
|
||||||
"Enables/Disables Powder ChestESP"
|
|
||||||
)
|
|
||||||
ChestEsp.enabled = powderChestEnable
|
|
||||||
|
|
||||||
val gemstoneRadius = config.getInt(
|
|
||||||
"gemstonesearchradius",
|
|
||||||
Configuration.CATEGORY_GENERAL,
|
|
||||||
16,
|
|
||||||
1,
|
|
||||||
256,
|
|
||||||
"Enables/Disables Powder ChestESP"
|
|
||||||
)
|
|
||||||
ChestEsp.enabled = powderChestEnable
|
|
||||||
GemstoneFinder.radius = gemstoneRadius
|
|
||||||
|
|
||||||
if (config.hasChanged()) {
|
if (config.hasChanged()) {
|
||||||
config.save()
|
config.save()
|
||||||
}
|
}
|
||||||
@ -80,4 +54,9 @@ class SkyBlockTweaks {
|
|||||||
config.save()
|
config.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun registerEventListeners() {
|
||||||
|
MinecraftForge.EVENT_BUS.register(RouteBuilder)
|
||||||
|
MinecraftForge.EVENT_BUS.register(GrottoFinder)
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
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> = []
|
||||||
|
)
|
@ -0,0 +1,31 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.github.itzilly.sbt.command
|
||||||
|
|
||||||
|
import com.github.itzilly.sbt.features.GrottoFinder
|
||||||
|
import com.github.itzilly.sbt.util.Chatterbox
|
||||||
|
import com.github.itzilly.sbt.util.SimpleChatMsg
|
||||||
|
|
||||||
|
object ClientCommands {
|
||||||
|
|
||||||
|
@SubCommand(
|
||||||
|
name = "autogrotto",
|
||||||
|
usage = "<status|enable|disable>",
|
||||||
|
description = "Manages the AutoGrotto feature"
|
||||||
|
)
|
||||||
|
fun autogrotto(ctx: CommandContext) {
|
||||||
|
val action = ctx.arg(0)?.lowercase()
|
||||||
|
|
||||||
|
when (action) {
|
||||||
|
"status" -> {
|
||||||
|
val isEnabled = GrottoFinder.isAutoDetectEnabled()
|
||||||
|
Chatterbox.say("Autogrotto is currently ${if (isEnabled) "enabled" else "disabled"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
"enable", "on" -> {
|
||||||
|
GrottoFinder.enableAutoDetect()
|
||||||
|
Chatterbox.say("Autogrotto has been enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
"disable", "off" -> {
|
||||||
|
GrottoFinder.disableAutoDetect()
|
||||||
|
Chatterbox.say("Autogrotto has been disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
Chatterbox.say(SimpleChatMsg("Invalid argument! Usage:").red())
|
||||||
|
Chatterbox.say("/sbt autogrotto <status | enable/on | disable/off>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubCommand(
|
||||||
|
name = "reveal_grotto",
|
||||||
|
usage = "",
|
||||||
|
description = "Reveal Grotto"
|
||||||
|
)
|
||||||
|
fun reveal_grotto(ctx: CommandContext) {
|
||||||
|
GrottoFinder.revealDetectedJasperBlocks()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
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}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/main/kotlin/com/github/itzilly/sbt/data/RouteNode.kt
Normal file
17
src/main/kotlin/com/github/itzilly/sbt/data/RouteNode.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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
|
||||||
|
)
|
4
src/main/kotlin/com/github/itzilly/sbt/data/Vec.kt
Normal file
4
src/main/kotlin/com/github/itzilly/sbt/data/Vec.kt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package com.github.itzilly.sbt.data
|
||||||
|
|
||||||
|
data class Vecd3(val x:Double, val y:Double, val z:Double)
|
||||||
|
data class Vecf3(val x:Float, val y:Float, val z:Float)
|
@ -1,175 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.SkyBlockTweaks
|
|
||||||
import com.github.itzilly.sbt.renderer.RenderUtils
|
|
||||||
import java.awt.Color
|
|
||||||
import com.github.itzilly.sbt.util.Chatterbox
|
|
||||||
import com.github.itzilly.sbt.util.DelayedFunction
|
|
||||||
import com.github.itzilly.sbt.util.SimpleChatMsg
|
|
||||||
import com.github.itzilly.sbt.util.Vecd3
|
|
||||||
import net.minecraft.block.Block
|
|
||||||
import net.minecraft.client.Minecraft
|
|
||||||
import net.minecraft.client.renderer.GlStateManager
|
|
||||||
import net.minecraft.init.Blocks
|
|
||||||
import net.minecraft.util.BlockPos
|
|
||||||
import net.minecraft.entity.Entity
|
|
||||||
import net.minecraft.tileentity.TileEntityChest
|
|
||||||
import net.minecraft.util.AxisAlignedBB
|
|
||||||
import net.minecraft.util.MovingObjectPosition
|
|
||||||
import net.minecraftforge.client.event.ClientChatReceivedEvent
|
|
||||||
import net.minecraftforge.client.event.RenderWorldLastEvent
|
|
||||||
import net.minecraftforge.common.config.Configuration
|
|
||||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import org.lwjgl.opengl.GL11
|
|
||||||
|
|
||||||
|
|
||||||
data class ChestNode(
|
|
||||||
val x: Int,
|
|
||||||
val y: Int,
|
|
||||||
val z: Int,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun chestNodeExists(x: Int, y: Int, z: Int): Boolean {
|
|
||||||
return ChestEsp.chestList.any { it.x == x && it.y == y && it.z == z }
|
|
||||||
}
|
|
||||||
object ChestEsp {
|
|
||||||
var chestList: ArrayList<ChestNode> = ArrayList()
|
|
||||||
var enabled: Boolean = SkyBlockTweaks.config.getBoolean("powderchestenable", Configuration.CATEGORY_GENERAL, true, "Enables/Disables Powder ChestESP")
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun chatMessageEvent(event: ClientChatReceivedEvent) {
|
|
||||||
if (!enabled) return
|
|
||||||
if (event.message.unformattedText == "You uncovered a treasure chest!") {
|
|
||||||
DelayedFunction({ highlightChests() }, 5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun renderBlockOverlay(event: RenderWorldLastEvent) {
|
|
||||||
if (!enabled) return
|
|
||||||
val player = Minecraft.getMinecraft().thePlayer
|
|
||||||
|
|
||||||
for (chest: ChestNode in chestList) {
|
|
||||||
val pos = BlockPos(chest.x, chest.y, chest.z)
|
|
||||||
drawChestOutline(player, pos, event.partialTicks)
|
|
||||||
drawChestLine(pos, event.partialTicks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun rightClickEvent(event: PlayerInteractEvent) {
|
|
||||||
if (!enabled) return
|
|
||||||
if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
|
|
||||||
val pos = event.pos
|
|
||||||
if (chestNodeExists(pos.x, pos.y, pos.z)) {
|
|
||||||
chestList.removeIf { it.x == pos.x && it.y == pos.y && it.z == pos.z }
|
|
||||||
checkChestLocations()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun checkChestLocations() {
|
|
||||||
for (chest in chestList) {
|
|
||||||
if (chestNodeExists(chest.x, chest.y, chest.z)) {
|
|
||||||
chestList.removeIf { it.x == chest.x && it.y == chest.y && it.z == chest.z }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun highlightChests() {
|
|
||||||
if (!enabled) return
|
|
||||||
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
|
|
||||||
|
|
||||||
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 tileEntity = world.getTileEntity(BlockPos(x, y, z))
|
|
||||||
if (tileEntity is TileEntityChest) {
|
|
||||||
if (tileEntity.numPlayersUsing != 0) {
|
|
||||||
val point = ChestNode(x, y, z)
|
|
||||||
if (!chestNodeExists(x, y, z)) {
|
|
||||||
chestList.add(point)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkChestLocations()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun drawChestOutline(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()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun drawChestLine(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 = Vecd3(rm.viewerPosX, rm.viewerPosY + render.eyeHeight, rm.viewerPosZ)
|
|
||||||
|
|
||||||
val pos2 = Vecd3(
|
|
||||||
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)
|
|
||||||
RenderUtils.drawLine(pos1, pos2, lineColor, 2, false, partialTicks)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.STBKeyBinds.toggleLeftWalk;
|
|
||||||
import com.github.itzilly.sbt.features.gardener.CaneMacroer
|
|
||||||
import com.github.itzilly.sbt.util.Chatterbox
|
|
||||||
import net.minecraft.client.Minecraft
|
|
||||||
import net.minecraft.client.gui.Gui
|
|
||||||
import net.minecraft.client.gui.GuiChat
|
|
||||||
import net.minecraftforge.client.event.RenderGameOverlayEvent
|
|
||||||
import net.minecraftforge.common.MinecraftForge
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import net.minecraftforge.fml.common.gameevent.InputEvent
|
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent
|
|
||||||
import org.lwjgl.input.Keyboard
|
|
||||||
|
|
||||||
|
|
||||||
object FarmHelper {
|
|
||||||
|
|
||||||
private val mc: Minecraft = Minecraft.getMinecraft()
|
|
||||||
|
|
||||||
private var isToggledLeft = false
|
|
||||||
private var isToggledRight = false
|
|
||||||
private var isToggledForward = false
|
|
||||||
private var isToggledBack = false
|
|
||||||
private var isToggledAttack = false
|
|
||||||
|
|
||||||
private var ignoreNextKeyUp = false
|
|
||||||
private var lastToggleKeyCode = -1
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun onTick(event: TickEvent.ClientTickEvent) {
|
|
||||||
if (mc.gameSettings.keyBindForward.isKeyDown) isToggledForward = false
|
|
||||||
if (mc.gameSettings.keyBindLeft.isKeyDown) isToggledLeft = false
|
|
||||||
if (mc.gameSettings.keyBindRight.isKeyDown) isToggledRight = false
|
|
||||||
if (mc.gameSettings.keyBindBack.isKeyDown) isToggledBack = false
|
|
||||||
if (mc.gameSettings.keyBindAttack.isKeyDown) isToggledAttack = false
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun onKeyInput(event: InputEvent.KeyInputEvent) {
|
|
||||||
val key = Keyboard.getEventKey()
|
|
||||||
val isPressed = Keyboard.getEventKeyState()
|
|
||||||
|
|
||||||
if (toggleLeftWalk.isPressed) {
|
|
||||||
Chatterbox.say("Enabled macro!")
|
|
||||||
CaneMacroer.isMacroToggled = true
|
|
||||||
MinecraftForge.EVENT_BUS.register(CaneMacroer)
|
|
||||||
CaneMacroer.mc.displayGuiScreen(GuiChat(""))
|
|
||||||
|
|
||||||
lastToggleKeyCode = key
|
|
||||||
ignoreNextKeyUp = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPressed && ignoreNextKeyUp && key == lastToggleKeyCode) {
|
|
||||||
ignoreNextKeyUp = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CaneMacroer.isMacroToggled) {
|
|
||||||
Chatterbox.say("Macro disabled by input!")
|
|
||||||
CaneMacroer.isMacroToggled = false
|
|
||||||
CaneMacroer.stop()
|
|
||||||
MinecraftForge.EVENT_BUS.unregister(CaneMacroer)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// if (toggleLeftWalk.isPressed) isToggledLeft = !isToggledLeft
|
|
||||||
// if (toggleRightWalk.isPressed) isToggledRight = !isToggledRight
|
|
||||||
// if (toggleForwardWalk.isPressed) isToggledForward = !isToggledForward
|
|
||||||
// if (toggleBackwardWalk.isPressed) isToggledBack = !isToggledBack
|
|
||||||
// if (toggleLeftMouse.isPressed) isToggledAttack = !isToggledAttack
|
|
||||||
//
|
|
||||||
// if (isToggledLeft) (mc.gameSettings.keyBindLeft as KeyBindingAccessor).setPressed(true)
|
|
||||||
// if (isToggledRight) (mc.gameSettings.keyBindRight as KeyBindingAccessor).setPressed(true)
|
|
||||||
// if (isToggledForward) (mc.gameSettings.keyBindForward as KeyBindingAccessor).setPressed(true)
|
|
||||||
// if (isToggledBack) (mc.gameSettings.keyBindBack as KeyBindingAccessor).setPressed(true)
|
|
||||||
// if (isToggledAttack) (mc.gameSettings.keyBindAttack as KeyBindingAccessor).setPressed(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun onRenderOverlay(event: RenderGameOverlayEvent.Text) {
|
|
||||||
val x = 10f
|
|
||||||
var y = 10f
|
|
||||||
|
|
||||||
val toggledKeys = mutableListOf<String>()
|
|
||||||
if (isToggledForward) toggledKeys.add("W")
|
|
||||||
if (isToggledLeft) toggledKeys.add("A")
|
|
||||||
if (isToggledBack) toggledKeys.add("S")
|
|
||||||
if (isToggledRight) toggledKeys.add("D")
|
|
||||||
if (isToggledAttack) toggledKeys.add("Attack")
|
|
||||||
|
|
||||||
if (toggledKeys.isEmpty()) return
|
|
||||||
|
|
||||||
val boxWidth = 60
|
|
||||||
val boxHeight = 10 + toggledKeys.size * 10
|
|
||||||
|
|
||||||
Gui.drawRect((x - 2).toInt(), (y - 2).toInt(), (x + boxWidth).toInt(), (y + boxHeight).toInt(), 0x90000000.toInt())
|
|
||||||
|
|
||||||
for (label in toggledKeys) {
|
|
||||||
mc.fontRendererObj.drawStringWithShadow("[$label]", x, y, 0xFFFFFF)
|
|
||||||
y += 10f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.SkyBlockTweaks
|
|
||||||
import com.github.itzilly.sbt.renderer.RenderFuncs
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
RenderFuncs.drawClusterOutline(player, cluster.positions, event.partialTicks, cluster.color.color)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class GemstoneCluster(
|
|
||||||
val positions: List<BlockPos>,
|
|
||||||
val color: GemstoneColors
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,38 +1,82 @@
|
|||||||
package com.github.itzilly.sbt.features
|
package com.github.itzilly.sbt.features
|
||||||
|
|
||||||
import com.github.itzilly.sbt.renderer.RenderFuncs
|
import com.github.itzilly.sbt.Keybinds
|
||||||
|
import com.github.itzilly.sbt.render.BlockOutlineRenderer
|
||||||
import com.github.itzilly.sbt.util.Chatterbox
|
import com.github.itzilly.sbt.util.Chatterbox
|
||||||
import com.github.itzilly.sbt.util.MessageScheduler
|
import com.github.itzilly.sbt.util.DelayedFunction
|
||||||
import com.github.itzilly.sbt.util.SimpleChatMsg
|
import com.github.itzilly.sbt.util.SimpleChatMsg
|
||||||
|
import com.github.itzilly.sbt.util.getMiniServerIdFromScoreboard
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.block.state.IBlockState
|
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.network.NetHandlerPlayClient
|
|
||||||
import net.minecraft.init.Blocks
|
import net.minecraft.init.Blocks
|
||||||
import net.minecraft.util.BlockPos
|
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.World
|
||||||
import net.minecraft.world.chunk.Chunk
|
import net.minecraft.world.chunk.Chunk
|
||||||
import net.minecraftforge.client.event.RenderWorldLastEvent
|
import net.minecraftforge.client.event.RenderWorldLastEvent
|
||||||
|
import net.minecraftforge.event.entity.EntityJoinWorldEvent
|
||||||
import net.minecraftforge.event.world.ChunkEvent
|
import net.minecraftforge.event.world.ChunkEvent
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
|
import net.minecraftforge.fml.common.gameevent.InputEvent
|
||||||
|
import net.minecraftforge.fml.common.gameevent.TickEvent
|
||||||
|
|
||||||
object GrottoFinder {
|
object GrottoFinder {
|
||||||
|
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 targetBlock: Block = Blocks.stained_glass
|
||||||
private val targetMeta: Int = 2 // Magenta stained glass
|
private val targetMeta: Int = 2 // Magenta stained glass
|
||||||
|
|
||||||
private var magentaGlassList: ArrayList<ChestNode> = ArrayList()
|
private var lastWorldLoadTime = 0L
|
||||||
|
private var lastMiniServerId: String? = null
|
||||||
|
|
||||||
private val minBounds = BlockPos(201, 30, 201)
|
private var renderBlockList: ArrayList<BlockPos> = ArrayList()
|
||||||
private val maxBounds = BlockPos(824, 189, 824)
|
private var jasperCrystalsList: ArrayList<BlockPos> = ArrayList()
|
||||||
|
|
||||||
var isEnabled: Boolean = true
|
fun enableAutoDetect() {
|
||||||
|
autoDetectEnabled = true
|
||||||
fun clear() {
|
|
||||||
magentaGlassList.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkWorldForMagentaStainedGlass(world: World) {
|
fun disableAutoDetect() {
|
||||||
|
autoDetectEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isAutoDetectEnabled(): Boolean {
|
||||||
|
return autoDetectEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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 (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 (chunkX in minBounds.x / 16..maxBounds.x / 16) {
|
||||||
for (chunkZ in minBounds.z / 16..maxBounds.z / 16) {
|
for (chunkZ in minBounds.z / 16..maxBounds.z / 16) {
|
||||||
val chunk = world.getChunkFromChunkCoords(chunkX, chunkZ)
|
val chunk = world.getChunkFromChunkCoords(chunkX, chunkZ)
|
||||||
@ -51,38 +95,244 @@ object GrottoFinder {
|
|||||||
val block = blockState.block
|
val block = blockState.block
|
||||||
val meta = block.getMetaFromState(blockState)
|
val meta = block.getMetaFromState(blockState)
|
||||||
|
|
||||||
if (block === Blocks.stained_glass && meta == 2) {
|
if (block === targetBlock && meta == targetMeta) {
|
||||||
if (!magentaNodeExists(blockPos.x, blockPos.y, blockPos.z)) {
|
if (!magentaNodeExists(blockPos.x, blockPos.y, blockPos.z)) {
|
||||||
magentaGlassList.add(ChestNode(blockPos.x, blockPos.y, blockPos.z))
|
renderBlockList.add(BlockPos(blockPos.x, blockPos.y, blockPos.z))
|
||||||
}
|
}
|
||||||
println("Found magenta stained glass at $blockPos")
|
}
|
||||||
val msg = SimpleChatMsg("Found magenta stained glass at $blockPos").light_purple()
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
Chatterbox.say(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private 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
|
@SubscribeEvent
|
||||||
fun renderBlockOverlay(event: RenderWorldLastEvent) {
|
fun renderBlockOverlay(event: RenderWorldLastEvent) {
|
||||||
val player = Minecraft.getMinecraft().thePlayer
|
val player = Minecraft.getMinecraft().thePlayer
|
||||||
|
|
||||||
for (glass: ChestNode in magentaGlassList) {
|
for (glass: BlockPos in renderBlockList) {
|
||||||
val pos = BlockPos(glass.x, glass.y, glass.z)
|
val pos = BlockPos(glass.x, glass.y, glass.z)
|
||||||
RenderFuncs.drawBlockOutline(player, pos, event.partialTicks)
|
BlockOutlineRenderer.drawBlockOutline(player, pos, event.partialTicks)
|
||||||
RenderFuncs.drawBlockLine(pos, event.partialTicks)
|
BlockOutlineRenderer.drawBlockLine(pos, event.partialTicks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun magentaNodeExists(x: Int, y: Int, z: Int): Boolean {
|
private fun isInCrystalHollowsFromTab(): Boolean {
|
||||||
return magentaGlassList.any { it.x == x && it.y == y && it.z == z }
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// World Bounds 824, 189, 824 201, 30, 201
|
|
@ -1,20 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft
|
|
||||||
import net.minecraft.client.settings.GameSettings
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent
|
|
||||||
|
|
||||||
object MacroInterface {
|
|
||||||
private val gs: GameSettings = Minecraft.getMinecraft().gameSettings
|
|
||||||
private var running: Boolean = false
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
private fun onClientTick(event: TickEvent.PlayerTickEvent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
running = false
|
|
||||||
}
|
|
||||||
}
|
|
121
src/main/kotlin/com/github/itzilly/sbt/features/RouteBuilder.kt
Normal file
121
src/main/kotlin/com/github/itzilly/sbt/features/RouteBuilder.kt
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
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)
|
||||||
|
Chatterbox.say("This is a string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,83 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features.gardener
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.mixin.KeyBindingAccessor
|
|
||||||
import com.github.itzilly.sbt.util.Chatterbox
|
|
||||||
import net.minecraft.client.Minecraft
|
|
||||||
import net.minecraft.client.gui.GuiChat
|
|
||||||
import net.minecraft.client.settings.KeyBinding
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent
|
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent
|
|
||||||
|
|
||||||
|
|
||||||
object CaneMacroer {
|
|
||||||
var isMacroToggled: Boolean = false
|
|
||||||
val mc = Minecraft.getMinecraft()
|
|
||||||
val allowedScreens = listOf(GuiChat::class.java)
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun onTick(event: ClientTickEvent) {
|
|
||||||
if (event.phase != TickEvent.Phase.END) return
|
|
||||||
if (!isMacroToggled) return
|
|
||||||
|
|
||||||
val currentScreen = mc.currentScreen
|
|
||||||
|
|
||||||
if (currentScreen != null && allowedScreens.none { it.isInstance(currentScreen) }) {
|
|
||||||
Chatterbox.say("Macro stopped: Invalid screen")
|
|
||||||
stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val mop = mc.objectMouseOver
|
|
||||||
|
|
||||||
if (mop == null || mop.typeOfHit?.name != "BLOCK") return
|
|
||||||
|
|
||||||
val blockPos = mop.blockPos
|
|
||||||
val facing = mop.sideHit
|
|
||||||
|
|
||||||
val player = mc.thePlayer
|
|
||||||
val blockCenter = blockPos.add(0.5, 0.5, 0.5)
|
|
||||||
val distanceSq = player.getDistanceSq(blockCenter.x.toDouble(), blockCenter.y.toDouble(), blockCenter.z.toDouble())
|
|
||||||
|
|
||||||
if (distanceSq > 25) {
|
|
||||||
Chatterbox.say("Macro stopped: Too far from block")
|
|
||||||
stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEntityBlockingView()) {
|
|
||||||
Chatterbox.say("Macro stopped: Entity in the way")
|
|
||||||
stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pressKey(mc.gameSettings.keyBindForward.keyCode)
|
|
||||||
mc.playerController.onPlayerDamageBlock(blockPos, facing)
|
|
||||||
player.swingItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun stop() {
|
|
||||||
KeyBinding.setKeyBindState(mc.gameSettings.keyBindForward.keyCode, false)
|
|
||||||
KeyBinding.setKeyBindState(mc.gameSettings.keyBindAttack.keyCode, false)
|
|
||||||
isMacroToggled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pressKey(keyCode: Int) {
|
|
||||||
KeyBinding.setKeyBindState(keyCode, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isEntityBlockingView(): Boolean {
|
|
||||||
val lookVec = mc.thePlayer.lookVec
|
|
||||||
val eyePos = mc.thePlayer.getPositionEyes(1f)
|
|
||||||
|
|
||||||
val entities = mc.theWorld.getEntitiesWithinAABBExcludingEntity(
|
|
||||||
mc.thePlayer,
|
|
||||||
mc.thePlayer.entityBoundingBox.expand(lookVec.xCoord * 5, lookVec.yCoord * 5, lookVec.zCoord * 5)
|
|
||||||
)
|
|
||||||
|
|
||||||
return entities.any {
|
|
||||||
it.canBeCollidedWith() &&
|
|
||||||
it.entityBoundingBox.isVecInside(eyePos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,199 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features.gardener
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.util.Chatterbox
|
|
||||||
import net.minecraft.client.gui.*
|
|
||||||
|
|
||||||
class MacroMakerGui : GuiScreen() {
|
|
||||||
private var selectedTaskIndex: Int = -1
|
|
||||||
private var draggedTaskIndex: Int = -1
|
|
||||||
private var dragOffsetY: Int = 0
|
|
||||||
|
|
||||||
private val macro = Macro("Example Macro")
|
|
||||||
|
|
||||||
enum class ButtonId(val id: Int) {
|
|
||||||
SAVE_MACRO(0),
|
|
||||||
CANCEL(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun initGui() {
|
|
||||||
this.buttonList.clear()
|
|
||||||
buttonList.add(GuiButton(ButtonId.SAVE_MACRO.id, width / 2 - 100, height - 40, 90, 20, "Save Macro"))
|
|
||||||
buttonList.add(GuiButton(ButtonId.CANCEL.id, width / 2 + 10, height - 40, 90, 20, "Cancel"))
|
|
||||||
|
|
||||||
macro.tasks.add(MoveTask("W", true))
|
|
||||||
macro.tasks.add(MouseTask("Left Click"))
|
|
||||||
macro.tasks.add(ChatCommandTask("/spawn"))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun actionPerformed(button: GuiButton) {
|
|
||||||
when (button.id) {
|
|
||||||
ButtonId.SAVE_MACRO.id -> {
|
|
||||||
Chatterbox.say("Saved macro!")
|
|
||||||
Close()
|
|
||||||
}
|
|
||||||
ButtonId.CANCEL.id -> Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) {
|
|
||||||
drawDefaultBackground()
|
|
||||||
|
|
||||||
val thirdWidth = width / 3
|
|
||||||
drawRect(0, 0, thirdWidth, height, 0xFF202020.toInt())
|
|
||||||
drawRect(thirdWidth, 0, thirdWidth * 2, height, 0xFF303030.toInt())
|
|
||||||
drawRect(thirdWidth * 2, 0, width, height, 0xFF202020.toInt())
|
|
||||||
|
|
||||||
drawCenteredString(fontRendererObj, "Macro Maker", width / 2, 10, 0xFFFFFF)
|
|
||||||
|
|
||||||
drawLeftPanel(mouseX, mouseY)
|
|
||||||
drawMiddlePanel(mouseX, mouseY)
|
|
||||||
drawRightPanel()
|
|
||||||
|
|
||||||
super.drawScreen(mouseX, mouseY, partialTicks)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun drawLeftPanel(mouseX: Int, mouseY: Int) {
|
|
||||||
drawString(fontRendererObj, "Editing: ${macro.name}", 10, 20, 0xFFFFFF)
|
|
||||||
drawString(fontRendererObj, "Add Task:", 10, 40, 0xAAAAAA)
|
|
||||||
|
|
||||||
val taskButtons = listOf(
|
|
||||||
Triple("+ Move", 60, { macro.tasks.add(MoveTask("W", false)) }),
|
|
||||||
Triple("+ Mouse", 80, { macro.tasks.add(MouseTask("Right Click")) }),
|
|
||||||
Triple("+ Command", 100, { macro.tasks.add(ChatCommandTask("/say Hello")) })
|
|
||||||
)
|
|
||||||
|
|
||||||
for ((label, y, _) in taskButtons) {
|
|
||||||
drawString(fontRendererObj, label, 10, y, 0x00FF00)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mouseClickedX in 10..100 && mouseClickedY != -1) {
|
|
||||||
for ((_, y, action) in taskButtons) {
|
|
||||||
if (mouseClickedY in y..(y + 10)) {
|
|
||||||
action.invoke()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mouseClickedX = -1
|
|
||||||
mouseClickedY = -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun drawMiddlePanel(mouseX: Int, mouseY: Int) {
|
|
||||||
val thirdWidth = width / 3
|
|
||||||
val taskStartY = 40
|
|
||||||
val taskHeight = 20
|
|
||||||
|
|
||||||
for ((index, task) in macro.tasks.withIndex()) {
|
|
||||||
val y = taskStartY + index * (taskHeight + 5)
|
|
||||||
if (draggedTaskIndex == index) continue // skip rendering the dragged one
|
|
||||||
val color = if (index == selectedTaskIndex) 0xFF4444 else 0xFFFFFF
|
|
||||||
drawRect(thirdWidth + 10, y, thirdWidth * 2 - 10, y + taskHeight, 0xFF404040.toInt())
|
|
||||||
drawString(fontRendererObj, "${task.name} - ${task.getPreview()}", thirdWidth + 15, y + 6, color)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the dragged task following the mouse
|
|
||||||
if (draggedTaskIndex != -1) {
|
|
||||||
val task = macro.tasks[draggedTaskIndex]
|
|
||||||
val y = mouseY - dragOffsetY
|
|
||||||
drawRect(thirdWidth + 10, y, thirdWidth * 2 - 10, y + taskHeight, 0xFF606060.toInt())
|
|
||||||
drawString(fontRendererObj, "${task.name} - ${task.getPreview()}", thirdWidth + 15, y + 6, 0xFFFF00)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun drawRightPanel() {
|
|
||||||
val selected = macro.tasks.getOrNull(selectedTaskIndex) ?: return
|
|
||||||
val startX = width - 180
|
|
||||||
val startY = 20
|
|
||||||
val boxWidth = 160
|
|
||||||
val boxHeight = 80
|
|
||||||
|
|
||||||
// Box with outline
|
|
||||||
drawRect(startX - 2, startY - 2, startX + boxWidth + 2, startY + boxHeight + 2, 0xFFFFFFFF.toInt())
|
|
||||||
drawRect(startX, startY, startX + boxWidth, startY + boxHeight, 0xFF101010.toInt())
|
|
||||||
|
|
||||||
drawString(fontRendererObj, "Task Properties", startX + 5, startY + 5, 0xFFFFFF)
|
|
||||||
|
|
||||||
when (selected) {
|
|
||||||
is MoveTask -> {
|
|
||||||
drawString(fontRendererObj, "Direction: ${selected.direction}", startX + 5, startY + 25, 0xCCCCCC)
|
|
||||||
drawString(fontRendererObj, "Hold: ${selected.hold}", startX + 5, startY + 40, 0xCCCCCC)
|
|
||||||
}
|
|
||||||
is MouseTask -> {
|
|
||||||
drawString(fontRendererObj, "Action: ${selected.action}", startX + 5, startY + 25, 0xCCCCCC)
|
|
||||||
}
|
|
||||||
is ChatCommandTask -> {
|
|
||||||
drawString(fontRendererObj, "Command:", startX + 5, startY + 25, 0xCCCCCC)
|
|
||||||
drawString(fontRendererObj, selected.command, startX + 5, startY + 40, 0x00FFAA)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var mouseClickedX = -1
|
|
||||||
private var mouseClickedY = -1
|
|
||||||
|
|
||||||
override fun mouseClicked(mouseX: Int, mouseY: Int, mouseButton: Int) {
|
|
||||||
mouseClickedX = mouseX
|
|
||||||
mouseClickedY = mouseY
|
|
||||||
|
|
||||||
val thirdWidth = width / 3
|
|
||||||
val taskStartY = 40
|
|
||||||
val taskHeight = 25
|
|
||||||
|
|
||||||
for ((index, _) in macro.tasks.withIndex()) {
|
|
||||||
val y = taskStartY + index * taskHeight
|
|
||||||
if (mouseX in (thirdWidth + 10)..(thirdWidth * 2 - 10) && mouseY in y..(y + 20)) {
|
|
||||||
selectedTaskIndex = index
|
|
||||||
draggedTaskIndex = index
|
|
||||||
dragOffsetY = mouseY - y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.mouseClicked(mouseX, mouseY, mouseButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mouseClickMove(mouseX: Int, mouseY: Int, clickedMouseButton: Int, timeSinceLastClick: Long) {
|
|
||||||
super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mouseReleased(mouseX: Int, mouseY: Int, state: Int) {
|
|
||||||
if (draggedTaskIndex != -1) {
|
|
||||||
val thirdWidth = width / 3
|
|
||||||
val taskStartY = 40
|
|
||||||
val taskHeight = 25
|
|
||||||
val newIndex = ((mouseY - taskStartY) / taskHeight).coerceIn(0, macro.tasks.size - 1)
|
|
||||||
if (newIndex != draggedTaskIndex) {
|
|
||||||
val task = macro.tasks.removeAt(draggedTaskIndex)
|
|
||||||
macro.tasks.add(newIndex, task)
|
|
||||||
selectedTaskIndex = newIndex
|
|
||||||
}
|
|
||||||
draggedTaskIndex = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
super.mouseReleased(mouseX, mouseY, state)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Close() {
|
|
||||||
mc.displayGuiScreen(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class MacroTask(val name: String) {
|
|
||||||
abstract fun getPreview(): String
|
|
||||||
}
|
|
||||||
|
|
||||||
class MoveTask(var direction: String, var hold: Boolean) : MacroTask("Move") {
|
|
||||||
override fun getPreview(): String = if (hold) "Hold $direction" else "Tap $direction"
|
|
||||||
}
|
|
||||||
|
|
||||||
class MouseTask(val action: String) : MacroTask("Mouse") {
|
|
||||||
override fun getPreview(): String = action
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatCommandTask(var command: String) : MacroTask("Command") {
|
|
||||||
override fun getPreview(): String = command
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Macro(
|
|
||||||
val name: String,
|
|
||||||
val tasks: MutableList<MacroTask> = mutableListOf()
|
|
||||||
)
|
|
@ -1,127 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features.router
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.itzilly.sbt.renderer.RenderFuncs
|
|
||||||
import java.awt.datatransfer.Clipboard
|
|
||||||
import java.awt.datatransfer.StringSelection
|
|
||||||
|
|
||||||
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.client.settings.KeyBinding
|
|
||||||
import net.minecraft.util.BlockPos
|
|
||||||
import net.minecraftforge.client.event.RenderWorldLastEvent
|
|
||||||
import net.minecraftforge.fml.client.registry.ClientRegistry
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import net.minecraftforge.fml.common.gameevent.InputEvent
|
|
||||||
import org.lwjgl.input.Keyboard
|
|
||||||
import java.awt.Toolkit
|
|
||||||
import kotlin.math.round
|
|
||||||
|
|
||||||
|
|
||||||
object RouteBuilder {
|
|
||||||
var addNodeKeybind: KeyBinding
|
|
||||||
var deleteLastNodeKeybind: KeyBinding
|
|
||||||
var finishRouteKeybind: KeyBinding
|
|
||||||
|
|
||||||
var nodes: ArrayList<RouteNode> = ArrayList()
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
|
||||||
addNodeKeybind = KeyBinding("key.addNode", Keyboard.KEY_ADD, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(addNodeKeybind)
|
|
||||||
|
|
||||||
deleteLastNodeKeybind = KeyBinding("key.removeLastNode", Keyboard.KEY_MINUS, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(deleteLastNodeKeybind)
|
|
||||||
|
|
||||||
finishRouteKeybind = KeyBinding("key.finishRoute", Keyboard.KEY_F4, "key.categories.sbt")
|
|
||||||
ClientRegistry.registerKeyBinding(finishRouteKeybind)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun onKeyInput(event: InputEvent.KeyInputEvent) {
|
|
||||||
if (addNodeKeybind.isPressed) {
|
|
||||||
val mc = Minecraft.getMinecraft()
|
|
||||||
val x = round(mc.thePlayer.posX - 0.5).toInt()
|
|
||||||
val y = round(mc.thePlayer.posY).toInt() - 1
|
|
||||||
val z = round(mc.thePlayer.posZ - 0.5).toInt()
|
|
||||||
|
|
||||||
if (nodeExists(x, y, z)) {
|
|
||||||
Chatterbox.say(SimpleChatMsg("Node already exists!").red())
|
|
||||||
} else {
|
|
||||||
addNode(x, y, z)
|
|
||||||
Chatterbox.say("This is a string")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deleteLastNodeKeybind.isPressed) {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finishRouteKeybind.isPressed) {
|
|
||||||
if (nodes.size == 0) {
|
|
||||||
val msg = SimpleChatMsg("There aren't any nodes to copy!")
|
|
||||||
Chatterbox.say(msg.red())
|
|
||||||
} else {
|
|
||||||
val jsonString = Gson().toJson(nodes)
|
|
||||||
val msg = SimpleChatMsg("String copied to clipboard!")
|
|
||||||
setClipboard(jsonString)
|
|
||||||
Chatterbox.say(msg.green())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
fun renderBlockOverlay(event: RenderWorldLastEvent) {
|
|
||||||
val player = Minecraft.getMinecraft().thePlayer
|
|
||||||
|
|
||||||
for (marker: RouteNode in nodes) {
|
|
||||||
val pos = BlockPos(marker.x, marker.y, marker.z)
|
|
||||||
RenderFuncs.drawBlockOutline(player, pos, event.partialTicks)
|
|
||||||
RenderFuncs.drawBlockLine(pos, event.partialTicks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addNode(x: Int, y: Int, z: Int) {
|
|
||||||
nodes.add(RouteNode(x, y, z, 0u, 1u, 0u, NodeOptions("${nodes.size + 1}")))
|
|
||||||
}
|
|
||||||
|
|
||||||
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}")))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setClipboard(s: String) {
|
|
||||||
val selection = StringSelection(s)
|
|
||||||
val clipboard: Clipboard = Toolkit.getDefaultToolkit().systemClipboard
|
|
||||||
clipboard.setContents(selection, selection)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
fun nodeExists(x: Int, y: Int, z: Int): Boolean {
|
|
||||||
return RouteBuilder.nodes.any { it.x == x && it.y == y && it.z == z }
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.features.router
|
|
||||||
|
|
||||||
object RouteMaker {
|
|
||||||
var markerList: ArrayList<RouteMarker> = ArrayList()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class RouteMarker(
|
|
||||||
val x: Int,
|
|
||||||
val y: Int,
|
|
||||||
val z: Int,
|
|
||||||
|
|
||||||
val r: UByte,
|
|
||||||
val g: UByte,
|
|
||||||
val b: UByte,
|
|
||||||
|
|
||||||
val options: RouteOptions
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RouteOptions(
|
|
||||||
val name: String
|
|
||||||
)
|
|
||||||
|
|
||||||
fun isPointInRouteList(routeList: ArrayList<RouteMarker>, x: Int, y: Int, z: Int): Boolean {
|
|
||||||
return routeList.any { it.x == x && it.y == y && it.z == z }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.settings.KeyBinding;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
@Mixin(KeyBinding.class)
|
|
||||||
public interface KeyBindingAccessor {
|
|
||||||
@Accessor("pressed")
|
|
||||||
void setPressed(boolean pressed);
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
package com.github.itzilly.sbt.renderer
|
package com.github.itzilly.sbt.render
|
||||||
|
|
||||||
import com.github.itzilly.sbt.util.Vecd3
|
import com.github.itzilly.sbt.data.Vecd3
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.renderer.GlStateManager
|
import net.minecraft.client.renderer.GlStateManager
|
||||||
@ -11,10 +11,10 @@ import net.minecraft.util.EnumFacing
|
|||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
|
|
||||||
object RenderFuncs {
|
object BlockOutlineRenderer {
|
||||||
|
|
||||||
fun drawBlockOutline(entity: Entity, blockPos: BlockPos, partialTicks: Float, outlineColor: Int) {
|
fun drawBlockOutline(entity: Entity, blockPos: BlockPos, partialTicks: Float, outlineColor: Int) {
|
||||||
val padding = 0.0020000000949949026
|
val padding = 0.0020000000949949026 // Magic number DO NOT TOUCH
|
||||||
|
|
||||||
val entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
|
val entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
|
||||||
val entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
|
val entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
|
||||||
@ -30,7 +30,6 @@ object RenderFuncs {
|
|||||||
blockPos.x + 1.0, blockPos.y + 1.0, blockPos.z + 1.0
|
blockPos.x + 1.0, blockPos.y + 1.0, blockPos.z + 1.0
|
||||||
).expand(padding, padding, padding)
|
).expand(padding, padding, padding)
|
||||||
|
|
||||||
// Convert integer color to r, g, b, a values
|
|
||||||
val r = (outlineColor shr 16 and 0xFF) / 255.0f
|
val r = (outlineColor shr 16 and 0xFF) / 255.0f
|
||||||
val g = (outlineColor shr 8 and 0xFF) / 255.0f
|
val g = (outlineColor shr 8 and 0xFF) / 255.0f
|
||||||
val b = (outlineColor and 0xFF) / 255.0f
|
val b = (outlineColor and 0xFF) / 255.0f
|
||||||
@ -45,12 +44,9 @@ object RenderFuncs {
|
|||||||
GL11.glEnable(GL11.GL_LINE_SMOOTH)
|
GL11.glEnable(GL11.GL_LINE_SMOOTH)
|
||||||
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
|
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
|
||||||
GL11.glLineWidth(2.0f)
|
GL11.glLineWidth(2.0f)
|
||||||
|
|
||||||
// Set the color with alpha
|
|
||||||
GL11.glColor4f(r, g, b, a)
|
GL11.glColor4f(r, g, b, a)
|
||||||
|
|
||||||
// Draw the outline using the bounding box
|
RenderPrimitives.drawBlock(boundingBox.offset(-entityX, -entityY, -entityZ), outlineColor, outlineColor)
|
||||||
RenderUtils.drawBlock(boundingBox.offset(-entityX, -entityY, -entityZ), outlineColor, outlineColor)
|
|
||||||
|
|
||||||
GL11.glDisable(GL11.GL_LINE_SMOOTH)
|
GL11.glDisable(GL11.GL_LINE_SMOOTH)
|
||||||
GL11.glDisable(GL11.GL_BLEND)
|
GL11.glDisable(GL11.GL_BLEND)
|
||||||
@ -75,7 +71,6 @@ object RenderFuncs {
|
|||||||
val blockState = world.getBlockState(blockPos)
|
val blockState = world.getBlockState(blockPos)
|
||||||
val block: Block = blockState.block
|
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)
|
val boundingBox: AxisAlignedBB = block.getCollisionBoundingBox(world, blockPos, blockState)
|
||||||
?: AxisAlignedBB(
|
?: AxisAlignedBB(
|
||||||
blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(),
|
blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(),
|
||||||
@ -91,7 +86,7 @@ object RenderFuncs {
|
|||||||
GL11.glLineWidth(2.0f)
|
GL11.glLineWidth(2.0f)
|
||||||
GL11.glShadeModel(GL11.GL_SMOOTH)
|
GL11.glShadeModel(GL11.GL_SMOOTH)
|
||||||
|
|
||||||
RenderUtils.drawBlock(boundingBox.offset(-entityX, -entityY, -entityZ), outlineStartColor, outlineEndColor)
|
RenderPrimitives.drawBlock(boundingBox.offset(-entityX, -entityY, -entityZ), outlineStartColor, outlineEndColor)
|
||||||
|
|
||||||
GL11.glLineWidth(2.0f)
|
GL11.glLineWidth(2.0f)
|
||||||
GL11.glDisable(GL11.GL_LINE_SMOOTH)
|
GL11.glDisable(GL11.GL_LINE_SMOOTH)
|
||||||
@ -115,13 +110,12 @@ object RenderFuncs {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val lineColor = Color(0xe310d5)
|
val lineColor = Color(0xe310d5)
|
||||||
RenderUtils.drawLine(pos1, pos2, lineColor, 2, false, partialTicks)
|
RenderPrimitives.drawLine(pos1, pos2, lineColor, 2, false, partialTicks)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun drawClusterOutline(entity: Entity, positions: List<BlockPos>, partialTicks: Float, outlineColor: Int) {
|
fun drawClusterOutline(entity: Entity, positions: List<BlockPos>, partialTicks: Float, outlineColor: Int) {
|
||||||
val padding = 0.0020000000949949026
|
val padding = 0.0020000000949949026 // Magic number DO NOT TOUCH
|
||||||
|
|
||||||
// Correctly calculate the player's interpolated position
|
|
||||||
val entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
|
val entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks
|
||||||
val entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
|
val entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks
|
||||||
val entityZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks
|
val entityZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks
|
||||||
@ -138,42 +132,38 @@ object RenderFuncs {
|
|||||||
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
|
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST)
|
||||||
GL11.glLineWidth(2.0f)
|
GL11.glLineWidth(2.0f)
|
||||||
|
|
||||||
// Convert integer color to r, g, b, a values
|
|
||||||
val r = (outlineColor shr 16 and 0xFF) / 255.0f
|
val r = (outlineColor shr 16 and 0xFF) / 255.0f
|
||||||
val g = (outlineColor shr 8 and 0xFF) / 255.0f
|
val g = (outlineColor shr 8 and 0xFF) / 255.0f
|
||||||
val b = (outlineColor and 0xFF) / 255.0f
|
val b = (outlineColor and 0xFF) / 255.0f
|
||||||
val a = (outlineColor shr 24 and 0xFF) / 255.0f
|
val a = (outlineColor shr 24 and 0xFF) / 255.0f
|
||||||
|
|
||||||
// Set the color with alpha
|
|
||||||
GL11.glColor4f(r, g, b, a)
|
GL11.glColor4f(r, g, b, a)
|
||||||
|
|
||||||
// Iterate over the positions and draw the outline around each block
|
|
||||||
for (pos in positions) {
|
for (pos in positions) {
|
||||||
val blockState = world.getBlockState(pos)
|
val blockState = world.getBlockState(pos)
|
||||||
val boundingBox = blockState.block.getCollisionBoundingBox(world, pos, blockState)
|
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)
|
?: 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)
|
||||||
|
|
||||||
// Offset the bounding box by the interpolated player position
|
|
||||||
val offsetBoundingBox = boundingBox.offset(-entityX, -entityY, -entityZ)
|
val offsetBoundingBox = boundingBox.offset(-entityX, -entityY, -entityZ)
|
||||||
|
|
||||||
// Check adjacent blocks and only draw faces that are exposed (not adjacent to another gemstone block)
|
// Only draw exposed faces
|
||||||
if (!positions.contains(pos.add(1, 0, 0))) {
|
if (!positions.contains(pos.add(1, 0, 0))) {
|
||||||
RenderUtils.drawBlockFace(offsetBoundingBox, EnumFacing.EAST, outlineColor)
|
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.EAST, outlineColor)
|
||||||
}
|
}
|
||||||
if (!positions.contains(pos.add(-1, 0, 0))) {
|
if (!positions.contains(pos.add(-1, 0, 0))) {
|
||||||
RenderUtils.drawBlockFace(offsetBoundingBox, EnumFacing.WEST, outlineColor)
|
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.WEST, outlineColor)
|
||||||
}
|
}
|
||||||
if (!positions.contains(pos.add(0, 1, 0))) {
|
if (!positions.contains(pos.add(0, 1, 0))) {
|
||||||
RenderUtils.drawBlockFace(offsetBoundingBox, EnumFacing.UP, outlineColor)
|
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.UP, outlineColor)
|
||||||
}
|
}
|
||||||
if (!positions.contains(pos.add(0, -1, 0))) {
|
if (!positions.contains(pos.add(0, -1, 0))) {
|
||||||
RenderUtils.drawBlockFace(offsetBoundingBox, EnumFacing.DOWN, outlineColor)
|
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.DOWN, outlineColor)
|
||||||
}
|
}
|
||||||
if (!positions.contains(pos.add(0, 0, 1))) {
|
if (!positions.contains(pos.add(0, 0, 1))) {
|
||||||
RenderUtils.drawBlockFace(offsetBoundingBox, EnumFacing.SOUTH, outlineColor)
|
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.SOUTH, outlineColor)
|
||||||
}
|
}
|
||||||
if (!positions.contains(pos.add(0, 0, -1))) {
|
if (!positions.contains(pos.add(0, 0, -1))) {
|
||||||
RenderUtils.drawBlockFace(offsetBoundingBox, EnumFacing.NORTH, outlineColor)
|
RenderPrimitives.drawBlockFace(offsetBoundingBox, EnumFacing.NORTH, outlineColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
package com.github.itzilly.sbt.renderer
|
package com.github.itzilly.sbt.render
|
||||||
|
|
||||||
|
import com.github.itzilly.sbt.data.Vecd3
|
||||||
import com.github.itzilly.sbt.util.Vecd3
|
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.renderer.GlStateManager
|
import net.minecraft.client.renderer.GlStateManager
|
||||||
import net.minecraft.client.renderer.Tessellator
|
import net.minecraft.client.renderer.Tessellator
|
||||||
@ -12,7 +11,7 @@ import net.minecraft.util.EnumFacing
|
|||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
|
|
||||||
object RenderUtils {
|
object RenderPrimitives {
|
||||||
var TESSELLATOR: Tessellator = Tessellator.getInstance()
|
var TESSELLATOR: Tessellator = Tessellator.getInstance()
|
||||||
var WORLD_RENDERER: WorldRenderer = Tessellator.getInstance().worldRenderer
|
var WORLD_RENDERER: WorldRenderer = Tessellator.getInstance().worldRenderer
|
||||||
|
|
@ -1,18 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.renderer
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft
|
|
||||||
import net.minecraft.util.BlockPos
|
|
||||||
import net.minecraftforge.client.event.RenderWorldLastEvent
|
|
||||||
|
|
||||||
class RenderableBlockOutline(val x: Int, val y: Int, val z: Int, val outlineColor: Int) {
|
|
||||||
fun renderOutline(event: RenderWorldLastEvent) {
|
|
||||||
val player = Minecraft.getMinecraft().thePlayer
|
|
||||||
val pos = BlockPos(x, y, z)
|
|
||||||
RenderFuncs.drawBlockOutline(player, pos, event.partialTicks, outlineColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun renderLine(event: RenderWorldLastEvent) {
|
|
||||||
val pos = BlockPos(x, y, z)
|
|
||||||
RenderFuncs.drawBlockLine(pos, event.partialTicks)
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ import net.minecraftforge.common.MinecraftForge
|
|||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent
|
import net.minecraftforge.fml.common.gameevent.TickEvent
|
||||||
|
|
||||||
|
|
||||||
class DelayedFunction(private val function: () -> Unit, private val delayTicks: Int) {
|
class DelayedFunction(private val function: () -> Unit, private val delayTicks: Int) {
|
||||||
private var ticksLeft: Int = delayTicks
|
private var ticksLeft: Int = delayTicks
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
19
src/main/kotlin/com/github/itzilly/sbt/util/WorldUtils.kt
Normal file
19
src/main/kotlin/com/github/itzilly/sbt/util/WorldUtils.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.github.itzilly.sbt.util
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft
|
||||||
|
|
||||||
|
fun getMiniServerIdFromScoreboard(): String? {
|
||||||
|
val scoreboard = Minecraft.getMinecraft().theWorld?.scoreboard ?: return null
|
||||||
|
val objective = scoreboard.getObjectiveInDisplaySlot(1) ?: return null
|
||||||
|
|
||||||
|
return scoreboard.getSortedScores(objective)
|
||||||
|
.mapNotNull { score ->
|
||||||
|
try {
|
||||||
|
score.playerName
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.map { it.replace(Regex("§."), "").trim() }
|
||||||
|
.firstOrNull { it.matches(Regex("^\\[mini\\w+]$")) }
|
||||||
|
}
|
@ -1,4 +0,0 @@
|
|||||||
package com.github.itzilly.sbt.util
|
|
||||||
|
|
||||||
data class Vecd3(val x:Double, val y:Double, val z:Double)
|
|
||||||
data class Vecf3(val x:Float, val y:Float, val z:Float)
|
|
@ -1,6 +1,7 @@
|
|||||||
|
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
|
|
@ -2,10 +2,10 @@
|
|||||||
{
|
{
|
||||||
"modid": "${modid}",
|
"modid": "${modid}",
|
||||||
"name": "SkyBlock Tweaks",
|
"name": "SkyBlock Tweaks",
|
||||||
"description": "Utilities for making Hypixel Skyblock more bearable",
|
"description": "Simple tweaks for Hypixel Skyblock",
|
||||||
"version": "${version}",
|
"version": "${version}",
|
||||||
"mcversion": "${mcversion}",
|
"mcversion": "${mcversion}",
|
||||||
"url": "http://itzilly.com/illyum/illyum/sbt-stash/",
|
"url": "http://itzilly.com/illyum/SkyBlockTweaks",
|
||||||
"updateUrl": "",
|
"updateUrl": "",
|
||||||
"authorList": [
|
"authorList": [
|
||||||
"itzilly"
|
"itzilly"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user