improvements, assets index

This commit is contained in:
Bixilon 2021-02-21 16:55:48 +01:00
parent 802f3a650a
commit 430fb33654
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
25 changed files with 345 additions and 47 deletions

View File

@ -1,17 +1,15 @@
# Roadmap
## Planned features
## Features implemented
- Entity data
- Entity id, sizes, health, modifiers
- Identifier, Inherits
- Meta data
- Entity animations
- Items
- Dimensions
- Blocks
- Biomes
- Achievements
- Particles
- Statistics
- General version information
@ -19,7 +17,6 @@
- Protocol version
- Data version
- Block entities
- Block actions
- Sounds
- Categories
- Sounds
@ -28,5 +25,8 @@
- Entity data
- Models
- Entity animations
- Recipes
- Packets
- Block actions
- Achievements

View File

@ -1,11 +1,18 @@
package de.bixilon.pixlyzer
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generators
import de.bixilon.pixlyzer.util.Util
import net.minecraft.DetectedVersion
import net.minecraft.core.Registry
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileWriter
import java.security.MessageDigest
import java.util.*
import java.util.zip.GZIPOutputStream
object PixLyzer {
@ -16,6 +23,7 @@ object PixLyzer {
private val GSON = GsonBuilder()
.create()
private val PRETTY_GSON = GsonBuilder()
.setPrettyPrinting()
.create()
@ -25,6 +33,23 @@ object PixLyzer {
fun main(args: Array<String>) {
println("Starting PixLyzer")
if (args.size != 3) {
error("Usage: java -cp minecraft,pixlyzer de.bixilon.pixlyzer.PixLyzer <Output directory> <Hash directory> <Assets index>")
}
val outputDirectory = File(args[0])
outputDirectory.mkdirs()
val hashDirectory = File(args[1])
hashDirectory.mkdirs()
val assetsIndex = File(args[2])
try {
Class.forName("net.minecraft.DetectedVersion")
} catch (exception: Exception) {
throw IllegalStateException("Can not find minecraft in the classpath. Please add it to the classpath and restart PixLyzer", exception)
}
println("Loading classes...")
val classesLoadStartTime = System.currentTimeMillis()
@ -33,42 +58,85 @@ object PixLyzer {
println("Class loading done in ${System.currentTimeMillis() - classesLoadStartTime}ms")
File("out/").mkdirs()
val all = JsonObject()
for (generator in Generators.GENERATORS) {
val startTime = System.currentTimeMillis()
println("Starting ${generator.name}...")
generator.generate()
println("Saving to out/${generator.fileName}")
println("Saving to ${outputDirectory.absolutePath}/${generator.fileName}.json")
val fileWriter = FileWriter("out/${generator.fileName}.json")
fileWriter.write(PRETTY_GSON.toJson(generator.data))
fileWriter.close()
val minFileWriter = FileWriter("out/${generator.fileName}.min.json")
minFileWriter.write(GSON.toJson(generator.data))
minFileWriter.close()
writeJson("out/${generator.fileName}", generator.data)
all.add(generator.fileName, generator.data)
println("Done generating ${generator.name} in ${System.currentTimeMillis() - startTime}ms, generated ${generator.entries} entries.")
}
println("Writing all to file...")
println("Generating entity data")
writeJson("${outputDirectory.absolutePath}/all", all)
// for (entityType in Registry.ENTITY_TYPE) {
// val resourceIdentifier = Registry.ENTITY_TYPE.getKey(entityType)
// val entity = entityType.spawn(DummyLevel, null, null, BlockPos(0, 0, 0), MobSpawnType.COMMAND, true, true)
// if (entity is LivingEntity) {
// println("Max health($resourceIdentifier): " + entity.attributes.getInstance(SharedMonsterAttributes.MAX_HEALTH)?.value)
// } else {
// println(resourceIdentifier)
// }
// }
val encodedOutput = GSON.toJson(all).byteInputStream()
val tempFileOutputPath = System.getProperty("java.io.tmpdir") + "/" + UUID.randomUUID().toString()
val fileOutputStream = GZIPOutputStream(FileOutputStream(tempFileOutputPath))
val buffer = ByteArray(4096)
var length: Int
while (encodedOutput.read(buffer, 0, buffer.size).also { length = it } != -1) {
fileOutputStream.write(buffer, 0, length)
}
fileOutputStream.close()
val fileInputStream = FileInputStream(tempFileOutputPath)
val crypt = MessageDigest.getInstance("SHA-1")
while (fileInputStream.read(buffer, 0, buffer.size).also { length = it } != -1) {
crypt.update(buffer, 0, length)
}
fileInputStream.close()
val hash: String = Util.byteArrayToHexString(crypt.digest())
val outputFile = File(hashDirectory.absolutePath + "/" + hash.substring(0, 2) + "/" + hash + ".gz")
outputFile.parentFile.mkdirs()
if (outputFile.exists()) {
println("Hash file does already exist, skipping")
} else {
File(tempFileOutputPath).renameTo(outputFile)
println("Generated and saved hash file to ${outputFile.absolutePath}")
val assetsIndexJson = Util.readJsonFile(assetsIndex.absolutePath)
val versionId = DetectedVersion.tryDetectVersion().id
assetsIndexJson.addProperty(versionId, hash)
val fileWriter = FileWriter(assetsIndex.absolutePath)
fileWriter.write(PRETTY_GSON.toJson(assetsIndexJson))
fileWriter.close()
}
println("Done in ${System.currentTimeMillis() - startTime}ms")
}
private fun writeJson(path: String, data: JsonObject) {
val fileWriter = FileWriter("$path.json")
fileWriter.write(PRETTY_GSON.toJson(data))
fileWriter.close()
val minFileWriter = FileWriter("$path.min.json")
minFileWriter.write(GSON.toJson(data))
minFileWriter.close()
}
}

View File

@ -1,5 +1,7 @@
package de.bixilon.pixlyzer.generator
import de.bixilon.pixlyzer.generator.generators.*
object Generators {
val GENERATORS: List<Generator> = mutableListOf(
@ -19,5 +21,10 @@ object Generators {
BlockEntityGenerator,
StatisticsGenerator,
VersionGenerator,
VillagerTypeGenerator,
PointOfInterestGenerator,
VillagerProfessionGenerator,
MenuTypeGenerator,
SoundEventGenerator,
)
}

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.level.biome.Biome

View File

@ -1,7 +1,8 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntityType

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.client.color.block.BlockColors
import net.minecraft.core.IdMapper
import net.minecraft.core.Registry

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.world.item.CreativeModeTab
import java.lang.reflect.Field

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
object DimensionGenerator : Generator(

View File

@ -1,7 +1,8 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.item.enchantment.Enchantment

View File

@ -1,9 +1,10 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.PixLyzer
import de.bixilon.pixlyzer.dummy.DummyPlayer
import de.bixilon.pixlyzer.dummy.chunk.DummyLevel
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.BlockPos
import net.minecraft.core.Registry
import net.minecraft.network.syncher.EntityDataAccessor
@ -44,30 +45,56 @@ object EntityGenerator : Generator(
entityData.addProperty("size_fixed", entityType.dimensions.fixed)
val entity = summonEntity(entityType)
val entity2 = summonEntity(entityType)
// some entities have random values, we can and will ignore these ones
if (entity is LivingEntity) {
if (entity is LivingEntity && entity2 is LivingEntity) {
entity.attributes.getInstance(SharedMonsterAttributes.MAX_HEALTH)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.MAX_HEALTH)?.value) {
return
}
entityData.addProperty("max_health", it)
}
entity.attributes.getInstance(SharedMonsterAttributes.FOLLOW_RANGE)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.FOLLOW_RANGE)?.value) {
return
}
entityData.addProperty("follow_range", it)
}
entity.attributes.getInstance(SharedMonsterAttributes.MOVEMENT_SPEED)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.MOVEMENT_SPEED)?.value) {
return
}
entityData.addProperty("movement_speed", it)
}
entity.attributes.getInstance(SharedMonsterAttributes.FLYING_SPEED)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.FLYING_SPEED)?.value) {
return
}
entityData.addProperty("flying_speed", it)
}
entity.attributes.getInstance(SharedMonsterAttributes.ATTACK_DAMAGE)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.ATTACK_DAMAGE)?.value) {
return
}
entityData.addProperty("attack_damage", it)
}
entity.attributes.getInstance(SharedMonsterAttributes.ARMOR)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.ARMOR)?.value) {
return
}
entityData.addProperty("armor", it)
}
entity.attributes.getInstance(SharedMonsterAttributes.ARMOR_TOUGHNESS)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.ARMOR_TOUGHNESS)?.value) {
return
}
entityData.addProperty("armor_toughness", it)
}
entity.attributes.getInstance(SharedMonsterAttributes.LUCK)?.value?.let {
if (it != entity2.attributes.getInstance(SharedMonsterAttributes.LUCK)?.value) {
return
}
entityData.addProperty("luck", it)
}
}

View File

@ -1,7 +1,8 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.EquipmentSlot
@ -47,7 +48,7 @@ object ItemGenerator : Generator(
}
if (item is DiggerItem) {
val blocks = JsonArray()
(DIGGER_ITEM_BLOCKS_FIELD.get(item) as Set<Block>?)?.let {
(DIGGER_ITEM_BLOCKS_FIELD.get(item) as Set<Block>?)?.toSortedSet { block: Block, block1: Block -> Registry.BLOCK.getId(block) - Registry.BLOCK.getId(block1) }?.let {
for (block in it) {
blocks.add(Registry.BLOCK.getId(block))
}
@ -67,7 +68,7 @@ object ItemGenerator : Generator(
}
if (item is AxeItem) {
val stripables = JsonArray()
(AXE_ITEM_STRIPABLES_FIELD.get(item) as Map<Block, Block>?)?.let {
(AXE_ITEM_STRIPABLES_FIELD.get(item) as Map<Block, Block>?)?.toSortedMap { block: Block, block1: Block -> Registry.BLOCK.getId(block) - Registry.BLOCK.getId(block1) }?.let {
for ((_, block) in it) {
stripables.add(Registry.BLOCK.getId(block))
}
@ -91,7 +92,7 @@ object ItemGenerator : Generator(
}
if (item is HoeItem) {
val tillables = JsonArray()
(HOE_ITEM_TILLABLES_FIELD.get(item) as Map<Block, BlockState>?)?.let {
(HOE_ITEM_TILLABLES_FIELD.get(item) as Map<Block, BlockState>?)?.toSortedMap { block: Block, block1: Block -> Registry.BLOCK.getId(block) - Registry.BLOCK.getId(block1) }?.let {
for ((_, state) in it) {
tillables.add(Block.getId(state))
}
@ -107,7 +108,7 @@ object ItemGenerator : Generator(
}
if (item is ShovelItem) {
val flattenables = JsonArray()
(SHOVEL_ITEM_FLATTENABLES_FIELD.get(item) as Map<Block, BlockState>?)?.let {
(SHOVEL_ITEM_FLATTENABLES_FIELD.get(item) as Map<Block, BlockState>?)?.toSortedMap { block: Block, block1: Block -> Registry.BLOCK.getId(block) - Registry.BLOCK.getId(block1) }?.let {
for ((_, state) in it) {
flattenables.add(Block.getId(state))
}
@ -128,7 +129,11 @@ object ItemGenerator : Generator(
itemData.addProperty("attack_speed", ATTACK_SPEED_SWORD_ITEM_FIELD.getFloat(item))
}
// ToDo: Record Item,
if (item is RecordItem) {
itemData.addProperty("analog_output", item.analogOutput)
itemData.addProperty("sound", Registry.SOUND_EVENT.getId(item.sound))
}
itemData.addProperty("class", item::class.java.simpleName)

View File

@ -0,0 +1,30 @@
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.dummy.DummyPlayer
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.ChestMenu
object MenuTypeGenerator : Generator(
"menu_types"
) {
override fun generate() {
for (menuType in Registry.MENU) {
val resourceIdentifier = Registry.MENU.getKey(menuType)
val menuTypeData = JsonObject()
menuTypeData.addProperty("id", Registry.MENU.getId(menuType))
val container = menuType.create(0, Inventory(DummyPlayer))
if (container is ChestMenu) {
menuTypeData.addProperty("row_count", container.rowCount)
}
menuTypeData.addProperty("class", container.javaClass.simpleName)
data.add(resourceIdentifier.toString(), menuTypeData)
}
}
}

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.world.entity.MobCategory
object MobCategoryGenerator : Generator(

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
object MotiveGenerator : Generator(

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
object ParticleGenerator : Generator(

View File

@ -0,0 +1,39 @@
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.entity.ai.village.poi.PoiType
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
object PointOfInterestGenerator : Generator(
"points_of_interest"
) {
override fun generate() {
for (pointOfInterestType in Registry.POINT_OF_INTEREST_TYPE) {
val resourceIdentifier = Registry.POINT_OF_INTEREST_TYPE.getKey(pointOfInterestType)
val pointOfInterestData = JsonObject()
pointOfInterestData.addProperty("id", Registry.POINT_OF_INTEREST_TYPE.getId(pointOfInterestType))
pointOfInterestData.addProperty("max_tickets", pointOfInterestType.maxTickets)
pointOfInterestData.addProperty("valid_range", pointOfInterestType.validRange)
(POINT_OF_INTEREST_MATCHING_STATES_FIELD.get(pointOfInterestType) as Set<BlockState>).let {
val states = JsonArray()
for (state in it) {
states.add(Block.getId(state))
}
pointOfInterestData.add("matching_states", states)
}
data.add(resourceIdentifier.toString(), pointOfInterestData)
}
}
private val POINT_OF_INTEREST_MATCHING_STATES_FIELD = PoiType::class.java.getDeclaredField("matchingStates")
init {
POINT_OF_INTEREST_MATCHING_STATES_FIELD.isAccessible = true
}
}

View File

@ -1,7 +1,8 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.world.effect.MobEffectInstance
import java.lang.reflect.Field

View File

@ -1,6 +1,7 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.world.item.Rarity
object RarityGenerator : Generator(

View File

@ -0,0 +1,20 @@
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
object SoundEventGenerator : Generator(
"sound_events"
) {
override fun generate() {
for (soundEvent in Registry.SOUND_EVENT) {
val resourceIdentifier = Registry.SOUND_EVENT.getKey(soundEvent)
val soundEventData = JsonObject()
soundEventData.addProperty("id", Registry.SOUND_EVENT.getId(soundEvent))
data.add(resourceIdentifier.toString(), soundEventData)
}
}
}

View File

@ -1,7 +1,8 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
import net.minecraft.stats.Stat
import net.minecraft.stats.StatFormatter
@ -31,13 +32,17 @@ object StatisticsGenerator : Generator(
else -> "other"
})
val subStatistics = JsonArray()
val sortedStatistics: MutableSet<String> = mutableSetOf()
for (subStatistic in statistic) {
val key = when (subStatistic) {
is Stat -> subStatistic.name
else -> subStatistic.toString()
}
subStatistics.add(key)
sortedStatistics.add(key)
}
val subStatistics = JsonArray()
for (subStatistic in sortedStatistics.toSortedSet()) {
subStatistics.add(subStatistic)
}
if (subStatistics.size() > 0) {
statisticData.add("sub_statistics", subStatistics)

View File

@ -1,5 +1,6 @@
package de.bixilon.pixlyzer.generator
package de.bixilon.pixlyzer.generator.generators
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.DetectedVersion
object VersionGenerator : Generator(

View File

@ -0,0 +1,49 @@
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
object VillagerProfessionGenerator : Generator(
"villager_professions"
) {
override fun generate() {
for (villagerProfession in Registry.VILLAGER_PROFESSION) {
val resourceIdentifier = Registry.VILLAGER_PROFESSION.getKey(villagerProfession)
val villagerProfessionData = JsonObject()
villagerProfessionData.addProperty("id", Registry.VILLAGER_PROFESSION.getId(villagerProfession))
villagerProfessionData.addProperty("primary_point_of_interest", Registry.POINT_OF_INTEREST_TYPE.getId(villagerProfession.jobPoiType))
villagerProfession.requestedItems.let {
val requestedItems = JsonArray()
for (item in it) {
requestedItems.add(Registry.ITEM.getId(item))
}
if (requestedItems.size() > 0) {
villagerProfessionData.add("requested_items", requestedItems)
}
}
villagerProfession.secondaryPoi.let {
val blocks = JsonArray()
for (block in it) {
blocks.add(Registry.BLOCK.getId(block))
}
if (blocks.size() > 0) {
villagerProfessionData.add("blocks", blocks)
}
}
villagerProfession.workSound?.let {
villagerProfessionData.addProperty("work_sound", Registry.SOUND_EVENT.getId(it))
}
data.add(resourceIdentifier.toString(), villagerProfessionData)
}
}
}

View File

@ -0,0 +1,19 @@
package de.bixilon.pixlyzer.generator.generators
import com.google.gson.JsonObject
import de.bixilon.pixlyzer.generator.Generator
import net.minecraft.core.Registry
object VillagerTypeGenerator : Generator(
"villager_types"
) {
override fun generate() {
for (villagerType in Registry.VILLAGER_TYPE) {
val resourceIdentifier = Registry.VILLAGER_TYPE.getKey(villagerType)
val villagerTypeData = JsonObject()
villagerTypeData.addProperty("id", Registry.VILLAGER_TYPE.getId(villagerType))
data.add(resourceIdentifier.toString(), villagerTypeData)
}
}
}

View File

@ -2,6 +2,7 @@ package de.bixilon.pixlyzer.util
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import java.io.FileInputStream
import java.io.InputStreamReader
object Util {
@ -20,4 +21,19 @@ object Util {
return json
}
fun readJsonFile(path: String): JsonObject {
val reader = InputStreamReader(FileInputStream(path))
val json: JsonObject = JsonParser().parse(reader).asJsonObject
reader.close()
return json
}
fun byteArrayToHexString(byteArray: ByteArray): String {
val result = StringBuilder()
for (value in byteArray) {
result.append(((value.toInt() and 0xff) + 0x100).toString(16).substring(1))
}
return result.toString()
}
}