Compare commits

...

5 Commits

51 changed files with 831 additions and 440 deletions

View File

@ -12,6 +12,7 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/data" />
<option value="$PROJECT_DIR$/modules/debug" />
<option value="$PROJECT_DIR$/modules/system" />
<option value="$PROJECT_DIR$/modules/util" />
</set>

View File

@ -60,6 +60,7 @@ idea {
["out", "src/main/kotlin", "src/test/kotlin"].each {
excludeDirs += file(it)
excludeDirs += file("modules/debug/" + it)
excludeDirs += file("modules/system/" + it)
excludeDirs += file("modules/util/" + it)
}
@ -128,7 +129,6 @@ minecraft {
runs {
client {
property "hee.debug", ""
property "mixin.env.remapRefMap", "true"
property "mixin.env.refMapRemappingFile", "${projectDir}/build/createSrgToMcp/output.srg"
arg "-mixin.config=hee.mixins.json"
@ -138,6 +138,7 @@ minecraft {
mods {
hee {
source sourceSets.main
source project(":debug").sourceSets.main
source project(":system").sourceSets.main
source project(":util").sourceSets.main
}
@ -145,7 +146,6 @@ minecraft {
}
server {
property "hee.debug", ""
property "mixin.env.remapRefMap", "true"
property "mixin.env.refMapRemappingFile", "${projectDir}/build/createSrgToMcp/output.srg"
arg "-mixin.config=hee.mixins.json"
@ -155,6 +155,7 @@ minecraft {
mods {
hee {
source sourceSets.main
source project(":debug").sourceSets.main
source project(":system").sourceSets.main
source project(":util").sourceSets.main
}
@ -162,7 +163,6 @@ minecraft {
}
data {
property "hee.debug", ""
args "--mod", "hee"
args "--all"
args "--output", file("data/gen")
@ -174,6 +174,7 @@ minecraft {
mods {
hee {
source sourceSets.main
source project(":debug").sourceSets.main
source project(":system").sourceSets.main
source project(":util").sourceSets.main
source project(":datagen").sourceSets.main
@ -190,12 +191,12 @@ mixin {
dependencies {
minecraft "net.minecraftforge:forge:" + mc_version + "-" + forge_version
implementation project(":system")
implementation project(":util")
implementation project(":system")
implementation "thedarkcolour:kotlinforforge:" + kotlin_mod_version
testImplementation project(":system")
testImplementation project(":util")
testImplementation project(":system")
testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.0-RC1"
if (System.getProperty("idea.sync.active") != "true") {

View File

@ -91,7 +91,7 @@ class LangEnglish(generator: DataGenerator, modid: String) : LanguageProvider(ge
}
}
for (command in ClientCommandHandler.nonHelpCommands.values) {
for (command in ClientCommandHandler.all.values) {
val name = command.name
add("commands.hee.$name.info", command.description)
}

View File

@ -0,0 +1,33 @@
buildscript {
repositories {
mavenCentral()
maven { url = "https://files.minecraftforge.net/maven" }
}
dependencies {
classpath group: "net.minecraftforge.gradle", name: "ForgeGradle", version: forge_gradle_version, changing: true
classpath group: "org.jetbrains.kotlin", name: "kotlin-gradle-plugin", version: kotlin_version
}
}
apply plugin: "net.minecraftforge.gradle"
minecraft {
mappings channel: "snapshot", version: rootProject.mapping_version
setAccessTransformers(rootProject.access_transformers)
}
dependencies {
minecraft "net.minecraftforge:forge:" + mc_version + "-" + forge_version
implementation rootProject
implementation project(":system")
implementation project(":util")
}
jar {
manifest {
attributes([
"FMLModType": "LIBRARY"
])
}
}

View File

@ -0,0 +1,143 @@
package chylex.hee.client
import chylex.hee.client.render.RenderStateBuilder
import chylex.hee.client.render.util.DF_ONE
import chylex.hee.client.render.util.DF_ZERO
import chylex.hee.client.render.util.SF_ONE_MINUS_SRC_ALPHA
import chylex.hee.client.render.util.SF_SRC_ALPHA
import chylex.hee.client.util.MC
import chylex.hee.game.item.util.nbtOrNull
import chylex.hee.game.world.util.floodFill
import chylex.hee.game.world.util.getBlock
import chylex.hee.game.world.util.getState
import chylex.hee.game.world.util.isAir
import chylex.hee.game.world.util.removeBlock
import chylex.hee.game.world.util.setState
import chylex.hee.util.nbt.hasKey
import net.minecraft.block.BlockState
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.BlockItem
import net.minecraft.item.Items
import net.minecraft.util.Direction
import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Direction.EAST
import net.minecraft.util.Direction.NORTH
import net.minecraft.util.Direction.SOUTH
import net.minecraft.util.Direction.UP
import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand.MAIN_HAND
import net.minecraft.util.Hand.OFF_HAND
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.world.IWorld
import net.minecraftforge.client.event.DrawHighlightEvent
import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock
import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock
import net.minecraftforge.event.world.BlockEvent.BreakEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import org.lwjgl.opengl.GL11
object BuildStick {
private val RENDER_TYPE_LINE = with(RenderStateBuilder()) {
line(2.25)
blend(SF_SRC_ALPHA, DF_ONE, SF_ONE_MINUS_SRC_ALPHA, DF_ZERO)
layering(RenderStateBuilder.LAYERING_OFFSET_Z)
mask(RenderStateBuilder.MASK_COLOR)
buildType("hee:debug_line", DefaultVertexFormats.POSITION_COLOR, GL11.GL_LINES, bufferSize = 256)
}
private fun isHoldingBuildStick(player: PlayerEntity): Boolean {
val heldItem = player.getHeldItem(MAIN_HAND)
return heldItem.item === Items.STICK && heldItem.nbtOrNull.hasKey("HEE_BUILD")
}
private fun getBuildStickBlocks(world: IWorld, pos: BlockPos, state: BlockState, face: Direction): List<BlockPos> {
val floodFaces = when (face) {
UP, DOWN -> listOf(NORTH, SOUTH, EAST, WEST)
NORTH, SOUTH -> listOf(UP, DOWN, EAST, WEST)
EAST, WEST -> listOf(UP, DOWN, NORTH, SOUTH)
else -> emptyList()
}
val limit = 1000
val block = state.block
return pos.floodFill(floodFaces, limit) { it.getBlock(world) === block }.takeIf { it.size < limit }.orEmpty()
}
private var lastLeftClickHit: BlockRayTraceResult? = null
@SubscribeEvent
fun onLeftClickBlock(e: LeftClickBlock) {
val world = e.world
if (isHoldingBuildStick(e.player) && !world.isRemote) {
lastLeftClickHit = MC.instance.objectMouseOver as? BlockRayTraceResult
}
}
@SubscribeEvent
fun onBlockBreak(e: BreakEvent) {
val world = e.world
if (isHoldingBuildStick(e.player) && !world.isRemote) {
val hit = lastLeftClickHit ?: return
for (pos in getBuildStickBlocks(world, e.pos, e.state, hit.face)) {
pos.removeBlock(world)
}
}
}
@SubscribeEvent
fun onRightClickBlock(e: RightClickBlock) {
val world = e.world
val player = e.player
if (isHoldingBuildStick(player) && !world.isRemote) {
val state = e.pos.getState(world)
val face = e.face!!
val place = (player.getHeldItem(OFF_HAND).item as? BlockItem)?.block?.defaultState ?: state
for (pos in getBuildStickBlocks(world, e.pos, state, face)) {
val offset = pos.offset(face)
if (offset.isAir(world)) {
offset.setState(world, place)
}
}
}
}
@SubscribeEvent
fun onRenderOverlay(e: DrawHighlightEvent.HighlightBlock) {
val player = MC.player!!
if (isHoldingBuildStick(player)) {
val hit = MC.instance.objectMouseOver as? BlockRayTraceResult ?: return
val world = player.world
val center = hit.pos
val info = e.info
val matrix = e.matrix.last.matrix
val builder = e.buffers.getBuffer(RENDER_TYPE_LINE)
for (pos in getBuildStickBlocks(world, center, center.getState(world), hit.face)) {
val x = pos.x - info.projectedView.x
val y = pos.y - info.projectedView.y
val z = pos.z - info.projectedView.z
val shape = pos.getState(world).getShape(world, pos, ISelectionContext.forEntity(info.renderViewEntity))
shape.forEachEdge { x1, y1, z1, x2, y2, z2 ->
builder.pos(matrix, (x1 + x).toFloat(), (y1 + y).toFloat(), (z1 + z).toFloat()).color(1F, 1F, 1F, 1F).endVertex()
builder.pos(matrix, (x2 + x).toFloat(), (y2 + y).toFloat(), (z2 + z).toFloat()).color(1F, 1F, 1F, 1F).endVertex()
}
}
e.isCanceled = true
}
}
}

View File

@ -0,0 +1,42 @@
package chylex.hee.client
import chylex.hee.client.util.MC
import chylex.hee.debug.benchmark.TerritoryGenerationBenchmarkScreen
import chylex.hee.util.color.RGB
import com.mojang.blaze3d.matrix.MatrixStack
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.widget.button.Button
import net.minecraft.util.text.StringTextComponent
import net.minecraftforge.client.event.InputEvent.KeyInputEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import org.lwjgl.glfw.GLFW
object DebugMenu {
@SubscribeEvent
fun onKeyPressed(e: KeyInputEvent) {
if (e.action != GLFW.GLFW_RELEASE) {
return
}
if (e.key == GLFW.GLFW_KEY_F12) {
MC.instance.displayGuiScreen(DebugMenuScreen(MC.currentScreen))
}
}
private class DebugMenuScreen(private val parentScreen: Screen?) : Screen(StringTextComponent("HEE 2 Debug")) {
override fun init() {
addButton(Button(width / 2 - 100, 36, 200, 20, StringTextComponent("Territory Generation Benchmark")) { MC.instance.displayGuiScreen(TerritoryGenerationBenchmarkScreen(this)) })
addButton(Button(width / 2 - 100, height - 40, 200, 20, StringTextComponent("Close")) { closeScreen() })
}
override fun render(matrix: MatrixStack, mouseX: Int, mouseY: Int, partialTicks: Float) {
renderBackground(matrix)
drawCenteredString(matrix, font, title, width / 2, 15, RGB(255u).i)
super.render(matrix, mouseX, mouseY, partialTicks)
}
override fun closeScreen() {
MC.instance.displayGuiScreen(parentScreen)
}
}
}

View File

@ -0,0 +1,27 @@
package chylex.hee.client
import chylex.hee.client.util.MC
import net.minecraftforge.client.event.InputEvent.KeyInputEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import org.lwjgl.glfw.GLFW
object GameModeToggle {
@SubscribeEvent
fun onKeyPressed(e: KeyInputEvent) {
if (e.action != GLFW.GLFW_PRESS) {
return
}
if (e.key == GLFW.GLFW_KEY_GRAVE_ACCENT) {
val player = MC.player ?: return
if (player.isCreative) {
val ctrl = (e.modifiers and GLFW.GLFW_MOD_CONTROL) != 0
player.sendChatMessage(if (ctrl) "/gamemode spectator" else "/gamemode survival")
}
else {
player.sendChatMessage("/gamemode creative")
}
}
}
}

View File

@ -0,0 +1,19 @@
package chylex.hee.client
import chylex.hee.client.render.TerritoryRenderer
import chylex.hee.client.util.MC
import chylex.hee.game.world.isInEndDimension
import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
object TerritoryVoidDebug {
@SubscribeEvent
fun onRenderGameOverlayText(e: RenderGameOverlayEvent.Text) {
if (MC.settings.showDebugInfo && MC.player?.isInEndDimension == true) {
with(e.left) {
add("")
add("End Void Factor: ${"%.3f".format(TerritoryRenderer.currentVoidFactor)}")
}
}
}
}

View File

@ -0,0 +1,74 @@
package chylex.hee.debug
import chylex.hee.HEE
import chylex.hee.client.BuildStick
import chylex.hee.client.DebugMenu
import chylex.hee.client.GameModeToggle
import chylex.hee.client.TerritoryVoidDebug
import chylex.hee.game.block.BlockScaffoldingDebug
import chylex.hee.game.block.HeeBlock
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.command.client.CommandClientDebugToggles
import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.command.server.CommandServerInstability
import chylex.hee.game.command.server.CommandServerStructure
import chylex.hee.game.command.server.CommandServerTerritory
import chylex.hee.game.command.server.CommandServerTestWorld
import chylex.hee.system.IDebugModule
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import chylex.hee.util.forge.SubscribeAllEvents
import chylex.hee.util.forge.SubscribeEvent
import net.minecraftforge.client.event.GuiOpenEvent
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent
@SubscribeAllEvents(modid = HEE.ID, bus = MOD)
internal object Debug : IDebugModule {
init {
HEE.debug = true
HEE.debugModule = this
}
override val clientCommands
get() = listOf(
CommandClientScaffolding,
CommandClientDebugToggles
)
override val serverCommands
get() = listOf(
CommandServerInstability,
CommandServerStructure,
CommandServerTerritory,
CommandServerTestWorld
)
override fun createScaffoldingBlock(builder: BlockBuilder): HeeBlock {
return BlockScaffoldingDebug(builder)
}
@SubscribeEvent
fun onClientSetup(@Suppress("UNUSED_PARAMETER") e: FMLClientSetupEvent) {
initializeClient()
}
@Sided(Side.CLIENT)
private fun initializeClient() {
if (HEE.debug) {
MinecraftForge.EVENT_BUS.register(DebugMenu)
MinecraftForge.EVENT_BUS.register(BuildStick)
MinecraftForge.EVENT_BUS.register(GameModeToggle)
MinecraftForge.EVENT_BUS.register(TerritoryVoidDebug)
MinecraftForge.EVENT_BUS.register(object : Any() {
@SubscribeEvent
fun onGuiOpen(@Suppress("UNUSED_PARAMETER") e: GuiOpenEvent) {
PowerShell.maximizeWindow()
MinecraftForge.EVENT_BUS.unregister(this)
}
})
}
}
}

View File

@ -0,0 +1,26 @@
package chylex.hee.debug
import chylex.hee.game.Environment
import chylex.hee.util.forge.Side
import org.apache.commons.lang3.SystemUtils
import java.io.File
import java.lang.management.ManagementFactory
internal object PowerShell {
private fun canExecutePowershell(scriptName: String): Boolean {
return SystemUtils.IS_OS_WINDOWS && Environment.side == Side.CLIENT && File(scriptName).exists()
}
fun setClipboardContents(file: File) {
if (canExecutePowershell("filecopy.ps1")) {
ProcessBuilder("powershell.exe", "-ExecutionPolicy", "Unrestricted", "-Sta", "-File", "filecopy.ps1", file.absolutePath).start()
}
}
fun maximizeWindow() {
if (canExecutePowershell("maximize.ps1")) {
val pid = ManagementFactory.getRuntimeMXBean().name.split("@")[0]
ProcessBuilder("powershell.exe", "-ExecutionPolicy", "Unrestricted", "-File", "maximize.ps1", pid).start()
}
}
}

View File

@ -0,0 +1,80 @@
package chylex.hee.debug.benchmark
import chylex.hee.HEE
import chylex.hee.client.util.MC
import chylex.hee.game.Environment
import chylex.hee.game.territory.TerritoryType
import chylex.hee.game.world.generation.structure.world.SegmentedWorld
import chylex.hee.util.color.RGB
import com.mojang.blaze3d.matrix.MatrixStack
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.widget.button.Button
import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World
import java.util.Random
class TerritoryGenerationBenchmarkScreen(private val parentScreen: Screen) : Screen(StringTextComponent("Territory Generation Benchmark")) {
private val generated = mutableListOf<SegmentedWorld>()
override fun init() {
try {
Environment.getDimension(World.OVERWORLD)
} catch (e: NullPointerException) {
println("Must be in a world!")
closeScreen()
return
}
val x = width / 2 - 100
addButton(Button(x, 36, 200, 20, StringTextComponent("(All)")) { runAll() })
for ((index, territory) in TerritoryType.ALL.withIndex()) {
val y = 36 + (22 * (index + 1))
addButton(Button(x, y, 200, 20, TranslationTextComponent(territory.translationKey)) { runOnce(territory) })
}
addButton(Button(x, height - 40, 200, 20, StringTextComponent("Close")) { closeScreen() })
}
override fun render(matrix: MatrixStack, mouseX: Int, mouseY: Int, partialTicks: Float) {
renderBackground(matrix)
drawCenteredString(matrix, font, title, width / 2, 15, RGB(255u).i)
super.render(matrix, mouseX, mouseY, partialTicks)
}
override fun closeScreen() {
MC.instance.displayGuiScreen(parentScreen)
}
private fun runAll() {
generated.clear()
for (territory in TerritoryType.ALL) {
if (territory.gen === TerritoryType.Companion.GeneratorDummy) {
continue
}
for (seed in 0L until 5L) {
runImpl(territory, seed)
}
}
HEE.log.info("[TerritoryGenerationBenchmarkScreen] done!")
}
private fun runOnce(territory: TerritoryType) {
generated.clear()
runImpl(territory, 0L)
}
private fun runImpl(territory: TerritoryType, seed: Long) {
HEE.log.info("[TerritoryGenerationBenchmarkScreen] generating " + territory.name)
val timeStart = System.currentTimeMillis()
generated.add(territory.generate(Random(seed)).first)
val timeEnd = System.currentTimeMillis()
HEE.log.info("[TerritoryGenerationBenchmarkScreen] finished in ${timeEnd - timeStart} ms")
}
}

View File

@ -0,0 +1,103 @@
package chylex.hee.game.block
import chylex.hee.debug.PowerShell
import chylex.hee.game.Environment
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.world.generation.structure.file.StructureFile
import chylex.hee.game.world.generation.util.WorldToStructureWorldAdapter
import chylex.hee.game.world.util.getBlock
import chylex.hee.game.world.util.offsetUntilExcept
import chylex.hee.util.math.BoundingBox
import chylex.hee.util.math.Pos
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.nbt.CompressedStreamTools
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.FAIL
import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.Direction
import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Direction.EAST
import net.minecraft.util.Direction.NORTH
import net.minecraft.util.Direction.SOUTH
import net.minecraft.util.Direction.UP
import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand
import net.minecraft.util.Util
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TextFormatting
import net.minecraft.world.World
import java.nio.file.Files
class BlockScaffoldingDebug(builder: BlockBuilder) : BlockScaffolding(builder) {
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
if (world.isRemote && player.isSneaking && !player.abilities.isFlying) {
val palette = CommandClientScaffolding.currentPalette
if (palette == null) {
player.sendMessage(StringTextComponent("No structure set."), Util.DUMMY_UUID)
return FAIL
}
val minPos = findMinPos(world, pos)?.let { findMinPos(world, it) } // double pass to find min from any side
val maxPos = minPos?.let { findMaxPos(world, it) }
if (minPos == null || maxPos == null) {
player.sendMessage(StringTextComponent("Could not find structure boundaries."), Util.DUMMY_UUID)
return FAIL
}
val box = BoundingBox(minPos, maxPos)
val serverWorld = Environment.getDimension(world.dimensionKey)
val (structureTag, missingMappings) = StructureFile.save(WorldToStructureWorldAdapter(serverWorld, serverWorld.rand, box.min), box.size, palette, this)
val structureFile = Files.createTempDirectory("HardcoreEnderExpansion_Structure_").resolve(CommandClientScaffolding.currentFile).toFile()
CompressedStreamTools.write(structureTag, structureFile)
PowerShell.setClipboardContents(structureFile)
if (missingMappings.isNotEmpty()) {
player.sendMessage(StringTextComponent("Missing mappings for states:"), Util.DUMMY_UUID)
for (missingMapping in missingMappings) {
player.sendMessage(StringTextComponent(" - ${TextFormatting.GRAY}$missingMapping"), Util.DUMMY_UUID)
}
}
player.sendMessage(StringTextComponent("Generated structure file of ${box.size}."), Util.DUMMY_UUID)
return SUCCESS
}
return FAIL
}
// Helpers
private fun find(world: World, pos: BlockPos?, direction: Direction): BlockPos? {
return pos?.offsetUntilExcept(direction, 0..255) { it.getBlock(world) === Blocks.AIR }
}
private fun findMinPos(world: World, pos: BlockPos): BlockPos? {
val bottomPos = find(world, pos, DOWN)
val y = bottomPos?.y
val x = find(world, bottomPos, WEST)?.x
val z = find(world, bottomPos, NORTH)?.z
return if (x == null || y == null || z == null) null else Pos(x, y, z)
}
private fun findMaxPos(world: World, pos: BlockPos): BlockPos? {
val topPos = find(world, pos, UP)
val y = topPos?.y
val x = find(world, topPos, EAST)?.x
val z = find(world, topPos, SOUTH)?.z
return if (x == null || y == null || z == null) null else Pos(x, y, z)
}
}

View File

@ -1,13 +1,13 @@
package chylex.hee.game.command.client
import chylex.hee.client.render.TerritoryRenderer
import chylex.hee.game.block.BlockScaffolding
import chylex.hee.game.command.IClientCommand
import chylex.hee.game.territory.TerritoryVoid
import chylex.hee.init.ModBlocks
import net.minecraft.command.CommandSource
import net.minecraft.util.text.StringTextComponent
object CommandDebugToggles : IClientCommand {
object CommandClientDebugToggles : IClientCommand {
override val name = "debug"
override val description = "access to debug toggles"
@ -23,8 +23,8 @@ object CommandDebugToggles : IClientCommand {
sender.sendFeedback(StringTextComponent("Territory debugging ${if (debug) "enabled" else "disabled"}."), false)
}
else if (name == "scaffolding") {
ModBlocks.SCAFFOLDING.enableShape = !ModBlocks.SCAFFOLDING.enableShape
sender.sendFeedback(StringTextComponent("Scaffolding shape ${if (ModBlocks.SCAFFOLDING.enableShape) "enabled" else "disabled"}."), false)
BlockScaffolding.enableShape = !BlockScaffolding.enableShape
sender.sendFeedback(StringTextComponent("Scaffolding shape ${if (BlockScaffolding.enableShape) "enabled" else "disabled"}."), false)
}
}
}

View File

@ -1,7 +1,7 @@
package chylex.hee.game.command.client
import chylex.hee.game.command.IClientCommand
import chylex.hee.game.command.server.CommandDebugStructure
import chylex.hee.game.command.server.CommandServerStructure
import net.minecraft.command.CommandSource
import net.minecraft.util.text.StringTextComponent
import java.util.prefs.Preferences
@ -14,7 +14,7 @@ object CommandClientScaffolding : IClientCommand {
get() = Preferences.userRoot().node("chylex-hee-scaffolding")
val currentPalette
get() = data.get("Structure", null)?.let(CommandDebugStructure.structureDescriptions::get)?.PALETTE
get() = data.get("Structure", null)?.let(CommandServerStructure.structureDescriptions::get)?.PALETTE
val currentFile
get() = data.get("File", "")!!.ifBlank { "structure.nbt" }
@ -22,7 +22,7 @@ object CommandClientScaffolding : IClientCommand {
override fun executeCommand(sender: CommandSource, args: Array<String>) {
val structure = args.getOrNull(0) ?: return
if (!CommandDebugStructure.structureDescriptions.containsKey(structure)) {
if (!CommandServerStructure.structureDescriptions.containsKey(structure)) {
sender.sendFeedback(StringTextComponent("Unknown structure."), false)
return
}

View File

@ -15,7 +15,7 @@ import net.minecraft.command.Commands.argument
import net.minecraft.command.Commands.literal
import net.minecraft.util.text.StringTextComponent
object CommandDebugInstability : ICommand {
object CommandServerInstability : ICommand {
override val name = "instability"
override val description = "utilities for instability"

View File

@ -31,7 +31,7 @@ import net.minecraft.util.Rotation
import net.minecraft.util.text.StringTextComponent
import java.util.Random
object CommandDebugStructure : ICommand {
object CommandServerStructure : ICommand {
val structureDescriptions = mapOf(
"stronghold" to StrongholdPieces,
"energyshrine" to EnergyShrinePieces,

View File

@ -23,7 +23,7 @@ import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.text.StringTextComponent
import java.util.Random
object CommandDebugTerritory : ICommand {
object CommandServerTerritory : ICommand {
override val name = "territory"
override val description = "utilities for territories"

View File

@ -7,7 +7,7 @@ import com.mojang.brigadier.builder.ArgumentBuilder
import com.mojang.brigadier.context.CommandContext
import net.minecraft.command.CommandSource
object CommandDebugTestWorld : ICommand, CommandExecutionFunction {
object CommandServerTestWorld : ICommand, CommandExecutionFunction {
override val name = "testworld"
override val description = "converts overworld into a test world"

View File

@ -0,0 +1,7 @@
{
"pack": {
"description": "Hardcore Ender Expansion 2 (Debug Library)",
"pack_format": 6,
"_comment": ""
}
}

View File

@ -1,6 +1,7 @@
package chylex.hee
import chylex.hee.game.Resource
import chylex.hee.system.IDebugModule
import net.minecraft.util.RegistryKey
import net.minecraft.util.registry.Registry
import net.minecraft.world.World
@ -12,6 +13,10 @@ object HEE {
lateinit var version: String
@JvmField
var debug = false
var debugModule: IDebugModule? = null
val log: Logger = LogManager.getLogger("HardcoreEnderExpansion")
val dim: RegistryKey<World> = RegistryKey.getOrCreateKey(Registry.WORLD_KEY, Resource.Custom("end"))
}

View File

@ -1,5 +1,7 @@
package chylex.hee.game.world.generation.noise
import chylex.hee.util.math.FloatRange
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import kotlin.math.abs
import kotlin.math.pow
@ -26,12 +28,12 @@ class NoiseValue(var value: Double) {
it.coerceIn(minimum, maximum)
}
fun remap(oldRange: ClosedFloatingPointRange<Double>, newRange: ClosedFloatingPointRange<Double>) = then {
fun remap(oldRange: FloatRange, newRange: FloatRange) = then {
remapRange(it, oldRange, newRange)
}
fun remap(newRange: ClosedFloatingPointRange<Double>) = then {
remapRange(it, (0.0)..(1.0), newRange)
fun remap(newRange: FloatRange) = then {
remapRange(it, range(0F, 1F), newRange)
}
inline fun ifNonZero(block: NoiseValue.() -> Unit) {

View File

@ -7,7 +7,6 @@ import chylex.hee.game.world.generation.structure.piece.IStructurePieceConnectio
import chylex.hee.game.world.generation.structure.piece.StructureBuild.AddMode.APPEND
import chylex.hee.game.world.generation.structure.piece.StructureBuild.AddMode.MERGE
import chylex.hee.game.world.generation.structure.world.OffsetStructureWorld
import chylex.hee.system.Debug
import chylex.hee.util.math.Size
import net.minecraft.util.math.BlockPos
@ -83,7 +82,7 @@ class StructureBuild<T : StructurePiece<*>.MutableInstance>(val size: Size) {
* [MERGE] mode allows intersection with [targetPiece] but no other pieces.
*/
fun addPiece(newPiece: T, newPieceConnection: IStructurePieceConnection, targetPiece: PositionedPiece<T>, targetPieceConnection: IStructurePieceConnection, mode: AddMode = APPEND): PositionedPiece<T>? {
if (Debug.enabled && !pieces.contains(targetPiece)) {
if (HEE.debug && !pieces.contains(targetPiece)) {
HEE.log.error("[StructureBuild] attempted to connect to a piece that is not present in the structure")
}

View File

@ -6,59 +6,67 @@ import chylex.hee.game.world.generation.structure.IStructureWorld
import chylex.hee.game.world.generation.structure.world.segments.ISegment
import chylex.hee.game.world.generation.structure.world.segments.ISegment.Companion.index
import chylex.hee.game.world.util.Transform
import chylex.hee.system.Debug
import chylex.hee.util.math.Pos
import chylex.hee.util.math.Size
import chylex.hee.util.math.ceilToInt
import chylex.hee.util.math.component1
import chylex.hee.util.math.component2
import chylex.hee.util.math.component3
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.util.math.BlockPos
import java.util.Random
open class SegmentedWorld(override val rand: Random, val worldSize: Size, private val segmentSize: Size, defaultSegmentFactory: (Size) -> ISegment) : IStructureWorld {
open class SegmentedWorld(override val rand: Random, val worldSize: Size, segmentSize: Size, defaultSegmentFactory: (Size) -> ISegment) : IStructureWorld {
private val segmentSizeX = segmentSize.x
private val segmentSizeY = segmentSize.y
private val segmentSizeZ = segmentSize.z
private val segmentCounts = Size(
(worldSize.x.toFloat() / segmentSize.x).ceilToInt(),
(worldSize.y.toFloat() / segmentSize.y).ceilToInt(),
(worldSize.z.toFloat() / segmentSize.z).ceilToInt()
(worldSize.x.toFloat() / segmentSizeX).ceilToInt(),
(worldSize.y.toFloat() / segmentSizeY).ceilToInt(),
(worldSize.z.toFloat() / segmentSizeZ).ceilToInt()
)
private val segments = Array(segmentCounts.x * segmentCounts.y * segmentCounts.z) { defaultSegmentFactory(segmentSize) }
private val triggers = mutableListOf<Pair<BlockPos, IStructureTrigger>>()
private fun mapPos(pos: BlockPos): Pair<Int, BlockPos>? {
if (!isInside(pos)) {
HEE.log.warn("[SegmentedWorld] attempted to access position outside bounds: $pos is outside $worldSize")
if (Debug.enabled) {
Thread.dumpStack()
}
return null
}
val (x, y, z) = pos
val (sizeX, sizeY, sizeZ) = segmentSize
val segmentIndex = index(x / sizeX, y / sizeY, z / sizeZ, segmentCounts)
val segmentOffset = Pos(x % sizeX, y % sizeY, z % sizeZ)
return Pair(segmentIndex, segmentOffset)
private fun getSegmentIndex(pos: BlockPos): Int {
return index(pos.x / segmentSizeX, pos.y / segmentSizeY, pos.z / segmentSizeZ, segmentCounts)
}
private fun getSegmentOffset(pos: BlockPos): BlockPos {
return Pos(pos.x % segmentSizeX, pos.y % segmentSizeY, pos.z % segmentSizeZ)
}
fun isInside(pos: BlockPos): Boolean {
return pos.x in 0..worldSize.maxX && pos.y in 0..worldSize.maxY && pos.z in 0..worldSize.maxZ
}
private fun warnNotInside(pos: BlockPos) {
HEE.log.warn("[SegmentedWorld] attempted to access position outside bounds: $pos is outside $worldSize")
if (HEE.debug) {
Thread.dumpStack()
}
}
override fun getState(pos: BlockPos): BlockState {
val (segmentIndex, segmentOffset) = mapPos(pos) ?: return Blocks.AIR.defaultState
if (!isInside(pos)) {
warnNotInside(pos)
return Blocks.AIR.defaultState
}
val segmentIndex = getSegmentIndex(pos)
val segmentOffset = getSegmentOffset(pos)
return segments[segmentIndex].getState(segmentOffset)
}
override fun setState(pos: BlockPos, state: BlockState) {
val (segmentIndex, segmentOffset) = mapPos(pos) ?: return
if (!isInside(pos)) {
warnNotInside(pos)
return
}
val segmentIndex = getSegmentIndex(pos)
val segmentOffset = getSegmentOffset(pos)
segments[segmentIndex] = segments[segmentIndex].withState(segmentOffset, state)
}

View File

@ -1,11 +1,26 @@
package chylex.hee.game.world.generation.structure.world.segments
import chylex.hee.game.world.generation.structure.world.segments.ISegment.Companion.index
import chylex.hee.util.math.MutablePos
import chylex.hee.util.math.Size
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
/**
* A segment that supports arbitrary block states in arbitrary positions.
*/
class SegmentFull(private val size: Size, fillState: BlockState) : ISegment {
constructor(size: Size, fillState: BlockState, posToStateMap: Long2ObjectOpenHashMap<BlockState>) : this(size, fillState) {
val pos = MutablePos()
val iter = posToStateMap.long2ObjectEntrySet().fastIterator()
while (iter.hasNext()) {
val entry = iter.next()
pos.setPos(entry.longKey)
data[index(pos, size)] = entry.value
}
}
private val data = Array(size.x * size.y * size.z) { fillState }
override fun getState(pos: BlockPos): BlockState {

View File

@ -0,0 +1,42 @@
package chylex.hee.game.world.generation.structure.world.segments
import chylex.hee.util.math.Size
import chylex.hee.util.math.floorToInt
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import kotlin.math.pow
/**
* A segment mostly filled with one type of block state, but allowing for a few [exceptions].
* When the amount of exceptions reaches a [threshold] based on the segment size, it gets converted to [SegmentFull].
*/
class SegmentMultiState(private val size: Size, private val fillState: BlockState) : ISegment {
constructor(size: Size, block: Block) : this(size, block.defaultState)
/**
* The threshold power was determined by careful experimentation and profiling.
*/
private val threshold = (size.x * size.y * size.z).toDouble().pow(0.69).floorToInt()
private val exceptions = Long2ObjectOpenHashMap<BlockState>(threshold, 0.75F).apply { defaultReturnValue(fillState) }
override fun getState(pos: BlockPos): BlockState {
return exceptions.get(pos.toLong())
}
override fun withState(pos: BlockPos, state: BlockState): ISegment {
if (state == fillState) {
exceptions.remove(pos.toLong())
return this
}
@Suppress("ReplacePutWithAssignment")
exceptions.put(pos.toLong(), state) // kotlin indexer boxes the values
return if (exceptions.size < threshold)
this
else
SegmentFull(size, fillState, exceptions)
}
}

View File

@ -5,6 +5,10 @@ import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
/**
* A segment completely filled with only one type of block state.
* When any block state is changed, gets converted to [SegmentMultiState].
*/
class SegmentSingleState(private val size: Size, private val fillState: BlockState) : ISegment {
constructor(size: Size, block: Block) : this(size, block.defaultState)
@ -16,6 +20,6 @@ class SegmentSingleState(private val size: Size, private val fillState: BlockSta
return if (state == fillState)
this
else
SegmentFull(size, fillState).withState(pos, state)
SegmentMultiState(size, fillState).withState(pos, state)
}
}

View File

@ -1,206 +0,0 @@
package chylex.hee.system
import chylex.hee.client.render.RenderStateBuilder
import chylex.hee.client.render.RenderStateBuilder.Companion.LAYERING_OFFSET_Z
import chylex.hee.client.render.RenderStateBuilder.Companion.MASK_COLOR
import chylex.hee.client.render.util.DF_ONE
import chylex.hee.client.render.util.DF_ZERO
import chylex.hee.client.render.util.SF_ONE_MINUS_SRC_ALPHA
import chylex.hee.client.render.util.SF_SRC_ALPHA
import chylex.hee.client.util.MC
import chylex.hee.game.Environment
import chylex.hee.game.item.util.nbtOrNull
import chylex.hee.game.world.util.floodFill
import chylex.hee.game.world.util.getBlock
import chylex.hee.game.world.util.getState
import chylex.hee.game.world.util.isAir
import chylex.hee.game.world.util.removeBlock
import chylex.hee.game.world.util.setState
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import chylex.hee.util.forge.SubscribeEvent
import chylex.hee.util.nbt.hasKey
import net.minecraft.block.BlockState
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.BlockItem
import net.minecraft.item.Items
import net.minecraft.util.Direction
import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Direction.EAST
import net.minecraft.util.Direction.NORTH
import net.minecraft.util.Direction.SOUTH
import net.minecraft.util.Direction.UP
import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand.MAIN_HAND
import net.minecraft.util.Hand.OFF_HAND
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.world.IWorld
import net.minecraftforge.client.event.DrawHighlightEvent
import net.minecraftforge.client.event.GuiOpenEvent
import net.minecraftforge.client.event.InputEvent.KeyInputEvent
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock
import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock
import net.minecraftforge.event.world.BlockEvent.BreakEvent
import org.apache.commons.lang3.SystemUtils
import org.lwjgl.glfw.GLFW
import org.lwjgl.opengl.GL11
import java.io.File
import java.lang.management.ManagementFactory
object Debug {
@JvmField
val enabled = System.getProperty("hee.debug") != null
@Sided(Side.CLIENT)
fun initializeClient() {
if (enabled) {
MinecraftForge.EVENT_BUS.register(object : Any() {
@SubscribeEvent
fun onKeyPressed(e: KeyInputEvent) {
if (e.action != GLFW.GLFW_PRESS) {
return
}
if (e.key == GLFW.GLFW_KEY_GRAVE_ACCENT) {
val player = MC.player ?: return
if (player.isCreative) {
val ctrl = (e.modifiers and GLFW.GLFW_MOD_CONTROL) != 0
player.sendChatMessage(if (ctrl) "/gamemode spectator" else "/gamemode survival")
}
else {
player.sendChatMessage("/gamemode creative")
}
}
}
private fun isHoldingBuildStick(player: PlayerEntity): Boolean {
val heldItem = player.getHeldItem(MAIN_HAND)
return heldItem.item === Items.STICK && heldItem.nbtOrNull.hasKey("HEE_BUILD")
}
private fun getBuildStickBlocks(world: IWorld, pos: BlockPos, state: BlockState, face: Direction): List<BlockPos> {
val floodFaces = when (face) {
UP, DOWN -> listOf(NORTH, SOUTH, EAST, WEST)
NORTH, SOUTH -> listOf(UP, DOWN, EAST, WEST)
EAST, WEST -> listOf(UP, DOWN, NORTH, SOUTH)
else -> emptyList()
}
val limit = 1000
val block = state.block
return pos.floodFill(floodFaces, limit) { it.getBlock(world) === block }.takeIf { it.size < limit }.orEmpty()
}
private var lastLeftClickHit: BlockRayTraceResult? = null
@SubscribeEvent
fun onLeftClickBlock(e: LeftClickBlock) {
val world = e.world
if (isHoldingBuildStick(e.player) && !world.isRemote) {
lastLeftClickHit = MC.instance.objectMouseOver as? BlockRayTraceResult
}
}
@SubscribeEvent
fun onBlockBreak(e: BreakEvent) {
val world = e.world
if (isHoldingBuildStick(e.player) && !world.isRemote) {
val hit = lastLeftClickHit ?: return
for (pos in getBuildStickBlocks(world, e.pos, e.state, hit.face)) {
pos.removeBlock(world)
}
}
}
@SubscribeEvent
fun onRightClickBlock(e: RightClickBlock) {
val world = e.world
val player = e.player
if (isHoldingBuildStick(player) && !world.isRemote) {
val state = e.pos.getState(world)
val face = e.face!!
val place = (player.getHeldItem(OFF_HAND).item as? BlockItem)?.block?.defaultState ?: state
for (pos in getBuildStickBlocks(world, e.pos, state, face)) {
val offset = pos.offset(face)
if (offset.isAir(world)) {
offset.setState(world, place)
}
}
}
}
private val RENDER_TYPE_LINE = with(RenderStateBuilder()) {
line(2.25)
blend(SF_SRC_ALPHA, DF_ONE, SF_ONE_MINUS_SRC_ALPHA, DF_ZERO)
layering(LAYERING_OFFSET_Z)
mask(MASK_COLOR)
buildType("hee:debug_line", DefaultVertexFormats.POSITION_COLOR, GL11.GL_LINES, bufferSize = 256)
}
@SubscribeEvent
fun onRenderOverlay(e: DrawHighlightEvent.HighlightBlock) {
val player = MC.player!!
if (isHoldingBuildStick(player)) {
val hit = MC.instance.objectMouseOver as? BlockRayTraceResult ?: return
val world = player.world
val center = hit.pos
val info = e.info
val matrix = e.matrix.last.matrix
val builder = e.buffers.getBuffer(RENDER_TYPE_LINE)
for (pos in getBuildStickBlocks(world, center, center.getState(world), hit.face)) {
val x = pos.x - info.projectedView.x
val y = pos.y - info.projectedView.y
val z = pos.z - info.projectedView.z
val shape = pos.getState(world).getShape(world, pos, ISelectionContext.forEntity(info.renderViewEntity))
shape.forEachEdge { x1, y1, z1, x2, y2, z2 ->
builder.pos(matrix, (x1 + x).toFloat(), (y1 + y).toFloat(), (z1 + z).toFloat()).color(1F, 1F, 1F, 1F).endVertex()
builder.pos(matrix, (x2 + x).toFloat(), (y2 + y).toFloat(), (z2 + z).toFloat()).color(1F, 1F, 1F, 1F).endVertex()
}
}
e.isCanceled = true
}
}
})
if (canExecutePowershell("maximize.ps1")) {
MinecraftForge.EVENT_BUS.register(object : Any() {
@SubscribeEvent
fun onGuiOpen(@Suppress("UNUSED_PARAMETER") e: GuiOpenEvent) {
val pid = ManagementFactory.getRuntimeMXBean().name.split("@")[0]
ProcessBuilder("powershell.exe", "-ExecutionPolicy", "Unrestricted", "-File", "maximize.ps1", pid).start()
MinecraftForge.EVENT_BUS.unregister(this)
}
})
}
}
}
fun setClipboardContents(file: File) {
if (canExecutePowershell("filecopy.ps1")) {
ProcessBuilder("powershell.exe", "-ExecutionPolicy", "Unrestricted", "-Sta", "-File", "filecopy.ps1", file.absolutePath).start()
}
}
private fun canExecutePowershell(scriptName: String): Boolean {
return SystemUtils.IS_OS_WINDOWS && Environment.side == Side.CLIENT && File(scriptName).exists()
}
}

View File

@ -0,0 +1,13 @@
package chylex.hee.system
import chylex.hee.game.block.HeeBlock
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.command.IClientCommand
import chylex.hee.game.command.ICommand
interface IDebugModule {
val clientCommands: List<IClientCommand>
val serverCommands: List<ICommand>
fun createScaffoldingBlock(builder: BlockBuilder): HeeBlock
}

View File

@ -19,7 +19,7 @@ object MinecraftForgeEventBus {
}
for (listener in item.javaClass.methods.filter { !Modifier.isStatic(it.modifiers) && it.isAnnotationPresent(SubscribeEvent::class.java) }) {
if (Debug.enabled) {
if (HEE.debug) {
HEE.log.info("[MinecraftForgeEventBus] registering ${listener.parameterTypes.firstOrNull()?.name?.substringAfterLast('.')} for ${item.javaClass.simpleName}")
}

View File

@ -48,15 +48,15 @@ fun lerp(from: Double, to: Double, progress: Double): Double {
/**
* Maps a range of values in [from] range to values in [to] range using linear interpolation.
*/
fun remapRange(value: Float, from: ClosedFloatingPointRange<Float>, to: ClosedFloatingPointRange<Float>): Float {
val remappedBetween0And1 = (value - from.start) / (from.endInclusive - from.start)
return to.start + remappedBetween0And1 * (to.endInclusive - to.start)
fun remapRange(value: Float, from: FloatRange, to: FloatRange): Float {
val remappedBetween0And1 = (value - from.start) / (from.end - from.start)
return to.start + remappedBetween0And1 * (to.end - to.start)
}
/**
* Maps a range of values in [from] range to values in [to] range using linear interpolation.
*/
fun remapRange(value: Double, from: ClosedFloatingPointRange<Double>, to: ClosedFloatingPointRange<Double>): Double {
val remappedBetween0And1 = (value - from.start) / (from.endInclusive - from.start)
return to.start + remappedBetween0And1 * (to.endInclusive - to.start)
fun remapRange(value: Double, from: FloatRange, to: FloatRange): Double {
val remappedBetween0And1 = (value - from.start) / (from.end - from.start)
return to.start + remappedBetween0And1 * (to.end - to.start)
}

View File

@ -0,0 +1,14 @@
package chylex.hee.util.math
@JvmInline
value class FloatRange(private val combined: Long) {
constructor(start: Float, end: Float) : this((start.toRawBits() shlong 32) or (end.toRawBits().toLong() and 0xFFFF_FFFFL))
val start
get() = Float.fromBits((combined ushr 32).toInt())
val end
get() = Float.fromBits((combined and 0xFFFF_FFFFL).toInt())
}
fun range(start: Float, end: Float) = FloatRange(start, end)

View File

@ -1,5 +1,6 @@
package chylex.hee.util.random
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import java.util.Random
import kotlin.math.pow
@ -29,7 +30,7 @@ abstract class RandomDouble private constructor(val min: Double, val max: Double
fun Exp(min: Double, max: Double, exp: Double) = object : RandomDouble(min, max) {
override fun invoke(rand: Random): Double {
return remapRange(rand.nextDouble().pow(exp), (0.0)..(1.0), min..max)
return remapRange(rand.nextDouble().pow(exp), range(0F, 1F), range(min.toFloat(), max.toFloat()))
}
}
}

View File

@ -1,7 +1,9 @@
include ":system"
include ":util"
include ":system"
include ":debug"
include ":datagen"
project(":system").projectDir = file("./modules/system")
project(":util").projectDir = file("./modules/util")
project(":system").projectDir = file("./modules/system")
project(":debug").projectDir = file("./modules/debug")
project(":datagen").projectDir = file("./data")

View File

@ -19,7 +19,6 @@ import chylex.hee.init.ModPackets
import chylex.hee.init.ModPotions
import chylex.hee.init.ModTileEntities
import chylex.hee.network.NetworkManager
import chylex.hee.system.Debug
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.SubscribeAllEvents
import chylex.hee.util.forge.SubscribeEvent
@ -29,7 +28,6 @@ import net.minecraftforge.fml.DistExecutor.SafeRunnable
import net.minecraftforge.fml.ModLoadingContext
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus.MOD
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent
@ -41,6 +39,10 @@ object Mod {
HEE.version = activeContainer.modInfo.version.toString()
}
try {
Class.forName("chylex.hee.debug.Debug")
} catch (e: ClassNotFoundException) {}
@Suppress("ConvertLambdaToReference")
DistExecutor.safeRunWhenOn(Side.CLIENT) {
SafeRunnable { VanillaResourceOverrides.register() }
@ -51,11 +53,6 @@ object Mod {
ModCreativeTabs
}
@SubscribeEvent
fun onClientSetup(@Suppress("UNUSED_PARAMETER") e: FMLClientSetupEvent) {
Debug.initializeClient()
}
@SubscribeEvent
fun onCommonSetup(@Suppress("UNUSED_PARAMETER") e: FMLCommonSetupEvent) {
NetworkManager.initialize(ModPackets.ALL)

View File

@ -17,7 +17,6 @@ import chylex.hee.game.territory.TerritoryType
import chylex.hee.game.territory.TerritoryVoid
import chylex.hee.game.territory.system.properties.TerritoryEnvironment
import chylex.hee.game.world.isInEndDimension
import chylex.hee.system.Debug
import chylex.hee.util.color.IntColor
import chylex.hee.util.color.RGB
import chylex.hee.util.forge.EventPriority
@ -26,6 +25,7 @@ import chylex.hee.util.forge.SubscribeAllEvents
import chylex.hee.util.forge.SubscribeEvent
import chylex.hee.util.math.LerpedFloat
import chylex.hee.util.math.floorToInt
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.scale
import com.mojang.blaze3d.matrix.MatrixStack
@ -36,7 +36,6 @@ import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.math.vector.Vector3f
import net.minecraftforge.client.event.EntityViewRenderEvent.RenderFogEvent
import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.event.TickEvent.ClientTickEvent
import net.minecraftforge.event.TickEvent.Phase
import org.lwjgl.opengl.GL11.GL_GREATER
@ -119,7 +118,7 @@ object TerritoryRenderer {
// Fog rendering
private val currentFogDensityMp
get() = 1F + (9F * remapRange(currentVoidFactor, (-0.5F)..(1F), (0F)..(1F)).coerceIn(0F, 1F).pow(1.5F))
get() = 1F + (9F * remapRange(currentVoidFactor, range(-0.5F, 1F), range(0F, 1F)).coerceIn(0F, 1F).pow(1.5F))
private val currentRenderDistanceMp
get() = MC.settings.renderDistanceChunks.let { if (it > 12) 0F else (1F - (it / 16.5F)).pow((it - 1) * 0.25F) }
@ -149,7 +148,7 @@ object TerritoryRenderer {
get() = Void.voidFactor.get(MC.partialTicks)
val currentSkyAlpha
get() = remapRange(currentVoidFactor, (-1F)..(0.5F), (1F)..(0F)).coerceIn(0F, 1F)
get() = remapRange(currentVoidFactor, range(-1F, 0.5F), range(1F, 0F)).coerceIn(0F, 1F)
private object Void {
private val VOID_PARTICLE = ParticleSpawnerCustom(
@ -159,12 +158,6 @@ object TerritoryRenderer {
val voidFactor = LerpedFloat(TerritoryVoid.OUTSIDE_VOID_FACTOR)
init {
if (Debug.enabled) {
MinecraftForge.EVENT_BUS.register(this)
}
}
fun tick(player: PlayerEntity) {
val factor = TerritoryVoid.getVoidFactor(player).also(voidFactor::update)
@ -186,16 +179,6 @@ object TerritoryRenderer {
fun reset() {
voidFactor.updateImmediately(TerritoryVoid.OUTSIDE_VOID_FACTOR)
}
@SubscribeEvent
fun onRenderGameOverlayText(e: RenderGameOverlayEvent.Text) {
if (MC.settings.showDebugInfo && MC.player?.isInEndDimension == true) {
with(e.left) {
add("")
add("End Void Factor: ${"%.3f".format(voidFactor.currentValue)}")
}
}
}
}
// Text rendering

View File

@ -1,48 +1,27 @@
package chylex.hee.game.block
import chylex.hee.HEE
import chylex.hee.game.Environment
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.CUTOUT
import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.world.generation.structure.file.StructureFile
import chylex.hee.game.world.generation.util.WorldToStructureWorldAdapter
import chylex.hee.game.world.util.getBlock
import chylex.hee.game.world.util.offsetUntilExcept
import chylex.hee.system.Debug
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import chylex.hee.util.math.BoundingBox
import chylex.hee.util.math.Pos
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.nbt.CompressedStreamTools
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.FAIL
import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.Direction
import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Direction.EAST
import net.minecraft.util.Direction.NORTH
import net.minecraft.util.Direction.SOUTH
import net.minecraft.util.Direction.UP
import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand
import net.minecraft.util.Util
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TextFormatting
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
import java.nio.file.Files
class BlockScaffolding(builder: BlockBuilder) : HeeBlock(builder) {
var enableShape = true
open class BlockScaffolding protected constructor(builder: BlockBuilder) : HeeBlock(builder) {
companion object {
var enableShape = true
fun create(builder: BlockBuilder): HeeBlock {
return HEE.debugModule?.createScaffoldingBlock(builder) ?: BlockScaffolding(builder)
}
}
override val model
get() = BlockModel.Manual
@ -50,73 +29,6 @@ class BlockScaffolding(builder: BlockBuilder) : HeeBlock(builder) {
override val renderLayer
get() = CUTOUT
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
if (world.isRemote && player.isSneaking && !player.abilities.isFlying && Debug.enabled) {
val palette = CommandClientScaffolding.currentPalette
if (palette == null) {
player.sendMessage(StringTextComponent("No structure set."), Util.DUMMY_UUID)
return FAIL
}
val minPos = findMinPos(world, pos)?.let { findMinPos(world, it) } // double pass to find min from any side
val maxPos = minPos?.let { findMaxPos(world, it) }
if (minPos == null || maxPos == null) {
player.sendMessage(StringTextComponent("Could not find structure boundaries."), Util.DUMMY_UUID)
return FAIL
}
val box = BoundingBox(minPos, maxPos)
val serverWorld = Environment.getDimension(world.dimensionKey)
val (structureTag, missingMappings) = StructureFile.save(WorldToStructureWorldAdapter(serverWorld, serverWorld.rand, box.min), box.size, palette, this)
val structureFile = Files.createTempDirectory("HardcoreEnderExpansion_Structure_").resolve(CommandClientScaffolding.currentFile).toFile()
CompressedStreamTools.write(structureTag, structureFile)
Debug.setClipboardContents(structureFile)
if (missingMappings.isNotEmpty()) {
player.sendMessage(StringTextComponent("Missing mappings for states:"), Util.DUMMY_UUID)
for (missingMapping in missingMappings) {
player.sendMessage(StringTextComponent(" - ${TextFormatting.GRAY}$missingMapping"), Util.DUMMY_UUID)
}
}
player.sendMessage(StringTextComponent("Generated structure file of ${box.size}."), Util.DUMMY_UUID)
return SUCCESS
}
return FAIL
}
// Helpers
private fun find(world: World, pos: BlockPos?, direction: Direction): BlockPos? {
return pos?.offsetUntilExcept(direction, 0..255) { it.getBlock(world) === Blocks.AIR }
}
private fun findMinPos(world: World, pos: BlockPos): BlockPos? {
val bottomPos = find(world, pos, DOWN)
val y = bottomPos?.y
val x = find(world, bottomPos, WEST)?.x
val z = find(world, bottomPos, NORTH)?.z
return if (x == null || y == null || z == null) null else Pos(x, y, z)
}
private fun findMaxPos(world: World, pos: BlockPos): BlockPos? {
val topPos = find(world, pos, UP)
val y = topPos?.y
val x = find(world, topPos, EAST)?.x
val z = find(world, topPos, SOUTH)?.z
return if (x == null || y == null || z == null) null else Pos(x, y, z)
}
// Visuals and physics
override fun getShape(state: BlockState, world: IBlockReader, pos: BlockPos, context: ISelectionContext): VoxelShape {

View File

@ -3,8 +3,6 @@ package chylex.hee.game.command
import chylex.hee.HEE
import chylex.hee.client.util.MC
import chylex.hee.game.command.client.CommandClientHelp
import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.command.client.CommandDebugToggles
import chylex.hee.init.ModCommands
import chylex.hee.util.forge.EventPriority
import chylex.hee.util.forge.Side
@ -14,11 +12,15 @@ import net.minecraftforge.client.event.ClientChatEvent
@SubscribeAllEvents(Side.CLIENT, modid = HEE.ID)
object ClientCommandHandler { // UPDATE
val nonHelpCommands = listOf(
CommandClientHelp,
CommandClientScaffolding,
CommandDebugToggles
).associateBy { it.name }
private val client
get() = listOf(
CommandClientHelp
)
private val debug
get() = HEE.debugModule?.clientCommands.orEmpty()
val all = (client + debug).associateBy { it.name }
@SubscribeEvent(priority = EventPriority.LOWEST)
fun onClientChat(e: ClientChatEvent) {
@ -34,7 +36,7 @@ object ClientCommandHandler { // UPDATE
val command = when {
arguments.isEmpty() -> CommandClientHelp
arguments[0] == CommandClientHelp.name -> CommandClientHelp.takeIf { arguments.size < 2 || arguments[1] == "1" } ?: return
else -> nonHelpCommands[arguments[0]] ?: return
else -> all[arguments[0]] ?: return
}
command.executeCommand(source, arguments.drop(1).toTypedArray())

View File

@ -10,6 +10,6 @@ object CommandClientHelp : IClientCommand {
override val description = CommandServerHelp.description
override fun executeCommand(sender: CommandSource, args: Array<String>) {
CommandServerHelp.sendCommandListPage(sender, ClientCommandHandler.nonHelpCommands.keys, emptyMap(), "commands.hee.help.header.client", 1, null)
CommandServerHelp.sendCommandListPage(sender, ClientCommandHandler.all.keys, emptyMap(), "commands.hee.help.header.client", 1, null)
}
}

View File

@ -27,6 +27,7 @@ import chylex.hee.system.random.nextItem
import chylex.hee.system.random.nextRounded
import chylex.hee.util.math.Vec
import chylex.hee.util.math.center
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.nbt.TagCompound
import chylex.hee.util.nbt.use
@ -268,9 +269,9 @@ class EntityInfusedTNT : TNTEntity {
val waterRatio = foundWaterBlocks.size.toFloat() / totalCountedBlocks
val dropAmount = when {
waterRatio < 0.1 -> remapRange(waterRatio, (0.0F)..(0.1F), (1.0F)..(1.6F))
waterRatio < 0.4 -> remapRange(waterRatio, (0.1F)..(0.4F), (1.6F)..(4.0F))
else -> remapRange(waterRatio, (0.4F)..(1.0F), (4.0F)..(5.8F))
waterRatio < 0.1 -> remapRange(waterRatio, range(0.0F, 0.1F), range(1.0F, 1.6F))
waterRatio < 0.4 -> remapRange(waterRatio, range(0.1F, 0.4F), range(1.6F, 4.0F))
else -> remapRange(waterRatio, range(0.4F, 1.0F), range(4.0F, 5.8F))
}
val lootTable = Environment.getLootTable(LootTables.GAMEPLAY_FISHING)

View File

@ -3,6 +3,7 @@ package chylex.hee.game.mechanics.instability.dimension
import chylex.hee.game.mechanics.instability.dimension.components.EndermiteSpawnLogic
import chylex.hee.util.math.ceilToInt
import chylex.hee.util.math.floorToInt
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.nbt.TagCompound
import chylex.hee.util.nbt.use
@ -26,7 +27,7 @@ open class DimensionInstabilityGlobal(private val world: World, private val ende
private fun calculateActionMultiplier(ticksSinceEndermiteSpawn: Long): Float {
return if (ticksSinceEndermiteSpawn < 300L)
remapRange(ticksSinceEndermiteSpawn.toFloat(), (0F)..(300F), (0.2F)..(1F))
remapRange(ticksSinceEndermiteSpawn.toFloat(), range(0F, 300F), range(0.2F, 1F))
else
1F
}

View File

@ -188,7 +188,7 @@ enum class TerritoryType(
}
}
private object GeneratorDummy : ITerritoryGenerator {
object GeneratorDummy : ITerritoryGenerator {
override val segmentSize = Size(1)
override fun provide(world: SegmentedWorld): TerritoryGenerationInfo {

View File

@ -28,6 +28,7 @@ import chylex.hee.util.math.Pos
import chylex.hee.util.math.ceilToInt
import chylex.hee.util.math.directionTowards
import chylex.hee.util.math.floorToInt
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.square
import net.minecraft.entity.Entity
@ -128,7 +129,7 @@ object TerritoryVoid {
private const val PLAYER_NEXT_DAMAGE_TIME_TAG = "VoidNextDamageTime"
private val FACTOR_DAMAGE_REMAP_FROM = (0.5F)..(3.0F)
private val FACTOR_DAMAGE_REMAP_FROM = range(0.5F, 3F)
private val DAMAGE = Damage(DEAL_CREATIVE, IGNORE_INVINCIBILITY())
fun onWorldTick(world: ServerWorld) {
@ -157,10 +158,10 @@ object TerritoryVoid {
val nextDamageTime = getLong(PLAYER_NEXT_DAMAGE_TIME_TAG)
if (currentTime >= nextDamageTime) {
val amount = remapRange(factor, FACTOR_DAMAGE_REMAP_FROM, (2F)..(6F)).ceilToInt().toFloat()
val amount = remapRange(factor, FACTOR_DAMAGE_REMAP_FROM, range(2F, 6F)).ceilToInt().toFloat()
if (DAMAGE.dealTo(amount, entity, TITLE_WITHER)) {
val cooldown = min(30, remapRange(factor, FACTOR_DAMAGE_REMAP_FROM, (30F)..(6F)).floorToInt())
val cooldown = min(30, remapRange(factor, FACTOR_DAMAGE_REMAP_FROM, range(30F, 6F)).floorToInt())
putLong(PLAYER_NEXT_DAMAGE_TIME_TAG, currentTime + cooldown)
}
}

View File

@ -33,6 +33,7 @@ import chylex.hee.util.math.Size
import chylex.hee.util.math.component1
import chylex.hee.util.math.component2
import chylex.hee.util.math.component3
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.square
import chylex.hee.util.math.xz
@ -121,9 +122,9 @@ object Generator_ForgottenTombs : ITerritoryGenerator {
val noiseY = NoiseGenerator.OldPerlinNormalized(rand, scale = 48.0, octaves = 2)
for ((x, y, z) in BlockPos.ZERO.allInCenteredBoxMutable(RADIUS_XZ, RADIUS_Y, RADIUS_XZ)) {
val normalizedY = remapRange(y.toFloat(), -radY..radY, 0F..1F)
val normalizedY = remapRange(y.toFloat(), range(-radY, radY), range(0F, 1F))
val powerY = remapRange(sqrt(normalizedY), 0F..1F, (4.8F)..(1.6F))
val powerY = remapRange(sqrt(normalizedY), range(0F, 1F), range(4.8F, 1.6F))
val powerXZ = powerY * 0.8F
val corner = 1 + ((abs(x) + abs(z)) / (3F * radXZ)).pow(2F)

View File

@ -56,6 +56,7 @@ import chylex.hee.util.math.addY
import chylex.hee.util.math.ceilToInt
import chylex.hee.util.math.center
import chylex.hee.util.math.floorToInt
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.scale
import chylex.hee.util.math.scaleY
@ -207,7 +208,7 @@ object Generator_LostGarden : ITerritoryGenerator {
}
val edgeMpXZ = if (distRatioXZ > 0.86)
remapRange(distRatioXZ.coerceAtMost(1.0), (0.86)..(1.0), (1.0)..(0.86 * noiseXZ.getRawValue(-x * 3, -z * 3)))
remapRange(distRatioXZ.coerceAtMost(1.0), range(0.86F, 1F), range(1F, 0.86F * noiseXZ.getRawValue(-x * 3, -z * 3).toFloat()))
else
1.0
@ -217,10 +218,10 @@ object Generator_LostGarden : ITerritoryGenerator {
}
val valueValley = 1.0 - noiseValley.getValue(x, z) {
remap((0.5)..(1.0), (0.0)..(1.0))
remap(range(0.5F, 1F), range(0F, 1F))
coerce()
redistribute(0.5)
remap((0.0)..(0.75))
remap(range(0F, 0.75F))
if (valueXZ < 0.6) {
multiply(valueXZ / 0.6)
@ -228,7 +229,7 @@ object Generator_LostGarden : ITerritoryGenerator {
}
val valueThreshold = noiseThreshold.getValue(x, z) {
remap((0.14)..(0.29))
remap(range(0.14F, 0.29F))
}
val valueTotalXZ = valueXZ * valueValley
@ -236,7 +237,7 @@ object Generator_LostGarden : ITerritoryGenerator {
val edgeMpY = (0.5 - (1.0 - edgeMpXZ))
val endersolY = -0.125 + (0.575 * noiseEndersol.getValue(x, z) {
if (value > 0.6) {
remap((0.6)..(1.0), (0.6)..(5.0))
remap(range(0.6F, 1F), range(0.6F, 5F))
}
})
@ -276,20 +277,20 @@ object Generator_LostGarden : ITerritoryGenerator {
private fun NoiseValue.distanceReshapeXZ(distance: Double) {
value = when (distance) {
in (0.00)..(0.40) -> value * remapRange(distance, (0.0)..(0.4), (0.8)..(1.0))
in (0.00)..(0.40) -> value * remapRange(distance, range(0F, 0.4F), range(0.8F, 1F))
in (0.40)..(0.85) -> value
in (0.85)..(1.00) -> value * remapRange(distance, (0.85)..(1.0), (1.0)..(0.0))
in (0.85)..(1.00) -> value * remapRange(distance, range(0.85F, 1F), range(1F, 0F))
else -> 0.0
}
}
private fun NoiseValue.distanceReshapeY(distance: Double) {
value = when (distance) {
in (-1.0)..(-0.6) -> value * square(remapRange(distance, (-1.0)..(-0.5), (0.0)..(1.0)))
in (-1.0)..(-0.6) -> value * square(remapRange(distance, range(-1F, -0.5F), range(0F, 1F)))
in (-0.6)..( 0.5) -> value
in ( 0.5)..( 0.8) -> value * remapRange(distance, (0.5)..(0.8), (1.0)..(0.5))
in ( 0.5)..( 0.8) -> value * remapRange(distance, range(0.5F, 0.8F), range(1F, 0.5F))
in ( 0.8)..( 1.4) -> value * 0.5
in ( 1.4)..( 2.0) -> value * remapRange(distance, (1.4)..(2.0), (0.5)..(0.1))
in ( 1.4)..( 2.0) -> value * remapRange(distance, range(1.4F, 2F), range(0.5F, 0.1F))
else -> 0.0
}
}

View File

@ -51,6 +51,7 @@ import chylex.hee.util.math.Vec
import chylex.hee.util.math.ceilToInt
import chylex.hee.util.math.center
import chylex.hee.util.math.directionTowards
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.square
import chylex.hee.util.math.toRadians
@ -414,7 +415,7 @@ object Generator_ObsidianTowers : ITerritoryGenerator {
ENDIUM_ORES {
override fun beforePillars(world: SegmentedWorld, rand: Random, island: Island) {
val piles = if (island.radius >= 5.0)
rand.nextRounded(remapRange(island.radius, (5.0)..(7.0), (2.0)..(4.0)).toFloat())
rand.nextRounded(remapRange(island.radius, range(5F, 7F), range(2F, 4F)).toFloat())
else
1

View File

@ -50,6 +50,7 @@ import chylex.hee.util.math.addY
import chylex.hee.util.math.ceilToInt
import chylex.hee.util.math.center
import chylex.hee.util.math.floorToInt
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.scale
import chylex.hee.util.math.scaleY
@ -128,7 +129,7 @@ object Generator_TheHub : ITerritoryGenerator {
redistribute(0.4)
ifNonZero {
remap((0.2)..(1.0))
remap(range(0.2F, 1F))
multiply(ELEVATION_BOTTOM)
}
}
@ -154,7 +155,7 @@ object Generator_TheHub : ITerritoryGenerator {
private fun NoiseValue.distanceReshape(distance: Double) {
value = when (distance) {
in (0.00)..(0.85) -> value
in (0.85)..(1.00) -> value * remapRange(distance, (0.85)..(1.0), (1.0)..(0.0))
in (0.85)..(1.00) -> value * remapRange(distance, range(0.85F, 1F), range(1F, 0F))
else -> 0.0
}
}

View File

@ -375,7 +375,7 @@ object ModBlocks {
// Blocks: Utilities
@JvmField val ETERNAL_FIRE = BlockEternalFire(buildEternalFire) named "eternal_fire"
@JvmField val SCAFFOLDING = BlockScaffolding(buildScaffolding) named "scaffolding"
@JvmField val SCAFFOLDING = BlockScaffolding.create(buildScaffolding) named "scaffolding"
// Registry

View File

@ -3,17 +3,12 @@ package chylex.hee.init
import chylex.hee.HEE
import chylex.hee.game.command.argument.EnumArgument
import chylex.hee.game.command.argument.ValidatedStringArgument
import chylex.hee.game.command.server.CommandDebugInstability
import chylex.hee.game.command.server.CommandDebugStructure
import chylex.hee.game.command.server.CommandDebugTerritory
import chylex.hee.game.command.server.CommandDebugTestWorld
import chylex.hee.game.command.server.CommandServerCausatum
import chylex.hee.game.command.server.CommandServerHelp
import chylex.hee.game.command.server.CommandServerInfusions
import chylex.hee.game.command.server.CommandServerLootChest
import chylex.hee.game.command.server.CommandServerPortalToken
import chylex.hee.game.command.util.executes
import chylex.hee.system.Debug
import chylex.hee.util.forge.SubscribeAllEvents
import chylex.hee.util.forge.SubscribeEvent
import net.minecraft.command.Commands.literal
@ -32,13 +27,7 @@ object ModCommands {
CommandServerPortalToken
)
val debug = if (Debug.enabled) listOf(
CommandDebugInstability,
CommandDebugStructure,
CommandDebugTerritory,
CommandDebugTestWorld
)
else emptyList()
val debug = HEE.debugModule?.serverCommands.orEmpty()
init {
ArgumentTypes.register("hee:enum", EnumArgument::class.java, EnumArgument.Serializer)

View File

@ -1,7 +1,7 @@
package chylex.hee.mixin;
import chylex.hee.HEE;
import chylex.hee.client.util.MC;
import chylex.hee.system.Debug;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Minecraft.WorldSelectionType;
import org.spongepowered.asm.mixin.Mixin;
@ -14,7 +14,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class HookUselessExperimentalWorldWarning { // UPDATE remove when https://github.com/MinecraftForge/MinecraftForge/pull/7275 is pulled
@Inject(method = "deleteWorld", at = @At("HEAD"), cancellable = true)
private void ignoreUselessWarning(final WorldSelectionType selectionType, final String worldName, final boolean customized, final Runnable runnable, final CallbackInfo ci) {
if (Debug.enabled) {
if (HEE.debug) {
ci.cancel();
MC.instance.enqueue(runnable);
}

View File

@ -1,5 +1,6 @@
package chylex.hee.network.client
import chylex.hee.HEE
import chylex.hee.game.block.BlockDragonEggOverride
import chylex.hee.game.block.BlockEnderGooPurified
import chylex.hee.game.block.BlockPuzzleLogic
@ -35,7 +36,6 @@ import chylex.hee.game.mechanics.table.TableParticleHandler
import chylex.hee.game.potion.BanishmentEffect
import chylex.hee.game.world.generation.feature.tombdungeon.piece.TombDungeonRoom_Tomb
import chylex.hee.network.BaseClientPacket
import chylex.hee.system.Debug
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import io.netty.buffer.ByteBuf
@ -114,7 +114,7 @@ class PacketClientFX<T : IFxData>() : BaseClientPacket() {
val index = buffer.readByte().toInt()
if (index == -1) {
if (Debug.enabled) {
if (HEE.debug) {
throw IndexOutOfBoundsException("could not find FX handler")
}
}

View File

@ -0,0 +1,46 @@
package chylex.hee.test.main
import chylex.hee.game.world.generation.structure.world.segments.ISegment
import chylex.hee.game.world.generation.structure.world.segments.SegmentFull
import chylex.hee.game.world.generation.structure.world.segments.SegmentMultiState
import chylex.hee.game.world.util.allInBoxMutable
import chylex.hee.util.math.Pos
import chylex.hee.util.math.Size
import net.minecraft.block.Blocks
import net.minecraft.util.registry.Bootstrap
fun main() {
println("Initializing...")
Bootstrap.register()
val segments = mutableListOf<ISegment>()
val thresholdField = SegmentMultiState::class.java.getDeclaredField("threshold").also { it.isAccessible = true }
println("Waiting 20 seconds for data fixers...")
Thread.sleep(20000L)
println("Waiting 4 seconds to start memory profiling...")
Thread.sleep(4000L)
for (s in 8..128 step 12) {
var segment: ISegment = SegmentMultiState(Size(s), Blocks.AIR).also(segments::add)
val threshold = thresholdField.getInt(segment)
println("Testing size $s (total ${s * s * s} threshold $threshold)")
for ((index, pos) in Pos(0, 0, 0).allInBoxMutable(Pos(s - 1, s - 1, s - 1)).withIndex()) {
if (index < threshold - 1) {
segment = segment.withState(pos, Blocks.END_STONE.defaultState)
continue
}
check(segment is SegmentMultiState)
segment = segment.withState(pos, Blocks.END_STONE.defaultState).also(segments::add)
check(segment is SegmentFull)
break
}
}
println("Done!")
readLine()
segments.toString()
}